From 011087baf55c5145edbe510f1027eabc2ac098c4 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Mon, 12 Oct 2026 22:27:32 +0300 Subject: [PATCH] Adopt correct UIAA and session token passing usage as per spec. --- .../Mocks/SDK/IdentityResetHandleSDKMock.swift | 2 +- .../EncryptionResetScreenViewModel.swift | 14 +++++++------- .../DeactivateAccountScreenViewModel.swift | 9 --------- .../Sources/Services/Client/ClientProxy.swift | 5 ++--- .../Services/Client/ClientProxyProtocol.swift | 2 +- ...DeactivateAccountScreenViewModelTests.swift | 18 +++++------------- 6 files changed, 16 insertions(+), 34 deletions(-) diff --git a/ElementX/Sources/Mocks/SDK/IdentityResetHandleSDKMock.swift b/ElementX/Sources/Mocks/SDK/IdentityResetHandleSDKMock.swift index a4e4ee10e..96948e9e6 100644 --- a/ElementX/Sources/Mocks/SDK/IdentityResetHandleSDKMock.swift +++ b/ElementX/Sources/Mocks/SDK/IdentityResetHandleSDKMock.swift @@ -16,7 +16,7 @@ nonisolated extension IdentityResetHandleSDKMock { convenience init(_ configuration: Configuration) { self.init() - authTypeReturnValue = .uiaa + authTypeReturnValue = .uiaa(info: .init(session: "session_token")) resetAuthClosure = { _ in try await Task.sleep(for: .seconds(60)) } diff --git a/ElementX/Sources/Screens/EncryptionReset/EncryptionResetScreen/EncryptionResetScreenViewModel.swift b/ElementX/Sources/Screens/EncryptionReset/EncryptionResetScreen/EncryptionResetScreenViewModel.swift index f3b9d6bfc..0cf41e9cc 100644 --- a/ElementX/Sources/Screens/EncryptionReset/EncryptionResetScreen/EncryptionResetScreenViewModel.swift +++ b/ElementX/Sources/Screens/EncryptionReset/EncryptionResetScreen/EncryptionResetScreenViewModel.swift @@ -75,12 +75,12 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp identityResetHandle = handle switch handle.authType() { - case .uiaa: + case .uiaa(let info): let passwordPublisher = PassthroughSubject() passwordCancellable = passwordPublisher.sink { [weak self] password in guard let self else { return } passwordCancellable = nil - Task { await self.resetWith(password: password) } + Task { await self.resetWith(password: password, session: info.session) } } actionsSubject.send(.requestPassword(passwordPublisher: passwordPublisher)) @@ -93,7 +93,7 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp actionsSubject.send(.requestOAuthAuthorisation(url: url)) - await resetWithOAuthAuthorisation() + await resetWithOAuthAuthorisation(session: oAuthInfo.session) } case .failure(let error): MXLog.error("Failed resetting encryption with error \(error)") @@ -101,7 +101,7 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp } } - func resetWith(password: String) async { + func resetWith(password: String, session: String) async { guard let identityResetHandle else { fatalError("Requested reset flow continuation without a stored handle") } @@ -113,7 +113,7 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp } do { - try await identityResetHandle.reset(auth: .password(passwordDetails: .init(identifier: clientProxy.userID, password: password))) + try await identityResetHandle.reset(auth: .password(passwordDetails: .init(identifier: clientProxy.userID, password: password, session: session))) actionsSubject.send(.resetFinished) } catch { MXLog.error("Failed resetting encryption with error \(error)") @@ -121,13 +121,13 @@ class EncryptionResetScreenViewModel: EncryptionResetScreenViewModelType, Encryp } } - private func resetWithOAuthAuthorisation() async { + private func resetWithOAuthAuthorisation(session: String) async { guard let identityResetHandle else { fatalError("Requested reset flow continuation without a stored handle") } do { - try await identityResetHandle.reset(auth: nil) + try await identityResetHandle.reset(auth: .oAuth(session: session)) actionsSubject.send(.resetFinished) } catch { MXLog.error("Failed resetting encryption with error \(error)") diff --git a/ElementX/Sources/Screens/Settings/DeactivateAccountScreen/DeactivateAccountScreenViewModel.swift b/ElementX/Sources/Screens/Settings/DeactivateAccountScreen/DeactivateAccountScreenViewModel.swift index e301f8b9a..9bb6bcd7f 100644 --- a/ElementX/Sources/Screens/Settings/DeactivateAccountScreen/DeactivateAccountScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/DeactivateAccountScreen/DeactivateAccountScreenViewModel.swift @@ -58,15 +58,6 @@ class DeactivateAccountScreenViewModel: DeactivateAccountScreenViewModelType, De MXLog.warning("Deactivating account.") - switch await clientProxy.deactivateAccount(password: nil, eraseData: state.bindings.eraseData) { - case .success: - MXLog.info("Account deactivated (no password needed).") - actionsSubject.send(.accountDeactivated) - return - case .failure: - MXLog.info("Request failed, including password.") - } - switch await clientProxy.deactivateAccount(password: state.bindings.password, eraseData: state.bindings.eraseData) { case .success: MXLog.info("Account deactivated.") diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 030eae211..b9c789b5d 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -822,10 +822,9 @@ class ClientProxy: ClientProxyProtocol { LinkNewDeviceService(handler: client.newGrantLoginWithQrCodeHandler()) } - func deactivateAccount(password: String?, eraseData: Bool) async -> Result { + func deactivateAccount(password: String, eraseData: Bool) async -> Result { do { - try await client.deactivateAccount(authData: password.map { .password(passwordDetails: .init(identifier: userID, password: $0)) }, - eraseData: eraseData) + try await client.deactivateAccount(password: password, eraseData: eraseData) return .success(()) } catch { return .failure(.sdkError(error)) diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index c372ed036..0cdfabe0a 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -247,7 +247,7 @@ protocol ClientProxyProtocol: AnyObject { func linkNewDeviceService() -> LinkNewDeviceServiceProtocol - func deactivateAccount(password: String?, eraseData: Bool) async -> Result + func deactivateAccount(password: String, eraseData: Bool) async -> Result func logout() async diff --git a/UnitTests/Sources/DeactivateAccountScreenViewModelTests.swift b/UnitTests/Sources/DeactivateAccountScreenViewModelTests.swift index be7dcc529..bb4fa7127 100644 --- a/UnitTests/Sources/DeactivateAccountScreenViewModelTests.swift +++ b/UnitTests/Sources/DeactivateAccountScreenViewModelTests.swift @@ -37,18 +37,10 @@ struct DeactivateAccountScreenViewModelTests { mutating func validateDeactivate(erasingData shouldErase: Bool) async throws { let enteredPassword = UUID().uuidString - clientProxy.deactivateAccountPasswordEraseDataClosure = { [weak clientProxy] password, eraseData in - guard let clientProxy else { return .failure(.sdkError(ClientProxyMockError.generic)) } - - if clientProxy.deactivateAccountPasswordEraseDataCallsCount == 1 { - #expect(password == nil, "The password shouldn't be sent first time round.") - #expect(eraseData == shouldErase, "The erase parameter is unexpected.") - return .failure(.sdkError(ClientProxyMockError.generic)) - } else { - #expect(password == enteredPassword, "The password should match the user's input on the second call.") - #expect(eraseData == shouldErase, "The erase parameter is unexpected.") - return .success(()) - } + clientProxy.deactivateAccountPasswordEraseDataClosure = { password, eraseData in + #expect(password == enteredPassword, "The password should match the user's input.") + #expect(eraseData == shouldErase, "The erase parameter is unexpected.") + return .success(()) } context.eraseData = shouldErase @@ -67,7 +59,7 @@ struct DeactivateAccountScreenViewModelTests { confirmationAction() try await deferredAction.fulfill() - #expect(clientProxy.deactivateAccountPasswordEraseDataCallsCount == 2) + #expect(clientProxy.deactivateAccountPasswordEraseDataCallsCount == 1) #expect(clientProxy.deactivateAccountPasswordEraseDataReceivedArguments?.password == enteredPassword) #expect(clientProxy.deactivateAccountPasswordEraseDataReceivedArguments?.eraseData == shouldErase) }