diff --git a/Networking/Networking.xcodeproj/project.pbxproj b/Networking/Networking.xcodeproj/project.pbxproj index c93f56993ae..13fe130ab64 100644 --- a/Networking/Networking.xcodeproj/project.pbxproj +++ b/Networking/Networking.xcodeproj/project.pbxproj @@ -716,6 +716,7 @@ DE50296328C609DE00551736 /* jetpack-user-not-connected.json in Resources */ = {isa = PBXBuildFile; fileRef = DE50296228C609DE00551736 /* jetpack-user-not-connected.json */; }; DE50296528C60A8000551736 /* JetpackUserMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE50296428C60A8000551736 /* JetpackUserMapperTests.swift */; }; DE5CA111288A3E080077BEF9 /* product-malformed-variations-and-image-alt.json in Resources */ = {isa = PBXBuildFile; fileRef = DE5CA110288A3E080077BEF9 /* product-malformed-variations-and-image-alt.json */; }; + DE66C5532976508300DAA978 /* CookieNonceAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE66C5522976508300DAA978 /* CookieNonceAuthenticator.swift */; }; DE6F308727966FEF004E1C9A /* CouponReportListMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6F308627966FEF004E1C9A /* CouponReportListMapperTests.swift */; }; DE74F29A27E08F5A0002FE59 /* SiteSettingMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE74F29927E08F5A0002FE59 /* SiteSettingMapper.swift */; }; DE74F29C27E0A1D00002FE59 /* setting-coupon.json in Resources */ = {isa = PBXBuildFile; fileRef = DE74F29B27E0A1D00002FE59 /* setting-coupon.json */; }; @@ -752,7 +753,7 @@ DEF13C5E296686AB0024A02B /* orders-load-all-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = DEF13C5D296686AB0024A02B /* orders-load-all-without-data.json */; }; DEF13C6029668C420024A02B /* order-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = DEF13C5F29668C420024A02B /* order-without-data.json */; }; DEFBA74E29485A7600C35BA9 /* RESTRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFBA74D29485A7600C35BA9 /* RESTRequest.swift */; }; - DEFBA7542949CE6600C35BA9 /* RequestProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFBA7532949CE6600C35BA9 /* RequestProcessor.swift */; }; + DEFBA7542949CE6600C35BA9 /* ApplicationPasswordRequestProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFBA7532949CE6600C35BA9 /* ApplicationPasswordRequestProcessor.swift */; }; DEFBA7562949D17400C35BA9 /* DefaultRequestAuthenticatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFBA7552949D17300C35BA9 /* DefaultRequestAuthenticatorTests.swift */; }; E12552C526385B05001CEE70 /* ShippingLabelAddressValidationSuccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12552C426385B05001CEE70 /* ShippingLabelAddressValidationSuccess.swift */; }; E137619929151C7400FD098F /* error-wp-rest-forbidden.json in Resources */ = {isa = PBXBuildFile; fileRef = E137619829151C7400FD098F /* error-wp-rest-forbidden.json */; }; @@ -779,13 +780,13 @@ EE6FDCFC2966A70400E1CECF /* product-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE6FDCFB2966A70400E1CECF /* product-without-data.json */; }; EE71CC3D2951A8EA0074D908 /* ApplicationPasswordStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE71CC3C2951A8EA0074D908 /* ApplicationPasswordStorage.swift */; }; EE71CC412951CE700074D908 /* generate-application-password-using-wporg-creds-success.json in Resources */ = {isa = PBXBuildFile; fileRef = EE71CC402951CE700074D908 /* generate-application-password-using-wporg-creds-success.json */; }; - EE76762F2962B85E000066FA /* RequestProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE76762E2962B85E000066FA /* RequestProcessorTests.swift */; }; + EE76762F2962B85E000066FA /* ApplicationPasswordRequestProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE76762E2962B85E000066FA /* ApplicationPasswordRequestProcessorTests.swift */; }; EE80A24729547F8B003591E4 /* coupons-all-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE80A24529547F8B003591E4 /* coupons-all-without-data.json */; }; EE80A24829547F8B003591E4 /* coupon-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE80A24629547F8B003591E4 /* coupon-without-data.json */; }; EE80A25029556FBD003591E4 /* coupon-reports-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE80A24F29556FBD003591E4 /* coupon-reports-without-data.json */; }; EE8A86F1286C5226003E8AA4 /* media-update-product-id-in-wordpress-site.json in Resources */ = {isa = PBXBuildFile; fileRef = EE8A86F0286C5226003E8AA4 /* media-update-product-id-in-wordpress-site.json */; }; EE8DE432294B17CD005054E7 /* DefaultApplicationPasswordUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE8DE431294B17CD005054E7 /* DefaultApplicationPasswordUseCaseTests.swift */; }; - EE99814E295AA7430074AE68 /* RequestAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE99814D295AA7430074AE68 /* RequestAuthenticator.swift */; }; + EE99814E295AA7430074AE68 /* ApplicationPasswordAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE99814D295AA7430074AE68 /* ApplicationPasswordAuthenticator.swift */; }; EE998150295AACE10074AE68 /* RequestConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE99814F295AACE10074AE68 /* RequestConverter.swift */; }; EEA6583E2966B41E00112DF0 /* products-load-all-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EEA6583D2966B41E00112DF0 /* products-load-all-without-data.json */; }; EEA658402966C05D00112DF0 /* product-search-sku-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EEA6583F2966C05D00112DF0 /* product-search-sku-without-data.json */; }; @@ -1545,6 +1546,7 @@ DE50296228C609DE00551736 /* jetpack-user-not-connected.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "jetpack-user-not-connected.json"; sourceTree = ""; }; DE50296428C60A8000551736 /* JetpackUserMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackUserMapperTests.swift; sourceTree = ""; }; DE5CA110288A3E080077BEF9 /* product-malformed-variations-and-image-alt.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "product-malformed-variations-and-image-alt.json"; sourceTree = ""; }; + DE66C5522976508300DAA978 /* CookieNonceAuthenticator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookieNonceAuthenticator.swift; sourceTree = ""; }; DE6F308627966FEF004E1C9A /* CouponReportListMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponReportListMapperTests.swift; sourceTree = ""; }; DE74F29927E08F5A0002FE59 /* SiteSettingMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteSettingMapper.swift; sourceTree = ""; }; DE74F29B27E0A1D00002FE59 /* setting-coupon.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "setting-coupon.json"; sourceTree = ""; }; @@ -1581,7 +1583,7 @@ DEF13C5D296686AB0024A02B /* orders-load-all-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "orders-load-all-without-data.json"; sourceTree = ""; }; DEF13C5F29668C420024A02B /* order-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "order-without-data.json"; sourceTree = ""; }; DEFBA74D29485A7600C35BA9 /* RESTRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTRequest.swift; sourceTree = ""; }; - DEFBA7532949CE6600C35BA9 /* RequestProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestProcessor.swift; sourceTree = ""; }; + DEFBA7532949CE6600C35BA9 /* ApplicationPasswordRequestProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordRequestProcessor.swift; sourceTree = ""; }; DEFBA7552949D17300C35BA9 /* DefaultRequestAuthenticatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultRequestAuthenticatorTests.swift; sourceTree = ""; }; E12552C426385B05001CEE70 /* ShippingLabelAddressValidationSuccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelAddressValidationSuccess.swift; sourceTree = ""; }; E137619829151C7400FD098F /* error-wp-rest-forbidden.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "error-wp-rest-forbidden.json"; sourceTree = ""; }; @@ -1608,13 +1610,13 @@ EE6FDCFB2966A70400E1CECF /* product-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "product-without-data.json"; sourceTree = ""; }; EE71CC3C2951A8EA0074D908 /* ApplicationPasswordStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordStorage.swift; sourceTree = ""; }; EE71CC402951CE700074D908 /* generate-application-password-using-wporg-creds-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "generate-application-password-using-wporg-creds-success.json"; sourceTree = ""; }; - EE76762E2962B85E000066FA /* RequestProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestProcessorTests.swift; sourceTree = ""; }; + EE76762E2962B85E000066FA /* ApplicationPasswordRequestProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordRequestProcessorTests.swift; sourceTree = ""; }; EE80A24529547F8B003591E4 /* coupons-all-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "coupons-all-without-data.json"; sourceTree = ""; }; EE80A24629547F8B003591E4 /* coupon-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "coupon-without-data.json"; sourceTree = ""; }; EE80A24F29556FBD003591E4 /* coupon-reports-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "coupon-reports-without-data.json"; sourceTree = ""; }; EE8A86F0286C5226003E8AA4 /* media-update-product-id-in-wordpress-site.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "media-update-product-id-in-wordpress-site.json"; sourceTree = ""; }; EE8DE431294B17CD005054E7 /* DefaultApplicationPasswordUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultApplicationPasswordUseCaseTests.swift; sourceTree = ""; }; - EE99814D295AA7430074AE68 /* RequestAuthenticator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestAuthenticator.swift; sourceTree = ""; }; + EE99814D295AA7430074AE68 /* ApplicationPasswordAuthenticator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordAuthenticator.swift; sourceTree = ""; }; EE99814F295AACE10074AE68 /* RequestConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestConverter.swift; sourceTree = ""; }; EEA6583D2966B41E00112DF0 /* products-load-all-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "products-load-all-without-data.json"; sourceTree = ""; }; EEA6583F2966C05D00112DF0 /* product-search-sku-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "product-search-sku-without-data.json"; sourceTree = ""; }; @@ -1953,6 +1955,7 @@ B557D9E5209753AA005962F4 /* Networking */ = { isa = PBXGroup; children = ( + DE66C5512976507100DAA978 /* CookieNonce */, EE54C899294777D000A9BF61 /* ApplicationPassword */, B5A0369F214C0F4C00774E2C /* Internal */, B5BB1D0A20A204F400112D92 /* Extensions */, @@ -2746,6 +2749,14 @@ path = Product; sourceTree = ""; }; + DE66C5512976507100DAA978 /* CookieNonce */ = { + isa = PBXGroup; + children = ( + DE66C5522976508300DAA978 /* CookieNonceAuthenticator.swift */, + ); + path = CookieNonce; + sourceTree = ""; + }; DE97C3902861B8CD0042E973 /* Encoder */ = { isa = PBXGroup; children = ( @@ -2780,10 +2791,10 @@ EE54C899294777D000A9BF61 /* ApplicationPassword */ = { isa = PBXGroup; children = ( - DEFBA7532949CE6600C35BA9 /* RequestProcessor.swift */, + DEFBA7532949CE6600C35BA9 /* ApplicationPasswordRequestProcessor.swift */, EE54C89E2947782E00A9BF61 /* ApplicationPasswordUseCase.swift */, EE71CC3C2951A8EA0074D908 /* ApplicationPasswordStorage.swift */, - EE99814D295AA7430074AE68 /* RequestAuthenticator.swift */, + EE99814D295AA7430074AE68 /* ApplicationPasswordAuthenticator.swift */, EE99814F295AACE10074AE68 /* RequestConverter.swift */, ); path = ApplicationPassword; @@ -2830,7 +2841,7 @@ isa = PBXGroup; children = ( EE8DE431294B17CD005054E7 /* DefaultApplicationPasswordUseCaseTests.swift */, - EE76762E2962B85E000066FA /* RequestProcessorTests.swift */, + EE76762E2962B85E000066FA /* ApplicationPasswordRequestProcessorTests.swift */, ); path = ApplicationPassword; sourceTree = ""; @@ -3330,7 +3341,7 @@ 457A574025D1817E000797AD /* ShippingLabelAddressVerification.swift in Sources */, 74ABA1D1213F22CA00FFAD30 /* TopEarnersStatsRemote.swift in Sources */, DEC51AF127699E7A009F3DF4 /* SystemStatus+Page.swift in Sources */, - EE99814E295AA7430074AE68 /* RequestAuthenticator.swift in Sources */, + EE99814E295AA7430074AE68 /* ApplicationPasswordAuthenticator.swift in Sources */, 025CA2C0238EB8CB00B05C81 /* ProductShippingClass.swift in Sources */, 02C1CEF424C6A02B00703EBA /* ProductVariationMapper.swift in Sources */, 3105470C262E27F000C5C02B /* WCPayPaymentIntentStatusEnum.swift in Sources */, @@ -3345,6 +3356,7 @@ 451A97E9260B657D0059D135 /* ShippingLabelPredefinedOption.swift in Sources */, 02C2548425635BD000A04423 /* ShippingLabelPaperSize.swift in Sources */, CE132BBC223859710029DB6C /* ProductTag.swift in Sources */, + DE66C5532976508300DAA978 /* CookieNonceAuthenticator.swift in Sources */, 26650332261FFA1A0079A159 /* ProductAddOnEnvelope.swift in Sources */, D88D5A47230BC838007B6E01 /* ProductReview.swift in Sources */, DEFBA74E29485A7600C35BA9 /* RESTRequest.swift in Sources */, @@ -3361,7 +3373,7 @@ 020D07B823D852BB00FD9580 /* Media.swift in Sources */, B5BB1D0C20A2050300112D92 /* DateFormatter+Woo.swift in Sources */, 743E84EE2217244C00FAC9D7 /* ShipmentTrackingListMapper.swift in Sources */, - DEFBA7542949CE6600C35BA9 /* RequestProcessor.swift in Sources */, + DEFBA7542949CE6600C35BA9 /* ApplicationPasswordRequestProcessor.swift in Sources */, 451A97E5260B631E0059D135 /* ShippingLabelPredefinedPackage.swift in Sources */, BAB373722795A1FB00837B4A /* OrderTaxLine.swift in Sources */, EE54C89F2947782E00A9BF61 /* ApplicationPasswordUseCase.swift in Sources */, @@ -3753,7 +3765,7 @@ D800DA0A25EFEB9C001E13CE /* WCPayRemoteTests.swift in Sources */, E13BAD5328F8625600217769 /* InAppPurchasesRemoteTests.swift in Sources */, CC851D1425E52AB500249E9C /* Decimal+ExtensionsTests.swift in Sources */, - EE76762F2962B85E000066FA /* RequestProcessorTests.swift in Sources */, + EE76762F2962B85E000066FA /* ApplicationPasswordRequestProcessorTests.swift in Sources */, B554FA8B2180B1D500C54DFF /* NotificationsRemoteTests.swift in Sources */, B518662A20A09C6F00037A38 /* OrdersRemoteTests.swift in Sources */, 02EF166E292F0C5800D90AD6 /* PaymentRemoteTests.swift in Sources */, diff --git a/Networking/Networking/ApplicationPassword/RequestAuthenticator.swift b/Networking/Networking/ApplicationPassword/ApplicationPasswordAuthenticator.swift similarity index 90% rename from Networking/Networking/ApplicationPassword/RequestAuthenticator.swift rename to Networking/Networking/ApplicationPassword/ApplicationPasswordAuthenticator.swift index 2de5123fe7d..8395e68a512 100644 --- a/Networking/Networking/ApplicationPassword/RequestAuthenticator.swift +++ b/Networking/Networking/ApplicationPassword/ApplicationPasswordAuthenticator.swift @@ -1,9 +1,9 @@ -enum RequestAuthenticatorError: Error { +enum ApplicationPasswordAuthenticatorError: Error { case applicationPasswordUseCaseNotAvailable case applicationPasswordNotAvailable } -protocol RequestAuthenticator { +protocol ApplicationPasswordAuthenticator { /// Credentials to authenticate the URLRequest /// var credentials: Credentials? { get } @@ -26,7 +26,7 @@ protocol RequestAuthenticator { /// Authenticates request /// -public struct DefaultRequestAuthenticator: RequestAuthenticator { +public struct DefaultApplicationPasswordAuthenticator: ApplicationPasswordAuthenticator { /// Credentials to authenticate the URLRequest /// let credentials: Credentials? @@ -71,7 +71,7 @@ public struct DefaultRequestAuthenticator: RequestAuthenticator { /// func generateApplicationPassword() async throws { guard let applicationPasswordUseCase else { - throw RequestAuthenticatorError.applicationPasswordUseCaseNotAvailable + throw ApplicationPasswordAuthenticatorError.applicationPasswordUseCaseNotAvailable } let _ = try await applicationPasswordUseCase.generateNewPassword() return @@ -84,7 +84,7 @@ public struct DefaultRequestAuthenticator: RequestAuthenticator { } } -private extension DefaultRequestAuthenticator { +private extension DefaultApplicationPasswordAuthenticator { /// To check whether the given URLRequest is a REST API request /// func isRestAPIRequest(_ urlRequest: URLRequest) -> Bool { @@ -110,7 +110,7 @@ private extension DefaultRequestAuthenticator { /// func authenticateUsingApplicationPasswordIfPossible(_ urlRequest: URLRequest) throws -> URLRequest { guard let applicationPassword = applicationPasswordUseCase?.applicationPassword else { - throw RequestAuthenticatorError.applicationPasswordNotAvailable + throw ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable } return AuthenticatedRESTRequest(applicationPassword: applicationPassword, request: urlRequest).asURLRequest() diff --git a/Networking/Networking/ApplicationPassword/RequestProcessor.swift b/Networking/Networking/ApplicationPassword/ApplicationPasswordRequestProcessor.swift similarity index 82% rename from Networking/Networking/ApplicationPassword/RequestProcessor.swift rename to Networking/Networking/ApplicationPassword/ApplicationPasswordRequestProcessor.swift index 26360f141e4..df0175dec4d 100644 --- a/Networking/Networking/ApplicationPassword/RequestProcessor.swift +++ b/Networking/Networking/ApplicationPassword/ApplicationPasswordRequestProcessor.swift @@ -3,21 +3,21 @@ import Foundation /// Authenticates and retries requests /// -final class RequestProcessor { +final class ApplicationPasswordRequestProcessor { private var requestsToRetry = [RequestRetryCompletion]() private var isAuthenticating = false - private let requestAuthenticator: RequestAuthenticator + private let requestAuthenticator: ApplicationPasswordAuthenticator - init(requestAuthenticator: RequestAuthenticator) { + init(requestAuthenticator: ApplicationPasswordAuthenticator) { self.requestAuthenticator = requestAuthenticator } } // MARK: Request Authentication // -extension RequestProcessor: RequestAdapter { +extension ApplicationPasswordRequestProcessor: RequestAdapter { func adapt(_ urlRequest: URLRequest) throws -> URLRequest { return try requestAuthenticator.authenticate(urlRequest) } @@ -25,7 +25,7 @@ extension RequestProcessor: RequestAdapter { // MARK: Retrying Request // -extension RequestProcessor: RequestRetrier { +extension ApplicationPasswordRequestProcessor: RequestRetrier { func should(_ manager: Alamofire.SessionManager, retry request: Alamofire.Request, with error: Error, @@ -48,7 +48,7 @@ extension RequestProcessor: RequestRetrier { // MARK: Helpers // -private extension RequestProcessor { +private extension ApplicationPasswordRequestProcessor { func generateApplicationPassword() { Task(priority: .medium) { isAuthenticating = true @@ -66,7 +66,7 @@ private extension RequestProcessor { func shouldRetry(_ error: Error) -> Bool { // Need to generate application password - if .applicationPasswordNotAvailable == error as? RequestAuthenticatorError { + if .applicationPasswordNotAvailable == error as? ApplicationPasswordAuthenticatorError { return true } diff --git a/Networking/Networking/ApplicationPassword/ApplicationPasswordUseCase.swift b/Networking/Networking/ApplicationPassword/ApplicationPasswordUseCase.swift index ab9f1eecc45..8404da29d21 100644 --- a/Networking/Networking/ApplicationPassword/ApplicationPasswordUseCase.swift +++ b/Networking/Networking/ApplicationPassword/ApplicationPasswordUseCase.swift @@ -84,13 +84,11 @@ final public class DefaultApplicationPasswordUseCase: ApplicationPasswordUseCase throw ApplicationPasswordUseCaseError.failedToConstructLoginOrAdminURLUsingSiteAddress } // Prepares the authenticator with username and password - let authenticator = CookieNonceAuthenticator(username: username, - password: password, - loginURL: loginURL, - adminURL: adminURL, - version: Constants.defaultWPVersion, - nonce: nil) - self.network = WordPressOrgNetwork(authenticator: authenticator) + let config = CookieNonceAuthenticatorConfiguration(username: username, + password: password, + loginURL: loginURL, + adminURL: adminURL) + self.network = WordPressOrgNetwork(configuration: config) } } @@ -218,6 +216,5 @@ private extension DefaultApplicationPasswordUseCase { enum Constants { static let loginPath = "/wp-login.php" static let adminPath = "/wp-admin/" - static let defaultWPVersion = "5.6.0" // a default version that supports Ajax nonce retrieval } } diff --git a/Networking/Networking/CookieNonce/CookieNonceAuthenticator.swift b/Networking/Networking/CookieNonce/CookieNonceAuthenticator.swift new file mode 100644 index 00000000000..3cab1cc55d0 --- /dev/null +++ b/Networking/Networking/CookieNonce/CookieNonceAuthenticator.swift @@ -0,0 +1,172 @@ +import Alamofire +import Foundation + +/// An authenticator to handle cookie-nonce authentication. +/// This differs from WordPressKit's version by handling the nonce retrieval as a separate request +/// instead of a redirect from the login request - to fix issues with Pressable sites. +/// +/// This authenticator uses Ajax nonce retrieval method by default +/// since we are not supporting sites with WP versions earlier than 5.6.0. +/// +final class CookieNonceAuthenticator: RequestRetrier & RequestAdapter { + private let username: String + private let password: String + private let loginURL: URL + private let adminURL: URL + private var nonce: String? + + private var canRetry = true + private var isAuthenticating = false + private var requestsToRetry = [RequestRetryCompletion]() + + init(configuration: CookieNonceAuthenticatorConfiguration) { + self.username = configuration.username + self.password = configuration.password + self.loginURL = configuration.loginURL + self.adminURL = configuration.adminURL + } + + // MARK: Request Adapter + + func adapt(_ urlRequest: URLRequest) throws -> URLRequest { + guard let nonce else { + return urlRequest + } + var adaptedRequest = urlRequest + adaptedRequest.addValue(nonce, forHTTPHeaderField: "X-WP-Nonce") + return adaptedRequest + } + + // MARK: Retrier + func should(_ manager: SessionManager, retry request: Alamofire.Request, with error: Swift.Error, completion: @escaping RequestRetryCompletion) { + guard + canRetry, + // Only retry once + request.retryCount == 0, + // And don't retry the login request + request.request?.url != loginURL, + // Only retry because of failed authorization + case .responseValidationFailed(reason: .unacceptableStatusCode(code: 401)) = error as? AFError + else { + return completion(false, 0.0) + } + + requestsToRetry.append(completion) + if !isAuthenticating { + startLoginSequence(manager: manager) + } + } + + enum Error: Swift.Error { + case invalidNewPostURL + case postLoginFailed(Swift.Error) + case missingNonce + case unknown(Swift.Error) + } +} + +// MARK: Private helpers +private extension CookieNonceAuthenticator { + + func startLoginSequence(manager: SessionManager) { + DDLogInfo("Starting Cookie+Nonce login sequence for \(loginURL)") + guard let nonceRetrievalURL = buildNonceRequestURL(base: adminURL), + let nonceRequest = try? URLRequest(url: nonceRetrievalURL, method: .get) else { + return invalidateLoginSequence(error: .invalidNewPostURL) + } + Task(priority: .medium) { + do { + try await handleSiteCredentialLogin(manager: manager) + let page = try await handleNonceRetrieval(request: nonceRequest, manager: manager) + guard let nonce = readNonceFromAjaxAction(html: page) else { + throw CookieNonceAuthenticator.Error.missingNonce + } + self.nonce = nonce + successfulLoginSequence() + } catch let error as CookieNonceAuthenticator.Error { + invalidateLoginSequence(error: error) + } catch { + DDLogError("⛔️ Cookie nonce authenticator failed with uncaught error: \(error)") + } + } + } + + func handleSiteCredentialLogin(manager: SessionManager) async throws { + let request = authenticatedRequest() + return try await withCheckedThrowingContinuation { continuation in + manager.request(request) + .validate() + .response { response in + if let error = response.error { + continuation.resume(throwing: error) + } else { + continuation.resume(returning: ()) + } + } + } + } + + func handleNonceRetrieval(request: URLRequest, manager: SessionManager) async throws -> String { + try await withCheckedThrowingContinuation { continuation -> Void in + manager.request(request) + .validate() + .responseString { response in + switch response.result { + case .failure(let error): + continuation.resume(throwing: error) + case .success(let page): + continuation.resume(returning: page) + } + } + } + } + + func successfulLoginSequence() { + DDLogInfo("Completed Cookie+Nonce login sequence for \(loginURL)") + completeRequests(true) + } + + func invalidateLoginSequence(error: Error) { + canRetry = false + if case .postLoginFailed(let originalError) = error { + let nsError = originalError as NSError + if nsError.domain == NSURLErrorDomain, nsError.code == NSURLErrorNotConnectedToInternet { + canRetry = true + } + } + DDLogInfo("Aborting Cookie+Nonce login sequence for \(loginURL)") + completeRequests(false) + isAuthenticating = false + } + + func completeRequests(_ shouldRetry: Bool) { + requestsToRetry.forEach { (completion) in + completion(shouldRetry, 0.0) + } + requestsToRetry.removeAll() + } + + func authenticatedRequest() -> URLRequest { + var request = URLRequest(url: loginURL) + + request.httpMethod = "POST" + request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") + + var parameters = [URLQueryItem]() + parameters.append(URLQueryItem(name: "log", value: username)) + parameters.append(URLQueryItem(name: "pwd", value: password)) + parameters.append(URLQueryItem(name: "rememberme", value: "true")) + var components = URLComponents() + components.queryItems = parameters + request.httpBody = components.percentEncodedQuery?.data(using: .utf8) + return request + } + + func readNonceFromAjaxAction(html: String) -> String? { + html.isEmpty ? nil : html + } + + func buildNonceRequestURL(base: URL) -> URL? { + URL(string: "admin-ajax.php?action=rest-nonce", relativeTo: base) + } +} diff --git a/Networking/Networking/Network/AlamofireNetwork.swift b/Networking/Networking/Network/AlamofireNetwork.swift index 4cd0f30575e..27dfdc15b6b 100644 --- a/Networking/Networking/Network/AlamofireNetwork.swift +++ b/Networking/Networking/Network/AlamofireNetwork.swift @@ -28,7 +28,7 @@ public class AlamofireNetwork: Network { /// Authenticator to update requests authorization header if possible. /// - private let requestAuthenticator: RequestProcessor + private let requestAuthenticator: ApplicationPasswordRequestProcessor public var session: URLSession { SessionManager.default.session } @@ -36,7 +36,7 @@ public class AlamofireNetwork: Network { /// public required init(credentials: Credentials?) { self.requestConverter = RequestConverter(credentials: credentials) - self.requestAuthenticator = RequestProcessor(requestAuthenticator: DefaultRequestAuthenticator(credentials: credentials)) + self.requestAuthenticator = ApplicationPasswordRequestProcessor(requestAuthenticator: DefaultApplicationPasswordAuthenticator(credentials: credentials)) } /// Executes the specified Network Request. Upon completion, the payload will be sent back to the caller as a Data instance. diff --git a/Networking/Networking/Network/WordPressOrgNetwork.swift b/Networking/Networking/Network/WordPressOrgNetwork.swift index 0735891da04..271db38ab5f 100644 --- a/Networking/Networking/Network/WordPressOrgNetwork.swift +++ b/Networking/Networking/Network/WordPressOrgNetwork.swift @@ -1,13 +1,28 @@ import Alamofire import Combine import Foundation -import WordPressKit + +/// Configuration for handling cookie nonce authentication. +/// +public struct CookieNonceAuthenticatorConfiguration { + let username: String + let password: String + let loginURL: URL + let adminURL: URL + + public init(username: String, password: String, loginURL: URL, adminURL: URL) { + self.username = username + self.password = password + self.loginURL = loginURL + self.adminURL = adminURL + } +} /// Class to handle WP.org REST API requests. /// public final class WordPressOrgNetwork: Network { - private let authenticator: Authenticator? + private let authenticator: CookieNonceAuthenticator private let userAgent: String? private lazy var sessionManager: Alamofire.SessionManager = { @@ -27,8 +42,8 @@ public final class WordPressOrgNetwork: Network { public var session: URLSession { sessionManager.session } - public init(authenticator: Authenticator? = nil, userAgent: String = UserAgent.defaultUserAgent) { - self.authenticator = authenticator + public init(configuration: CookieNonceAuthenticatorConfiguration, userAgent: String = UserAgent.defaultUserAgent) { + self.authenticator = CookieNonceAuthenticator(configuration: configuration) self.userAgent = userAgent } diff --git a/Networking/NetworkingTests/ApplicationPassword/RequestProcessorTests.swift b/Networking/NetworkingTests/ApplicationPassword/ApplicationPasswordRequestProcessorTests.swift similarity index 86% rename from Networking/NetworkingTests/ApplicationPassword/RequestProcessorTests.swift rename to Networking/NetworkingTests/ApplicationPassword/ApplicationPasswordRequestProcessorTests.swift index affa03ea631..4c0ff3bc6fb 100644 --- a/Networking/NetworkingTests/ApplicationPassword/RequestProcessorTests.swift +++ b/Networking/NetworkingTests/ApplicationPassword/ApplicationPasswordRequestProcessorTests.swift @@ -4,9 +4,9 @@ import XCTest /// RequestProcessor Unit Tests /// -final class RequestProcessorTests: XCTestCase { +final class ApplicationPasswordRequestProcessorTests: XCTestCase { private var mockRequestAuthenticator: MockRequestAuthenticator! - private var sut: RequestProcessor! + private var sut: ApplicationPasswordRequestProcessor! private var sessionManager: Alamofire.SessionManager! private let url = URL(string: "https://test.com/")! @@ -16,7 +16,7 @@ final class RequestProcessorTests: XCTestCase { sessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.default) mockRequestAuthenticator = MockRequestAuthenticator() - sut = RequestProcessor(requestAuthenticator: mockRequestAuthenticator) + sut = ApplicationPasswordRequestProcessor(requestAuthenticator: mockRequestAuthenticator) } override func tearDown() { @@ -50,7 +50,8 @@ final class RequestProcessorTests: XCTestCase { // When request.retryCount = 0 let shouldRetry = waitFor { promise in - self.sut.should(sessionManager, retry: request, with: RequestAuthenticatorError.applicationPasswordNotAvailable) { shouldRetry, timeDelay in + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable + self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(shouldRetry) } } @@ -67,7 +68,8 @@ final class RequestProcessorTests: XCTestCase { // When request.retryCount = 1 let shouldRetry = waitFor { promise in - self.sut.should(sessionManager, retry: request, with: RequestAuthenticatorError.applicationPasswordNotAvailable) { shouldRetry, timeDelay in + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable + self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(shouldRetry) } } @@ -86,7 +88,8 @@ final class RequestProcessorTests: XCTestCase { // When mockRequestAuthenticator.mockedShouldRetryValue = true let shouldRetry = waitFor { promise in - self.sut.should(sessionManager, retry: request, with: RequestAuthenticatorError.applicationPasswordNotAvailable) { shouldRetry, timeDelay in + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable + self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(shouldRetry) } } @@ -103,7 +106,8 @@ final class RequestProcessorTests: XCTestCase { // When mockRequestAuthenticator.mockedShouldRetryValue = false let shouldRetry = waitFor { promise in - self.sut.should(sessionManager, retry: request, with: RequestAuthenticatorError.applicationPasswordNotAvailable) { shouldRetry, timeDelay in + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable + self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(shouldRetry) } } @@ -120,7 +124,7 @@ final class RequestProcessorTests: XCTestCase { let request = try mockRequest() // When - let error = RequestAuthenticatorError.applicationPasswordNotAvailable + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable let shouldRetry = waitFor { promise in self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(shouldRetry) @@ -173,7 +177,7 @@ final class RequestProcessorTests: XCTestCase { let request = try mockRequest() // When - let error = RequestAuthenticatorError.applicationPasswordNotAvailable + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable waitFor { promise in self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(()) @@ -192,7 +196,8 @@ final class RequestProcessorTests: XCTestCase { // When mockRequestAuthenticator.mockedShouldRetryValue = false waitFor { promise in - self.sut.should(sessionManager, retry: request, with: RequestAuthenticatorError.applicationPasswordNotAvailable) { shouldRetry, timeDelay in + let error = ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable + self.sut.should(sessionManager, retry: request, with: error) { shouldRetry, timeDelay in promise(()) } } @@ -204,7 +209,7 @@ final class RequestProcessorTests: XCTestCase { // MARK: Helpers // -private extension RequestProcessorTests { +private extension ApplicationPasswordRequestProcessorTests { func mockRequest() throws -> Alamofire.Request { let originalTask = MockTaskConvertible() let task = try originalTask.task(session: sessionManager.session, adapter: nil, queue: .main) @@ -221,7 +226,7 @@ private class MockTaskConvertible: TaskConvertible { } } -private class MockRequestAuthenticator: RequestAuthenticator { +private class MockRequestAuthenticator: ApplicationPasswordAuthenticator { var mockedShouldRetryValue: Bool? private(set) var authenticateCalled = false diff --git a/Networking/NetworkingTests/Network/DefaultRequestAuthenticatorTests.swift b/Networking/NetworkingTests/Network/DefaultRequestAuthenticatorTests.swift index f2de80abc8c..e4b70994d6e 100644 --- a/Networking/NetworkingTests/Network/DefaultRequestAuthenticatorTests.swift +++ b/Networking/NetworkingTests/Network/DefaultRequestAuthenticatorTests.swift @@ -6,7 +6,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { func test_authenticateRequest_returns_unauthenticated_request_for_non_REST_request_without_WPCOM_credentials() throws { // Given - let authenticator = DefaultRequestAuthenticator(credentials: nil) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: nil) let jetpackRequest = JetpackRequest(wooApiVersion: .mark1, method: .get, siteID: 123, path: "test", availableAsRESTRequest: false) // When @@ -20,7 +20,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { func test_authenticatedRequest_returns_authenticated_request_for_non_REST_request_with_WPCOM_credentials() throws { // Given let credentials = Credentials(authToken: "secret") - let authenticator = DefaultRequestAuthenticator(credentials: credentials) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: credentials) let jetpackRequest = JetpackRequest(wooApiVersion: .mark1, method: .get, siteID: 123, path: "test", availableAsRESTRequest: false) // When @@ -38,7 +38,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { let credentials: Credentials = .wporg(username: "admin", password: "supersecret", siteAddress: siteURL) let applicationPassword = ApplicationPassword(wpOrgUsername: credentials.username, password: .init(credentials.secret)) let useCase = MockApplicationPasswordUseCase(mockApplicationPassword: applicationPassword) - let authenticator = DefaultRequestAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) let wooAPIVersion = WooAPIVersion.mark1 let basePath = RESTRequest.Settings.basePath let restRequest = RESTRequest(siteURL: siteURL, wooApiVersion: wooAPIVersion, method: .get, path: "test") @@ -60,7 +60,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { let credentials: Credentials = .wporg(username: "admin", password: "supersecret", siteAddress: siteURL) let applicationPassword = ApplicationPassword(wpOrgUsername: credentials.username, password: .init(credentials.secret)) let useCase = MockApplicationPasswordUseCase(mockGeneratedPassword: applicationPassword) - let authenticator = DefaultRequestAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) let wooAPIVersion = WooAPIVersion.mark1 let basePath = RESTRequest.Settings.basePath let restRequest = RESTRequest(siteURL: siteURL, wooApiVersion: wooAPIVersion, method: .get, path: "test") @@ -70,7 +70,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { do { let _ = try authenticator.authenticate(request) - } catch RequestAuthenticatorError.applicationPasswordNotAvailable { + } catch ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable { try await authenticator.generateApplicationPassword() } @@ -88,7 +88,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { let siteURL = "https://test.com/" let credentials: Credentials = .wporg(username: "admin", password: "supersecret", siteAddress: siteURL) let useCase = MockApplicationPasswordUseCase(mockGenerationError: NetworkError.timeout) - let authenticator = DefaultRequestAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) let wooAPIVersion = WooAPIVersion.mark1 let restRequest = RESTRequest(siteURL: siteURL, wooApiVersion: wooAPIVersion, method: .get, path: "test") @@ -98,7 +98,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { let request = try restRequest.asURLRequest() do { let _ = try authenticator.authenticate(request) - } catch RequestAuthenticatorError.applicationPasswordNotAvailable { + } catch ApplicationPasswordAuthenticatorError.applicationPasswordNotAvailable { // Then do { try await authenticator.generateApplicationPassword() @@ -115,7 +115,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { let siteURL = "https://test.com/" let credentials: Credentials = .wporg(username: "admin", password: "supersecret", siteAddress: siteURL) let useCase = MockApplicationPasswordUseCase(mockGenerationError: NetworkError.timeout) - let authenticator = DefaultRequestAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) let wooAPIVersion = WooAPIVersion.mark1 let restRequest = RESTRequest(siteURL: siteURL, wooApiVersion: wooAPIVersion, method: .get, path: "test") @@ -131,7 +131,7 @@ final class DefaultRequestAuthenticatorTests: XCTestCase { let siteURL = "https://test.com/" let credentials: Credentials = .wporg(username: "admin", password: "supersecret", siteAddress: siteURL) let useCase = MockApplicationPasswordUseCase(mockGenerationError: NetworkError.timeout) - let authenticator = DefaultRequestAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) + let authenticator = DefaultApplicationPasswordAuthenticator(credentials: credentials, applicationPasswordUseCase: useCase) let jetpackRequest = JetpackRequest(wooApiVersion: .mark1, method: .get, siteID: 123, path: "test", availableAsRESTRequest: false) // When diff --git a/WooCommerce/Classes/Authentication/Jetpack Setup/Site Credential Login/SiteCredentialLoginViewModel.swift b/WooCommerce/Classes/Authentication/Jetpack Setup/Site Credential Login/SiteCredentialLoginViewModel.swift index 61b175de9ed..ea28ea2f6ea 100644 --- a/WooCommerce/Classes/Authentication/Jetpack Setup/Site Credential Login/SiteCredentialLoginViewModel.swift +++ b/WooCommerce/Classes/Authentication/Jetpack Setup/Site Credential Login/SiteCredentialLoginViewModel.swift @@ -1,9 +1,8 @@ import Foundation import Yosemite -import WordPressKit import WordPressAuthenticator import enum Alamofire.AFError -import class Networking.UserAgent +import struct Networking.CookieNonceAuthenticatorConfiguration import class Networking.WordPressOrgNetwork /// View model for `SiteCredentialLoginView`. @@ -78,13 +77,11 @@ private extension SiteCredentialLoginViewModel { return } // Prepares the authenticator with username and password - let authenticator = CookieNonceAuthenticator(username: username, - password: password, - loginURL: loginURL, - adminURL: adminURL, - version: Constants.defaultWPVersion, - nonce: nil) - let network = WordPressOrgNetwork(authenticator: authenticator) + let config = CookieNonceAuthenticatorConfiguration(username: username, + password: password, + loginURL: loginURL, + adminURL: adminURL) + let network = WordPressOrgNetwork(configuration: config) let authenticationAction = JetpackConnectionAction.authenticate(siteURL: siteURL, network: network) stores.dispatch(authenticationAction) } @@ -141,6 +138,5 @@ extension SiteCredentialLoginViewModel { enum Constants { static let loginPath = "/wp-login.php" static let adminPath = "/wp-admin/" - static let defaultWPVersion = "5.6.0" // a default version that supports Ajax nonce retrieval } } diff --git a/WooCommerce/Classes/Authentication/Navigation Exceptions/WrongAccountErrorViewModel.swift b/WooCommerce/Classes/Authentication/Navigation Exceptions/WrongAccountErrorViewModel.swift index 49364a6522c..86128cf30f4 100644 --- a/WooCommerce/Classes/Authentication/Navigation Exceptions/WrongAccountErrorViewModel.swift +++ b/WooCommerce/Classes/Authentication/Navigation Exceptions/WrongAccountErrorViewModel.swift @@ -244,10 +244,10 @@ private extension WrongAccountErrorViewModel { /// Prepares `JetpackConnectionStore` to authenticate subsequent requests to WP.org API. /// func authenticate(with credentials: WordPressOrgCredentials) { - guard let authenticator = credentials.makeCookieNonceAuthenticator() else { + guard let config = credentials.makeCookieNonceAuthenticatorConfig() else { return } - let network = WordPressOrgNetwork(authenticator: authenticator) + let network = WordPressOrgNetwork(configuration: config) let action = JetpackConnectionAction.authenticate(siteURL: siteURL, network: network) storesManager.dispatch(action) } diff --git a/WooCommerce/Classes/Authentication/WordPressOrgCredentials+Authenticator.swift b/WooCommerce/Classes/Authentication/WordPressOrgCredentials+Authenticator.swift index 4009828bf4c..0a0add10237 100644 --- a/WooCommerce/Classes/Authentication/WordPressOrgCredentials+Authenticator.swift +++ b/WooCommerce/Classes/Authentication/WordPressOrgCredentials+Authenticator.swift @@ -1,6 +1,6 @@ import Foundation -import WordPressKit import WordPressAuthenticator +import struct Networking.CookieNonceAuthenticatorConfiguration /// Extension to create cookie nonce authenticator from WP.org credentials. /// @@ -15,31 +15,17 @@ extension WordPressOrgCredentials { return value ?? siteURL + Strings.adminPath } - var version: String { - let value = optionValue(for: Key.version.rawValue) - if let stringValue = value as? String { - return stringValue - } - - if let numberValue = value as? NSNumber { - return numberValue.stringValue - } - - return "" - } - - /// Returns a cookie nonce authenticator based on the current credentials + /// Returns a cookie nonce authenticator configuration based on the current credentials /// - func makeCookieNonceAuthenticator() -> CookieNonceAuthenticator? { + func makeCookieNonceAuthenticatorConfig() -> CookieNonceAuthenticatorConfiguration? { guard let loginURL = URL(string: loginURL), let adminURL = URL(string: adminURL) else { return nil } - return CookieNonceAuthenticator(username: username, - password: password, - loginURL: loginURL, - adminURL: adminURL, - version: version) + return CookieNonceAuthenticatorConfiguration(username: username, + password: password, + loginURL: loginURL, + adminURL: adminURL) } } @@ -65,7 +51,6 @@ private extension WordPressOrgCredentials { enum Key: String { case loginURL = "login_url" case adminURL = "admin_url" - case version = "software_version" case value } } diff --git a/WooCommerce/WooCommerceTests/Extensions/WordPressOrgCredentialsAuthenticatorTests.swift b/WooCommerce/WooCommerceTests/Extensions/WordPressOrgCredentialsAuthenticatorTests.swift index 2be6ebb5e0e..3a0bae62598 100644 --- a/WooCommerce/WooCommerceTests/Extensions/WordPressOrgCredentialsAuthenticatorTests.swift +++ b/WooCommerce/WooCommerceTests/Extensions/WordPressOrgCredentialsAuthenticatorTests.swift @@ -29,23 +29,15 @@ final class WordPressOrgCredentialsAuthenticatorTests: XCTestCase { assertEqual(credentials.adminURL, "https://test.com/wp-admin") } - func test_version_is_correct() { - // Given - let credentials = WordPressOrgCredentials(username: username, password: password, xmlrpc: xmlrpc, options: options) - - // Then - assertEqual(credentials.version, "5.3.1") - } - - func test_authenticator_is_created_correctly() { + func test_configuration_is_created_correctly() { // Given let credentials = WordPressOrgCredentials(username: username, password: password, xmlrpc: xmlrpc, options: options) // When - let authenticator = credentials.makeCookieNonceAuthenticator() + let configuration = credentials.makeCookieNonceAuthenticatorConfig() // Then - XCTAssertNotNil(authenticator) + XCTAssertNotNil(configuration) } }