From 01c5e4f15cf484d2fe30060ce3457ceed87d01a8 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 29 Oct 2024 13:29:31 +1300 Subject: [PATCH 1/4] Use ephemeral URLSession to send .org REST API requests --- WordPress/Classes/Networking/WordPressClient.swift | 12 +++++++++++- .../ViewModel/BlogDashboardViewModel.swift | 2 +- .../BlogDetailsViewController+SectionHelpers.swift | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/Networking/WordPressClient.swift b/WordPress/Classes/Networking/WordPressClient.swift index 85066b40da8d..0f93d0cf81f5 100644 --- a/WordPress/Classes/Networking/WordPressClient.swift +++ b/WordPress/Classes/Networking/WordPressClient.swift @@ -45,9 +45,19 @@ actor WordPressClient { self.rootUrl = rootUrl.url() } - static func `for`(site: WordPressSite, in session: URLSession) throws -> WordPressClient { + static func `for`(site: WordPressSite) throws -> WordPressClient { let parsedUrl = try ParsedUrl.parse(input: site.baseUrl) + // At the moment, the app supports account password and application password. + // When a site is initially signed in with account password, WordPress login cookies are stored + // in `URLSession.shared`. After switching the site to application password authentication, + // the store cookies may interfere with application-password authentication, which results in 401 + // errors from REST API. + // + // To avoid the above issue, we'll use ephemeral URLSession for now (which stores cookies in memory + // rather than using the shared one on disk). + let session = URLSession(configuration: .ephemeral) + switch site.type { case let .dotCom(authToken): let api = WordPressAPI(urlSession: session, baseUrl: parsedUrl, authenticationStategy: .authorizationHeader(token: authToken)) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift index a87434da349b..1108a7db44a0 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift @@ -108,7 +108,7 @@ final class BlogDashboardViewModel { var _error: Error? do { - self.wordpressClient = try WordPressClient.for(site: .from(blog: self.blog), in: .shared) + self.wordpressClient = try WordPressClient.for(site: .from(blog: self.blog)) } catch { _error = error self.wordpressClient = nil diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift index 26f43f0f0937..171b0ce97960 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift @@ -130,7 +130,7 @@ extension BlogDetailsViewController { do { let site = try WordPressSite.from(blog: self.blog) - let client = try WordPressClient.for(site: site, in: .shared) + let client = try WordPressClient.for(site: site) return ApplicationPasswordService(api: client, currentUserId: userId) } catch { DDLogError("Failed to create WordPressClient: \(error)") From 2f910578f9f76ad02fb736e9f2a53e10ad298a1b Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 29 Oct 2024 13:41:06 +1300 Subject: [PATCH 2/4] Fix grammar issues in code comment --- WordPress/Classes/Networking/WordPressClient.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/Classes/Networking/WordPressClient.swift b/WordPress/Classes/Networking/WordPressClient.swift index 0f93d0cf81f5..3b2aa71ef199 100644 --- a/WordPress/Classes/Networking/WordPressClient.swift +++ b/WordPress/Classes/Networking/WordPressClient.swift @@ -48,13 +48,13 @@ actor WordPressClient { static func `for`(site: WordPressSite) throws -> WordPressClient { let parsedUrl = try ParsedUrl.parse(input: site.baseUrl) - // At the moment, the app supports account password and application password. - // When a site is initially signed in with account password, WordPress login cookies are stored + // Currently, the app supports both account passwords and application passwords. + // When a site is initially signed in with an account password, WordPress login cookies are stored // in `URLSession.shared`. After switching the site to application password authentication, - // the store cookies may interfere with application-password authentication, which results in 401 - // errors from REST API. + // the stored cookies may interfere with application-password authentication, resulting in 401 + // errors from the REST API. // - // To avoid the above issue, we'll use ephemeral URLSession for now (which stores cookies in memory + // To avoid this issue, we'll use an ephemeral URLSession for now (which stores cookies in memory // rather than using the shared one on disk). let session = URLSession(configuration: .ephemeral) From 3343c287b9cbbee92f107864d2bf2a532b4386cb Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 30 Oct 2024 09:31:02 +1300 Subject: [PATCH 3/4] Change static functions to initialisers --- WordPress/Classes/Networking/WordPressClient.swift | 12 ++++++------ .../ViewModel/BlogDashboardViewModel.swift | 2 +- .../BlogDetailsViewController+SectionHelpers.swift | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/WordPress/Classes/Networking/WordPressClient.swift b/WordPress/Classes/Networking/WordPressClient.swift index 3b2aa71ef199..f9dcf6cd4447 100644 --- a/WordPress/Classes/Networking/WordPressClient.swift +++ b/WordPress/Classes/Networking/WordPressClient.swift @@ -16,12 +16,12 @@ struct WordPressSite { self.type = type } - static func from(blog: Blog) throws -> WordPressSite { + init(blog: Blog) throws { let url = try ParsedUrl.parse(input: blog.getUrlString()) if let account = blog.account { - return WordPressSite(baseUrl: url, type: .dotCom(authToken: account.authToken)) + self.init(baseUrl: url, type: .dotCom(authToken: account.authToken)) } else { - return WordPressSite(baseUrl: url, type: .selfHosted( + self.init(baseUrl: url, type: .selfHosted( username: try blog.getUsername(), authToken: try blog.getApplicationToken()) ) @@ -45,7 +45,7 @@ actor WordPressClient { self.rootUrl = rootUrl.url() } - static func `for`(site: WordPressSite) throws -> WordPressClient { + init(site: WordPressSite) throws { let parsedUrl = try ParsedUrl.parse(input: site.baseUrl) // Currently, the app supports both account passwords and application passwords. @@ -61,10 +61,10 @@ actor WordPressClient { switch site.type { case let .dotCom(authToken): let api = WordPressAPI(urlSession: session, baseUrl: parsedUrl, authenticationStategy: .authorizationHeader(token: authToken)) - return WordPressClient(api: api, rootUrl: parsedUrl) + self.init(api: api, rootUrl: parsedUrl) case .selfHosted(let username, let authToken): let api = WordPressAPI.init(urlSession: session, baseUrl: parsedUrl, authenticationStategy: .init(username: username, password: authToken)) - return WordPressClient(api: api, rootUrl: parsedUrl) + self.init(api: api, rootUrl: parsedUrl) } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift index 1108a7db44a0..be64e977adc0 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/ViewModel/BlogDashboardViewModel.swift @@ -108,7 +108,7 @@ final class BlogDashboardViewModel { var _error: Error? do { - self.wordpressClient = try WordPressClient.for(site: .from(blog: self.blog)) + self.wordpressClient = try WordPressClient(site: .init(blog: self.blog)) } catch { _error = error self.wordpressClient = nil diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift index 171b0ce97960..45d55df7c3ac 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift @@ -120,7 +120,7 @@ extension BlogDetailsViewController { @objc func shouldShowApplicationPasswordRow() -> Bool { // Only available for application-password authenticated self-hosted sites. - return self.blog.account == nil && self.blog.userID != nil && (try? WordPressSite.from(blog: self.blog)) != nil + return self.blog.account == nil && self.blog.userID != nil && (try? WordPressSite(blog: self.blog)) != nil } private func createApplicationPasswordService() -> ApplicationPasswordService? { @@ -129,8 +129,8 @@ extension BlogDetailsViewController { } do { - let site = try WordPressSite.from(blog: self.blog) - let client = try WordPressClient.for(site: site) + let site = try WordPressSite(blog: self.blog) + let client = try WordPressClient(site: site) return ApplicationPasswordService(api: client, currentUserId: userId) } catch { DDLogError("Failed to create WordPressClient: \(error)") From 5e50400e33f0d89e90c049fd627c4eb7c9ed7778 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 30 Oct 2024 09:39:57 +1300 Subject: [PATCH 4/4] Remove an unnecessary throw --- WordPress/Classes/Networking/WordPressClient.swift | 14 ++++++++++---- .../BlogDetailsViewController+SectionHelpers.swift | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/WordPress/Classes/Networking/WordPressClient.swift b/WordPress/Classes/Networking/WordPressClient.swift index f9dcf6cd4447..e3176f6df152 100644 --- a/WordPress/Classes/Networking/WordPressClient.swift +++ b/WordPress/Classes/Networking/WordPressClient.swift @@ -8,11 +8,11 @@ struct WordPressSite { case selfHosted(username: String, authToken: String) } - let baseUrl: String + let baseUrl: URL let type: WordPressSite.SiteType init(baseUrl: ParsedUrl, type: WordPressSite.SiteType) { - self.baseUrl = baseUrl.url() + self.baseUrl = baseUrl.asURL() self.type = type } @@ -45,8 +45,14 @@ actor WordPressClient { self.rootUrl = rootUrl.url() } - init(site: WordPressSite) throws { - let parsedUrl = try ParsedUrl.parse(input: site.baseUrl) + init(site: WordPressSite) { + // `site.barUrl` is a legal HTTP URL, which should be convertable to the `ParsedUrl` type. + let parsedUrl: ParsedUrl + do { + parsedUrl = try ParsedUrl.parse(input: site.baseUrl.absoluteString) + } catch { + fatalError("Failed to cast URL (\(site.baseUrl.absoluteString)) to ParsedUrl: \(error)") + } // Currently, the app supports both account passwords and application passwords. // When a site is initially signed in with an account password, WordPress login cookies are stored diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift index 45d55df7c3ac..4523322e5c2b 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+SectionHelpers.swift @@ -130,7 +130,7 @@ extension BlogDetailsViewController { do { let site = try WordPressSite(blog: self.blog) - let client = try WordPressClient(site: site) + let client = WordPressClient(site: site) return ApplicationPasswordService(api: client, currentUserId: userId) } catch { DDLogError("Failed to create WordPressClient: \(error)")