Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/WordPressData/Blog+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extension Blog {
/// The title of the blog
public var title: String? {
guard let blogName = settings?.name, !blogName.isEmpty else {
return displayURL as String?
return displayURL
}
return blogName
}
Expand Down
94 changes: 0 additions & 94 deletions Sources/WordPressData/Objective-C/Blog.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
@import SFHFKeychainUtils;
@import WordPressShared;
@import NSObject_SafeExpectations;
@import NSURL_IDN;
@import WordPressKit;

@class Comment;
Expand Down Expand Up @@ -158,99 +157,6 @@ - (NSNumber *)organizationID {
}
}

// Used as a key to store passwords, if you change the algorithm, logins will break
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems obsolete. I found where the app uses self.xmlrpc, but nothing else.

- (NSString *)displayURL
{
if (self.url == nil) {
DDLogInfo(@"Blog display URL is nil");
return nil;
}

NSError *error = nil;
NSRegularExpression *protocol = [NSRegularExpression regularExpressionWithPattern:@"http(s?)://" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *result = [NSString stringWithFormat:@"%@", [protocol stringByReplacingMatchesInString:self.url options:0 range:NSMakeRange(0, [self.url length]) withTemplate:@""]];

if ([result hasSuffix:@"/"]) {
result = [result substringToIndex:[result length] - 1];
}

NSString *decodedResult = [NSURL IDNDecodedHostname:result];
NSAssert(decodedResult != nil, @"Decoded url shouldn't be nil");
if (decodedResult == nil) {
DDLogInfo(@"displayURL: decoded url is nil: %@", self.url);
return result;
}

return decodedResult;
}

- (NSString *)hostURL
{
return [self displayURL];
}

- (NSString *)homeURL
{
NSString *homeURL = [self getOptionValue:@"home_url"];
if (!homeURL) {
homeURL = self.url;
}
return homeURL;
}

- (NSString *)hostname
{
NSString *hostname = [[NSURL URLWithString:self.xmlrpc] host];
if (hostname == nil) {
NSError *error = nil;
NSRegularExpression *protocol = [NSRegularExpression regularExpressionWithPattern:@"^.*://" options:NSRegularExpressionCaseInsensitive error:&error];
hostname = [protocol stringByReplacingMatchesInString:self.url options:0 range:NSMakeRange(0, [self.url length]) withTemplate:@""];
}

// NSURL seems to not recongnize some TLDs like .me and .it, which results in hostname returning a full path.
// This can break reachibility (among other things) for the blog.
// As a saftey net, make sure we drop any path component before returning the hostname.
NSArray *parts = [hostname componentsSeparatedByString:@"/"];
if (parts.count) {
hostname = [parts firstObject];
}

return hostname;
}

- (NSString *)loginUrl
{
NSString *loginUrl = [self getOptionValue:@"login_url"];
if (!loginUrl) {
loginUrl = [self urlWithPath:@"wp-login.php"];
}
return loginUrl;
}

- (NSString *)urlWithPath:(NSString *)path
{
if (!path || !self.xmlrpc) {
DDLogError(@"Blog: Error creating urlWithPath.");
return nil;
}

NSError *error = nil;
NSRegularExpression *xmlrpc = [NSRegularExpression regularExpressionWithPattern:@"xmlrpc.php$" options:NSRegularExpressionCaseInsensitive error:&error];
return [xmlrpc stringByReplacingMatchesInString:self.xmlrpc options:0 range:NSMakeRange(0, [self.xmlrpc length]) withTemplate:path];
}

- (NSString *)adminUrlWithPath:(NSString *)path
{
NSString *adminBaseUrl = [self getOptionValue:@"admin_url"];
if (!adminBaseUrl) {
adminBaseUrl = [self urlWithPath:@"wp-admin/"];
}
if (![adminBaseUrl hasSuffix:@"/"]) {
adminBaseUrl = [adminBaseUrl stringByAppendingString:@"/"];
}
return [NSString stringWithFormat:@"%@%@", adminBaseUrl, path];
}

- (NSArray *)sortedCategories
{
NSSortDescriptor *sortNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"categoryName"
Expand Down
17 changes: 0 additions & 17 deletions Sources/WordPressData/Objective-C/include/Blog.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,22 +213,8 @@ typedef NS_ENUM(NSInteger, SiteVisibility) {
@property (nonatomic, strong, readonly, nullable) NSString *authToken;
@property (nonatomic, strong, readonly, nullable) NSSet *allowedFileTypes;

/**
* @details URL properties (example: http://wp.koke.me/sub/xmlrpc.php)
*/

// User to display the blog url to the user (IDN decoded, no http:)
// wp.koke.me/sub
@property (weak, readonly, nullable) NSString *displayURL;
// alias of displayURL
// kept for compatibilty, used as a key to store passwords
@property (weak, readonly, nullable) NSString *hostURL;
@property (weak, readonly, nullable) NSString *homeURL;
// http://wp.koke.me/sub
@property (nonatomic, strong, nullable) NSString *url;
// Used for reachability checks (IDN encoded)
// wp.koke.me
@property (weak, readonly, nullable) NSString *hostname;

// Used to check if the blog has an icon set up
@property (readonly) BOOL hasIcon;
Expand All @@ -243,9 +229,6 @@ typedef NS_ENUM(NSInteger, SiteVisibility) {
- (nullable NSArray *)sortedCategories;
- (nullable id)getOptionValue:(NSString *) name;
- (void)setValue:(id)value forOption:(NSString *)name;
- (NSString *)loginUrl;
- (nullable NSString *)urlWithPath:(NSString *)path;
- (NSString *)adminUrlWithPath:(NSString *)path;
- (NSDictionary *) getImageResizeDimensions;
- (BOOL)supports:(BlogFeature)feature;
- (BOOL)supportsPublicize;
Expand Down
2 changes: 1 addition & 1 deletion Sources/WordPressData/Swift/AbstractPost+Searchable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension AbstractPost: SearchableItemConvertable {

public var searchDescription: String? {
guard let postPreview = contentPreviewForDisplay(), !postPreview.isEmpty else {
return blog.displayURL as String? ?? contentForDisplay()
return blog.displayURL ?? contentForDisplay()
}
return postPreview
}
Expand Down
65 changes: 65 additions & 0 deletions Sources/WordPressData/Swift/Blog+Swift.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import CoreData
import NSURL_IDN

extension Blog {

Expand All @@ -26,4 +27,68 @@ extension Blog {
return nil
}
}

// MARK: - URLs

/// User-facing display URL with protocol and trailing slash stripped, IDN decoded.
@objc public var displayURL: String? {
guard let url else { return nil }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't imagine a situation where the site URL should be nil?

But I guess that's another PR

var result = url.replacingOccurrences(
of: "^https?://",
with: "",
options: [.regularExpression, .caseInsensitive]
)
if result.hasSuffix("/") {
result = String(result.dropLast())
}
return NSURL.idnDecodedHostname(result) ?? result
}

/// The home URL for the blog. Falls back to ``url``.
@objc public var homeURL: String? {
getOptionString(name: "home_url") ?? url
}

/// The hostname extracted from the XML-RPC endpoint, used for reachability checks.
@objc public var hostname: String? {
var result: String?
if let xmlrpc {
result = URL(string: xmlrpc)?.host
}
if result == nil, let url {
result = url.replacingOccurrences(
of: "^.*://",
with: "",
options: [.regularExpression, .caseInsensitive]
)
}
// NSURL doesn't recognize some TLDs like .me and .it, returning
// a full path. Strip path components to avoid breaking reachability.
return result?.components(separatedBy: "/").first
}

/// The login URL for the blog.
public var loginURL: URL? {
let string = getOptionString(name: "login_url") ?? url(withPath: "wp-login.php")
return string.flatMap(URL.init)
}

/// Builds a URL by replacing `xmlrpc.php` in the XML-RPC endpoint with the given path.
public func url(withPath path: String) -> String? {
guard let xmlrpc else { return nil }
return xmlrpc.replacingOccurrences(
of: "xmlrpc\\.php$",
with: path,
options: [.regularExpression, .caseInsensitive]
)
}

/// Builds an admin URL by appending the given path to the admin base URL.
public func makeAdminURL(path: String? = nil) -> URL? {
var base = getOptionString(name: "admin_url") ?? url(withPath: "wp-admin/") ?? ""
if !base.hasSuffix("/") {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be a better way to implement some of these, but I decided to keep direct ObjC to Swift conversion for now to reduce risk of breaking something.

base += "/"
}
return URL(string: base + (path ?? ""))
}
}
2 changes: 1 addition & 1 deletion Sources/WordPressData/Swift/Theme+Swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extension Theme {
guard let themePathForCustomization else { return nil }

let path = "customize.php?theme=\(themePathForCustomization)&hide_close=true"
return blog?.adminUrl(withPath: path)
return blog?.makeAdminURL(path: path)?.absoluteString
}

private var themePathForCustomization: String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ extension WordPressOrgRestApi {
let credential: WordPressOrgRestApi.SelfHostedSiteCredential
if let appPassword = try? blog.getApplicationToken() {
credential = .applicationPassword(username: username, password: .init(appPassword))
} else if let loginURL = URL(string: blog.loginUrl()),
let adminURL = URL(string: blog.adminUrl(withPath: "")),
} else if let loginURL = blog.loginURL,
let adminURL = blog.makeAdminURL(),
let password = blog.password {
credential = .accountPassword(loginURL: loginURL, username: username, password: .init(password), adminURL: adminURL)
} else {
Expand Down
Loading