Skip to content

Commit 75cc81e

Browse files
authored
Application password: Fetch site username when authenticated with WPCom (#16037)
2 parents 413b1a7 + e5890fc commit 75cc81e

File tree

6 files changed

+53
-24
lines changed

6 files changed

+53
-24
lines changed

Modules/Sources/NetworkingCore/ApplicationPassword/ApplicationPasswordUseCase.swift

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ final public class DefaultApplicationPasswordUseCase: ApplicationPasswordUseCase
3939
///
4040
private let authenticationType: AuthenticationType
4141

42-
/// WPOrg username
43-
///
44-
private var username: String {
45-
switch authenticationType {
46-
case .wporg(let username, _, _):
47-
return username
48-
case .wpcom(let wporgUsername, _):
49-
return wporgUsername
50-
}
51-
}
52-
5342
/// To generate and delete application password
5443
///
5544
private let network: Network
@@ -165,7 +154,7 @@ private extension DefaultApplicationPasswordUseCase {
165154
/// or through Jetpack proxy.
166155
func constructRequest(method: HTTPMethod, path: String, parameters: [String: Any]? = nil) -> Request {
167156
switch authenticationType {
168-
case .wpcom(_, let siteID):
157+
case .wpcom(let siteID):
169158
JetpackRequest(wooApiVersion: .none,
170159
method: method,
171160
siteID: siteID,
@@ -190,13 +179,21 @@ private extension DefaultApplicationPasswordUseCase {
190179
let request = constructRequest(method: .post,
191180
path: Path.applicationPasswords,
192181
parameters: parameters)
182+
let wpOrgUsername = try await {
183+
switch authenticationType {
184+
case .wporg(let username, _, _):
185+
return username
186+
case .wpcom(let siteID):
187+
return try await fetchWPOrgUsername(siteID: siteID)
188+
}
189+
}()
190+
193191
return try await withCheckedThrowingContinuation { continuation in
194-
network.responseData(for: request) { [weak self] result in
195-
guard let self else { return }
192+
network.responseData(for: request) { result in
196193
switch result {
197194
case .success(let data):
198195
do {
199-
let mapper = ApplicationPasswordMapper(wpOrgUsername: self.username)
196+
let mapper = ApplicationPasswordMapper(wpOrgUsername: wpOrgUsername)
200197
let password = try mapper.map(response: data)
201198
continuation.resume(returning: password)
202199
} catch {
@@ -237,7 +234,7 @@ private extension DefaultApplicationPasswordUseCase {
237234
do {
238235
let mapper = ApplicationPasswordNameAndUUIDMapper()
239236
let list = try mapper.map(response: data)
240-
if let item = list.first(where: { $0.name == passwordName }) {
237+
if let item = list.last(where: { $0.name == passwordName }) {
241238
continuation.resume(returning: item.uuid)
242239
} else {
243240
continuation.resume(throwing: ApplicationPasswordUseCaseError.unableToFindPasswordUUID)
@@ -268,12 +265,39 @@ private extension DefaultApplicationPasswordUseCase {
268265
}
269266
}
270267
}
268+
269+
func fetchWPOrgUsername(siteID: Int64) async throws -> String {
270+
let parameters = [
271+
ParameterKey.context: Constants.editValue
272+
]
273+
let request = JetpackRequest(wooApiVersion: .none,
274+
method: .get,
275+
siteID: siteID,
276+
path: Path.userDetails,
277+
parameters: parameters)
278+
return try await withCheckedThrowingContinuation { continuation in
279+
network.responseData(for: request) { result in
280+
switch result {
281+
case .success(let data):
282+
let mapper = UserMapper(siteID: siteID)
283+
do {
284+
let user = try mapper.map(response: data)
285+
continuation.resume(returning: user.username)
286+
} catch {
287+
continuation.resume(throwing: error)
288+
}
289+
case .failure(let error):
290+
continuation.resume(throwing: error)
291+
}
292+
}
293+
}
294+
}
271295
}
272296

273297
extension DefaultApplicationPasswordUseCase {
274298
enum AuthenticationType {
275299
case wporg(username: String, password: String, siteAddress: String)
276-
case wpcom(wporgUsername: String, siteID: Int64)
300+
case wpcom(siteID: Int64)
277301
}
278302
}
279303

@@ -282,10 +306,12 @@ extension DefaultApplicationPasswordUseCase {
282306
private extension DefaultApplicationPasswordUseCase {
283307
enum Path {
284308
static let applicationPasswords = "wp/v2/users/me/application-passwords"
309+
static let userDetails = "wp/v2/users/me"
285310
}
286311

287312
enum ParameterKey {
288313
static let name = "name"
314+
static let context = "context"
289315
}
290316

291317
enum ErrorCode {
@@ -298,5 +324,6 @@ private extension DefaultApplicationPasswordUseCase {
298324
enum Constants {
299325
static let loginPath = "/wp-login.php"
300326
static let adminPath = "/wp-admin/"
327+
static let editValue = "edit"
301328
}
302329
}

Modules/Sources/Yosemite/Model/Mocks/MockSessionManager.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public struct MockSessionManager: SessionManagerProtocol {
3131

3232
public var defaultStoreURL: String?
3333

34+
/// periphery: ignore
3435
public var defaultRoles: [User.Role] = []
3536

3637
public var defaultStoreIDPublisher: AnyPublisher<Int64?, Never>

Modules/Tests/NetworkingTests/ApplicationPassword/DefaultApplicationPasswordUseCaseTests.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ final class DefaultApplicationPasswordUseCaseTests: XCTestCase {
1414
///
1515
private enum URLSuffix {
1616
static let generateApplicationPassword = "users/me/application-passwords"
17+
static let userDetails = "wp/v2/users/me"
1718
}
1819

1920
override func setUp() {
@@ -95,23 +96,23 @@ final class DefaultApplicationPasswordUseCaseTests: XCTestCase {
9596
// Given
9697
network.simulateResponse(requestUrlSuffix: URLSuffix.generateApplicationPassword,
9798
filename: "generate-application-password-using-wporg-creds-success")
98-
let wporgUsername = "username"
99-
let sut = DefaultApplicationPasswordUseCase(type: .wpcom(wporgUsername: wporgUsername, siteID: 123), network: network)
99+
network.simulateResponse(requestUrlSuffix: URLSuffix.userDetails, filename: "user-complete")
100+
let sut = DefaultApplicationPasswordUseCase(type: .wpcom(siteID: 123), network: network)
100101

101102
// When
102103
let password = try await sut.generateNewPassword()
103104

104105
// Then
105106
XCTAssertEqual(password.password.secretValue, "passwordvalue")
106-
XCTAssertEqual(password.wpOrgUsername, wporgUsername)
107+
XCTAssertEqual(password.wpOrgUsername, "test-username")
107108
}
108109

109110
func test_applicationPasswordsDisabled_error_is_thrown_if_generating_password_fails_with_501_error_when_authenticated_with_wpcom() async throws {
110111
// Given
111112
let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 501))
112113
network.simulateError(requestUrlSuffix: URLSuffix.generateApplicationPassword, error: error)
113-
let wporgUsername = "username"
114-
let sut = DefaultApplicationPasswordUseCase(type: .wpcom(wporgUsername: wporgUsername, siteID: 123), network: network)
114+
network.simulateResponse(requestUrlSuffix: URLSuffix.userDetails, filename: "user-complete")
115+
let sut = DefaultApplicationPasswordUseCase(type: .wpcom(siteID: 123), network: network)
115116

116117
// When
117118
var failure: ApplicationPasswordUseCaseError?
@@ -129,8 +130,8 @@ final class DefaultApplicationPasswordUseCaseTests: XCTestCase {
129130
// Given
130131
let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 401))
131132
network.simulateError(requestUrlSuffix: URLSuffix.generateApplicationPassword, error: error)
132-
let wporgUsername = "username"
133-
let sut = DefaultApplicationPasswordUseCase(type: .wpcom(wporgUsername: wporgUsername, siteID: 123), network: network)
133+
network.simulateResponse(requestUrlSuffix: URLSuffix.userDetails, filename: "user-complete")
134+
let sut = DefaultApplicationPasswordUseCase(type: .wpcom(siteID: 123), network: network)
134135

135136
// When
136137
var failure: ApplicationPasswordUseCaseError?

0 commit comments

Comments
 (0)