Skip to content

Commit 58d8adb

Browse files
committed
Check error code instead of http code 501
1 parent 5bb95f6 commit 58d8adb

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

Modules/Sources/NetworkingCore/ApplicationPassword/RequestProcessor.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,16 @@ private extension RequestProcessor {
107107
} catch {
108108
return false
109109
}
110-
case NetworkError.unacceptableStatusCode(let statusCode, let response) where statusCode == 501:
111-
fallthrough // treat this the same as 404 code
112110
case NetworkError.notFound:
113111
/// Site doesn't support application password
114112
delegate?.didFailToAuthenticateRequestWithApplicationPassword(siteID: currentSiteID)
115113
return false
114+
case let networkError as NetworkError:
115+
if let code = networkError.errorCode,
116+
Constants.disabledCodes.contains(code) {
117+
delegate?.didFailToAuthenticateRequestWithApplicationPassword(siteID: currentSiteID)
118+
}
119+
return false
116120
default:
117121
return false
118122
}
@@ -138,6 +142,15 @@ private extension RequestProcessor {
138142
}
139143
}
140144

145+
private extension RequestProcessor {
146+
enum Constants {
147+
static let disabledCodes = [
148+
"application_passwords_disabled",
149+
"application_passwords_disabled_for_user"
150+
]
151+
}
152+
}
153+
141154
// MARK: - Application Password Notifications
142155
//
143156
public extension NSNotification.Name {

Modules/Sources/NetworkingCore/Network/NetworkError.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ public enum NetworkError: Error, Equatable {
4949
return nil
5050
}
5151
}
52+
53+
/// Content of the `code` field in the response if available
54+
var errorCode: String? {
55+
guard let response else { return nil }
56+
let decoder = JSONDecoder()
57+
guard let decodedResponse = try? decoder.decode(NetworkErrorResponse.self, from: response) else {
58+
return nil
59+
}
60+
return decodedResponse.code
61+
}
5262
}
5363

5464

@@ -121,3 +131,28 @@ extension NetworkError: CustomStringConvertible {
121131
}
122132
}
123133
}
134+
135+
struct NetworkErrorResponse: Decodable {
136+
let code: String?
137+
let message: String?
138+
139+
init(from decoder: Decoder) throws {
140+
let container = try decoder.container(keyedBy: CodingKeys.self)
141+
self.code = try {
142+
let errorValue = try container.decodeIfPresent(String.self, forKey: .error)
143+
if let errorValue {
144+
return errorValue
145+
}
146+
return try container.decodeIfPresent(String.self, forKey: .code)
147+
}()
148+
self.message = try container.decodeIfPresent(String.self, forKey: .message)
149+
}
150+
151+
/// Coding Keys
152+
///
153+
private enum CodingKeys: String, CodingKey {
154+
case error
155+
case code
156+
case message
157+
}
158+
}

Modules/Tests/NetworkingTests/ApplicationPassword/RequestProcessorTests.swift

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ final class RequestProcessorTests: XCTestCase {
326326
}
327327
}
328328

329-
func test_delegate_called_when_501_error_occurs_with_wpcom_authentication() throws {
329+
func test_delegate_called_when_application_password_disabled() throws {
330330
// Given
331331
let session = Alamofire.Session(configuration: URLSessionConfiguration.default)
332332
let request = try mockRequest()
@@ -338,7 +338,41 @@ final class RequestProcessorTests: XCTestCase {
338338
sut.updateAuthenticator(mockRequestAuthenticator)
339339
sut.delegate = mockDelegate
340340

341-
let notSupportedError = NetworkError.unacceptableStatusCode(statusCode: 501, response: nil)
341+
let response = ["error": "application_passwords_disabled"]
342+
let data = try JSONEncoder().encode(response)
343+
let notSupportedError = NetworkError.unacceptableStatusCode(statusCode: 501, response: data)
344+
mockRequestAuthenticator.mockErrorWhileGeneratingPassword = notSupportedError
345+
346+
// When
347+
let error = RequestAuthenticatorError.applicationPasswordNotAvailable
348+
let shouldRetry = waitFor { promise in
349+
self.sut.retry(request, for: session, dueTo: error) { shouldRetry in
350+
promise(shouldRetry)
351+
}
352+
}
353+
354+
// Then
355+
XCTAssertFalse(shouldRetry.retryRequired)
356+
waitUntil {
357+
mockDelegate.didFailToAuthenticateRequestForSiteID == 123
358+
}
359+
}
360+
361+
func test_delegate_called_when_application_password_disabled_for_user() throws {
362+
// Given
363+
let session = Alamofire.Session(configuration: URLSessionConfiguration.default)
364+
let request = try mockRequest()
365+
let wpcomCredentials = Networking.Credentials.wpcom(username: "test", authToken: "token", siteAddress: "test.com")
366+
let mockDelegate = MockRequestProcessorDelegate()
367+
368+
mockRequestAuthenticator.credentials = wpcomCredentials
369+
mockRequestAuthenticator.jetpackSiteID = 123
370+
sut.updateAuthenticator(mockRequestAuthenticator)
371+
sut.delegate = mockDelegate
372+
373+
let response = ["error": "application_passwords_disabled_for_user"]
374+
let data = try JSONEncoder().encode(response)
375+
let notSupportedError = NetworkError.unacceptableStatusCode(statusCode: 501, response: data)
342376
mockRequestAuthenticator.mockErrorWhileGeneratingPassword = notSupportedError
343377

344378
// When

0 commit comments

Comments
 (0)