mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 11:58:32 +00:00
Add a recovery key screen hook. (#5684)
update generateRecoveryKey to take a passphrase option Wire up AppHooks with recovery key hook Update xcodeproj Review fixups Review fixups Make the `SecureBackupRecoveryState.viewMode` extension private Bump the enterprise submodule
This commit is contained in:
@@ -700,6 +700,7 @@
|
|||||||
748F482FEF4E04D61C39AAD7 /* EmojiPickerScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */; };
|
748F482FEF4E04D61C39AAD7 /* EmojiPickerScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */; };
|
||||||
74DF5BC17DE9F51E077FD457 /* LinkNewDeviceServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */; };
|
74DF5BC17DE9F51E077FD457 /* LinkNewDeviceServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */; };
|
||||||
7501442D52A65F73DF79FFD4 /* PaginationIndicatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */; };
|
7501442D52A65F73DF79FFD4 /* PaginationIndicatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */; };
|
||||||
|
75072C529C9C363F531721F1 /* RecoveryKeyScreenHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE97AD18893E2D8120F559D /* RecoveryKeyScreenHook.swift */; };
|
||||||
754602A7B2AAD443C4228ED4 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = 4278261E147DB2DE5CFB7FC5 /* PostHog */; };
|
754602A7B2AAD443C4228ED4 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = 4278261E147DB2DE5CFB7FC5 /* PostHog */; };
|
||||||
755395927DDD6EBDDA5E217A /* SettingsFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */; };
|
755395927DDD6EBDDA5E217A /* SettingsFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */; };
|
||||||
755727E0B756430DFFEC4732 /* SessionVerificationViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF05DA24F71B455E8EFEBC3B /* SessionVerificationViewModelTests.swift */; };
|
755727E0B756430DFFEC4732 /* SessionVerificationViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF05DA24F71B455E8EFEBC3B /* SessionVerificationViewModelTests.swift */; };
|
||||||
@@ -2329,6 +2330,7 @@
|
|||||||
7ACFFE7814849BB200CE0969 /* SpaceAddRoomsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceAddRoomsScreenModels.swift; sourceTree = "<group>"; };
|
7ACFFE7814849BB200CE0969 /* SpaceAddRoomsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceAddRoomsScreenModels.swift; sourceTree = "<group>"; };
|
||||||
7AE094FCB6387D268C436161 /* SecureBackupScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModel.swift; sourceTree = "<group>"; };
|
7AE094FCB6387D268C436161 /* SecureBackupScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModel.swift; sourceTree = "<group>"; };
|
7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
7AE97AD18893E2D8120F559D /* RecoveryKeyScreenHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryKeyScreenHook.swift; sourceTree = "<group>"; };
|
||||||
7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
7B04BD3874D736127A8156B8 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
7B04BD3874D736127A8156B8 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
7B19B2BCC779ED934E0BBC2A /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = "<group>"; };
|
7B19B2BCC779ED934E0BBC2A /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = "<group>"; };
|
||||||
@@ -3748,6 +3750,7 @@
|
|||||||
8B89D6C760E8CAE29CA28FB1 /* CompoundHook.swift */,
|
8B89D6C760E8CAE29CA28FB1 /* CompoundHook.swift */,
|
||||||
0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */,
|
0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */,
|
||||||
04CAC77224E949D8E758E2E3 /* OAuthPresenterHook.swift */,
|
04CAC77224E949D8E758E2E3 /* OAuthPresenterHook.swift */,
|
||||||
|
7AE97AD18893E2D8120F559D /* RecoveryKeyScreenHook.swift */,
|
||||||
D5D186A6DB8FAC5C9D0E4D61 /* RemoteSettingsHook.swift */,
|
D5D186A6DB8FAC5C9D0E4D61 /* RemoteSettingsHook.swift */,
|
||||||
B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */,
|
B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */,
|
||||||
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */,
|
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */,
|
||||||
@@ -8748,6 +8751,7 @@
|
|||||||
ABD29E06DD1224812E750AF8 /* ReadReceiptCell.swift in Sources */,
|
ABD29E06DD1224812E750AF8 /* ReadReceiptCell.swift in Sources */,
|
||||||
1653275750CE11F5CE94DDFD /* ReadReceiptsSummaryView.swift in Sources */,
|
1653275750CE11F5CE94DDFD /* ReadReceiptsSummaryView.swift in Sources */,
|
||||||
C76892321558E75101E68ED6 /* ReadableFrameModifier.swift in Sources */,
|
C76892321558E75101E68ED6 /* ReadableFrameModifier.swift in Sources */,
|
||||||
|
75072C529C9C363F531721F1 /* RecoveryKeyScreenHook.swift in Sources */,
|
||||||
AF19D65A9C60C6B2646F3210 /* RedactedRoomTimelineItem.swift in Sources */,
|
AF19D65A9C60C6B2646F3210 /* RedactedRoomTimelineItem.swift in Sources */,
|
||||||
8CFDA5F1562479CB3A34D277 /* RedactedRoomTimelineView.swift in Sources */,
|
8CFDA5F1562479CB3A34D277 /* RedactedRoomTimelineView.swift in Sources */,
|
||||||
3A2640C52505BAB3D983A92A /* RemotePreference.swift in Sources */,
|
3A2640C52505BAB3D983A92A /* RemotePreference.swift in Sources */,
|
||||||
|
|||||||
@@ -68,6 +68,15 @@ final class AppHooks: AppHooksProtocol {
|
|||||||
func registerDeveloperOptionsScreenHook(_ hook: DeveloperOptionsScreenHookProtocol) {
|
func registerDeveloperOptionsScreenHook(_ hook: DeveloperOptionsScreenHookProtocol) {
|
||||||
_developerOptionsScreenHook.withLock { $0 = hook }
|
_developerOptionsScreenHook.withLock { $0 = hook }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let _recoveryKeyScreenHook: Mutex<RecoveryKeyScreenHookProtocol> = Mutex(DefaultRecoveryKeyScreenHook())
|
||||||
|
var recoveryKeyScreenHook: RecoveryKeyScreenHookProtocol {
|
||||||
|
_recoveryKeyScreenHook.withLock { $0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerRecoveryKeyScreenHook(_ hook: RecoveryKeyScreenHookProtocol) {
|
||||||
|
_recoveryKeyScreenHook.withLock { $0 = hook }
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private let _tracingHook: Mutex<TracingHookProtocol> = Mutex(DefaultTracingHook())
|
private let _tracingHook: Mutex<TracingHookProtocol> = Mutex(DefaultTracingHook())
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2026 Element Creations Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@MainActor protocol SecureBackupRecoveryKeyCoordinatorProtocol: CoordinatorProtocol {
|
||||||
|
var actions: AnyPublisher<SecureBackupRecoveryKeyScreenCoordinatorAction, Never> { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol RecoveryKeyScreenHookProtocol {
|
||||||
|
@MainActor func makeCoordinator(parameters: SecureBackupRecoveryKeyScreenCoordinatorParameters, homeserver: String) -> any SecureBackupRecoveryKeyCoordinatorProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DefaultRecoveryKeyScreenHook: RecoveryKeyScreenHookProtocol {
|
||||||
|
@MainActor func makeCoordinator(parameters: SecureBackupRecoveryKeyScreenCoordinatorParameters, homeserver: String) -> any SecureBackupRecoveryKeyCoordinatorProtocol {
|
||||||
|
SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -672,7 +672,8 @@ class ChatsTabFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
userIndicatorController: flowParameters.userIndicatorController,
|
userIndicatorController: flowParameters.userIndicatorController,
|
||||||
isModallyPresented: true)
|
isModallyPresented: true)
|
||||||
|
|
||||||
let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters)
|
let coordinator = flowParameters.appHooks.recoveryKeyScreenHook.makeCoordinator(parameters: parameters,
|
||||||
|
homeserver: userSession.clientProxy.homeserver)
|
||||||
coordinator.actions.sink { [weak self] action in
|
coordinator.actions.sink { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
switch action {
|
switch action {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ enum EncryptionSettingsFlowCoordinatorAction: Equatable {
|
|||||||
struct EncryptionSettingsFlowCoordinatorParameters {
|
struct EncryptionSettingsFlowCoordinatorParameters {
|
||||||
let userSession: UserSessionProtocol
|
let userSession: UserSessionProtocol
|
||||||
let appSettings: AppSettings
|
let appSettings: AppSettings
|
||||||
|
let appHooks: AppHooks
|
||||||
let userIndicatorController: UserIndicatorControllerProtocol
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
let navigationStackCoordinator: NavigationStackCoordinator
|
let navigationStackCoordinator: NavigationStackCoordinator
|
||||||
}
|
}
|
||||||
@@ -25,6 +26,7 @@ struct EncryptionSettingsFlowCoordinatorParameters {
|
|||||||
class EncryptionSettingsFlowCoordinator: FlowCoordinatorProtocol {
|
class EncryptionSettingsFlowCoordinator: FlowCoordinatorProtocol {
|
||||||
private let userSession: UserSessionProtocol
|
private let userSession: UserSessionProtocol
|
||||||
private let appSettings: AppSettings
|
private let appSettings: AppSettings
|
||||||
|
private let appHooks: AppHooks
|
||||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
private let navigationStackCoordinator: NavigationStackCoordinator
|
private let navigationStackCoordinator: NavigationStackCoordinator
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ class EncryptionSettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
init(parameters: EncryptionSettingsFlowCoordinatorParameters) {
|
init(parameters: EncryptionSettingsFlowCoordinatorParameters) {
|
||||||
userSession = parameters.userSession
|
userSession = parameters.userSession
|
||||||
appSettings = parameters.appSettings
|
appSettings = parameters.appSettings
|
||||||
|
appHooks = parameters.appHooks
|
||||||
userIndicatorController = parameters.userIndicatorController
|
userIndicatorController = parameters.userIndicatorController
|
||||||
navigationStackCoordinator = parameters.navigationStackCoordinator
|
navigationStackCoordinator = parameters.navigationStackCoordinator
|
||||||
|
|
||||||
@@ -158,9 +161,11 @@ class EncryptionSettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
private func presentRecoveryKeyScreen() {
|
private func presentRecoveryKeyScreen() {
|
||||||
let sheetNavigationStackCoordinator = NavigationStackCoordinator()
|
let sheetNavigationStackCoordinator = NavigationStackCoordinator()
|
||||||
let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: .init(secureBackupController: userSession.clientProxy.secureBackupController,
|
let parameters = SecureBackupRecoveryKeyScreenCoordinatorParameters(secureBackupController: userSession.clientProxy.secureBackupController,
|
||||||
userIndicatorController: userIndicatorController,
|
userIndicatorController: userIndicatorController,
|
||||||
isModallyPresented: true))
|
isModallyPresented: true)
|
||||||
|
let coordinator = appHooks.recoveryKeyScreenHook.makeCoordinator(parameters: parameters,
|
||||||
|
homeserver: userSession.clientProxy.homeserver)
|
||||||
|
|
||||||
coordinator.actions.sink { [weak self] action in
|
coordinator.actions.sink { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -302,7 +302,8 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
userIndicatorController: userIndicatorController,
|
userIndicatorController: userIndicatorController,
|
||||||
isModallyPresented: false)
|
isModallyPresented: false)
|
||||||
|
|
||||||
let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters)
|
let coordinator = appHooks.recoveryKeyScreenHook.makeCoordinator(parameters: parameters,
|
||||||
|
homeserver: userSession.clientProxy.homeserver)
|
||||||
|
|
||||||
coordinator.actions
|
coordinator.actions
|
||||||
.sink { action in
|
.sink { action in
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
private func startEncryptionSettingsFlow(animated: Bool) {
|
private func startEncryptionSettingsFlow(animated: Bool) {
|
||||||
let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: flowParameters.userSession,
|
let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: flowParameters.userSession,
|
||||||
appSettings: flowParameters.appSettings,
|
appSettings: flowParameters.appSettings,
|
||||||
|
appHooks: flowParameters.appHooks,
|
||||||
userIndicatorController: flowParameters.userIndicatorController,
|
userIndicatorController: flowParameters.userIndicatorController,
|
||||||
navigationStackCoordinator: navigationStackCoordinator))
|
navigationStackCoordinator: navigationStackCoordinator))
|
||||||
coordinator.actionsPublisher.sink { [weak self] action in
|
coordinator.actionsPublisher.sink { [weak self] action in
|
||||||
|
|||||||
@@ -10963,30 +10963,44 @@ class SecureBackupControllerMock: SecureBackupControllerProtocol, @unchecked Sen
|
|||||||
}
|
}
|
||||||
//MARK: - generateRecoveryKey
|
//MARK: - generateRecoveryKey
|
||||||
|
|
||||||
private let generateRecoveryKeyCallsCountLock = NSLock()
|
private let generateRecoveryKeyWithPassphraseCallsCountLock = NSLock()
|
||||||
private var generateRecoveryKeyUnderlyingCallsCount = 0
|
private var generateRecoveryKeyWithPassphraseUnderlyingCallsCount = 0
|
||||||
var generateRecoveryKeyCallsCount: Int {
|
var generateRecoveryKeyWithPassphraseCallsCount: Int {
|
||||||
get { generateRecoveryKeyCallsCountLock.withLock { generateRecoveryKeyUnderlyingCallsCount } }
|
get { generateRecoveryKeyWithPassphraseCallsCountLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingCallsCount } }
|
||||||
set { generateRecoveryKeyCallsCountLock.withLock { generateRecoveryKeyUnderlyingCallsCount = newValue } }
|
set { generateRecoveryKeyWithPassphraseCallsCountLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingCallsCount = newValue } }
|
||||||
}
|
}
|
||||||
var generateRecoveryKeyCalled: Bool {
|
var generateRecoveryKeyWithPassphraseCalled: Bool {
|
||||||
return generateRecoveryKeyCallsCount > 0
|
return generateRecoveryKeyWithPassphraseCallsCount > 0
|
||||||
|
}
|
||||||
|
private let generateRecoveryKeyWithPassphraseReceivedPassphraseLock = NSLock()
|
||||||
|
private var generateRecoveryKeyWithPassphraseUnderlyingReceivedPassphrase: String?
|
||||||
|
var generateRecoveryKeyWithPassphraseReceivedPassphrase: String? {
|
||||||
|
get { generateRecoveryKeyWithPassphraseReceivedPassphraseLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReceivedPassphrase } }
|
||||||
|
set { generateRecoveryKeyWithPassphraseReceivedPassphraseLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReceivedPassphrase = newValue } }
|
||||||
|
}
|
||||||
|
private let generateRecoveryKeyWithPassphraseReceivedInvocationsLock = NSLock()
|
||||||
|
private var generateRecoveryKeyWithPassphraseUnderlyingReceivedInvocations: [String?] = []
|
||||||
|
var generateRecoveryKeyWithPassphraseReceivedInvocations: [String?] {
|
||||||
|
get { generateRecoveryKeyWithPassphraseReceivedInvocationsLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReceivedInvocations } }
|
||||||
|
set { generateRecoveryKeyWithPassphraseReceivedInvocationsLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReceivedInvocations = newValue } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private let generateRecoveryKeyReturnValueLock = NSLock()
|
private let generateRecoveryKeyWithPassphraseReturnValueLock = NSLock()
|
||||||
private var generateRecoveryKeyUnderlyingReturnValue: Result<String, SecureBackupControllerError>!
|
private var generateRecoveryKeyWithPassphraseUnderlyingReturnValue: Result<String, SecureBackupControllerError>!
|
||||||
var generateRecoveryKeyReturnValue: Result<String, SecureBackupControllerError>! {
|
var generateRecoveryKeyWithPassphraseReturnValue: Result<String, SecureBackupControllerError>! {
|
||||||
get { generateRecoveryKeyReturnValueLock.withLock { generateRecoveryKeyUnderlyingReturnValue } }
|
get { generateRecoveryKeyWithPassphraseReturnValueLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReturnValue } }
|
||||||
set { generateRecoveryKeyReturnValueLock.withLock { generateRecoveryKeyUnderlyingReturnValue = newValue } }
|
set { generateRecoveryKeyWithPassphraseReturnValueLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReturnValue = newValue } }
|
||||||
}
|
}
|
||||||
var generateRecoveryKeyClosure: (() async -> Result<String, SecureBackupControllerError>)?
|
var generateRecoveryKeyWithPassphraseClosure: ((String?) async -> Result<String, SecureBackupControllerError>)?
|
||||||
|
|
||||||
func generateRecoveryKey() async -> Result<String, SecureBackupControllerError> {
|
func generateRecoveryKey(withPassphrase passphrase: String?) async -> Result<String, SecureBackupControllerError> {
|
||||||
generateRecoveryKeyCallsCountLock.withLock { generateRecoveryKeyUnderlyingCallsCount += 1 }
|
generateRecoveryKeyWithPassphraseCallsCountLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingCallsCount += 1 }
|
||||||
if let generateRecoveryKeyClosure = generateRecoveryKeyClosure {
|
generateRecoveryKeyWithPassphraseReceivedPassphrase = passphrase
|
||||||
return await generateRecoveryKeyClosure()
|
generateRecoveryKeyWithPassphraseReceivedInvocationsLock.withLock { generateRecoveryKeyWithPassphraseUnderlyingReceivedInvocations.append(passphrase) }
|
||||||
|
if let generateRecoveryKeyWithPassphraseClosure = generateRecoveryKeyWithPassphraseClosure {
|
||||||
|
return await generateRecoveryKeyWithPassphraseClosure(passphrase)
|
||||||
} else {
|
} else {
|
||||||
return generateRecoveryKeyReturnValue
|
return generateRecoveryKeyWithPassphraseReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//MARK: - confirmRecoveryKey
|
//MARK: - confirmRecoveryKey
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ extension SecureBackupControllerMock {
|
|||||||
return .success(())
|
return .success(())
|
||||||
}
|
}
|
||||||
|
|
||||||
generateRecoveryKeyClosure = {
|
generateRecoveryKeyWithPassphraseClosure = { _ in
|
||||||
recoveryStateSubject.send(.enabled)
|
recoveryStateSubject.send(.enabled)
|
||||||
return .success("a1B2 C3d4 E5F6 g7H8 i9J0 K1l2 M3n4 O5p6 Q7R8 s9T0 U1v2 W3X4")
|
return .success("a1B2 C3d4 E5F6 g7H8 i9J0 K1l2 M3n4 O5p6 Q7R8 s9T0 U1v2 W3X4")
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ enum SecureBackupRecoveryKeyScreenCoordinatorAction {
|
|||||||
case complete
|
case complete
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SecureBackupRecoveryKeyScreenCoordinator: CoordinatorProtocol {
|
final class SecureBackupRecoveryKeyScreenCoordinator: SecureBackupRecoveryKeyCoordinatorProtocol {
|
||||||
private let parameters: SecureBackupRecoveryKeyScreenCoordinatorParameters
|
private let parameters: SecureBackupRecoveryKeyScreenCoordinatorParameters
|
||||||
private var viewModel: SecureBackupRecoveryKeyScreenViewModelProtocol
|
private var viewModel: SecureBackupRecoveryKeyScreenViewModelProtocol
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -41,7 +41,7 @@ class SecureBackupRecoveryKeyScreenViewModel: SecureBackupRecoveryKeyScreenViewM
|
|||||||
state.isGeneratingKey = true
|
state.isGeneratingKey = true
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
switch await secureBackupController.generateRecoveryKey() {
|
switch await secureBackupController.generateRecoveryKey(withPassphrase: nil) {
|
||||||
case .success(let key):
|
case .success(let key):
|
||||||
state.recoveryKey = key
|
state.recoveryKey = key
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
@@ -101,7 +101,7 @@ class SecureBackupRecoveryKeyScreenViewModel: SecureBackupRecoveryKeyScreenViewM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SecureBackupRecoveryState {
|
private extension SecureBackupRecoveryState {
|
||||||
var viewMode: SecureBackupRecoveryKeyScreenViewMode {
|
var viewMode: SecureBackupRecoveryKeyScreenViewMode {
|
||||||
switch self {
|
switch self {
|
||||||
case .disabled:
|
case .disabled:
|
||||||
|
|||||||
+2
-2
@@ -278,9 +278,9 @@ struct SecureBackupRecoveryKeyScreen_Previews: PreviewProvider, TestablePreview
|
|||||||
backupController.recoveryState = CurrentValueSubject<SecureBackupRecoveryState, Never>(recoveryState).asCurrentValuePublisher()
|
backupController.recoveryState = CurrentValueSubject<SecureBackupRecoveryState, Never>(recoveryState).asCurrentValuePublisher()
|
||||||
|
|
||||||
if let key {
|
if let key {
|
||||||
backupController.generateRecoveryKeyReturnValue = .success(key)
|
backupController.generateRecoveryKeyWithPassphraseReturnValue = .success(key)
|
||||||
} else {
|
} else {
|
||||||
backupController.generateRecoveryKeyClosure = {
|
backupController.generateRecoveryKeyWithPassphraseClosure = { _ in
|
||||||
try? await Task.sleep(for: .seconds(1000))
|
try? await Task.sleep(for: .seconds(1000))
|
||||||
return .success("youshouldntseeme")
|
return .success("youshouldntseeme")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,19 +110,18 @@ class SecureBackupController: SecureBackupControllerProtocol {
|
|||||||
return .success(())
|
return .success(())
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateRecoveryKey() async -> Result<String, SecureBackupControllerError> {
|
func generateRecoveryKey(withPassphrase passphrase: String?) async -> Result<String, SecureBackupControllerError> {
|
||||||
do {
|
do {
|
||||||
guard recoveryState.value == .disabled else {
|
if recoveryState.value == .disabled {
|
||||||
|
MXLog.info("Enabling recovery")
|
||||||
|
} else {
|
||||||
MXLog.info("Resetting recovery key")
|
MXLog.info("Resetting recovery key")
|
||||||
|
|
||||||
let key = try await encryption.resetRecoveryKey()
|
|
||||||
return .success(key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MXLog.info("Enabling recovery")
|
|
||||||
|
|
||||||
var keyUploadErrored = false
|
var keyUploadErrored = false
|
||||||
let recoveryKey = try await encryption.enableRecovery(waitForBackupsToUpload: false, passphrase: nil, progressListener: SDKListener { [weak self] state in
|
// Note: `enableRecovery` also handles the reset case (equivalent to `resetRecoveryKey`).
|
||||||
|
// Despite the name, it is the correct call for both initial setup and key rotation.
|
||||||
|
let recoveryKey = try await encryption.enableRecovery(waitForBackupsToUpload: false, passphrase: passphrase, progressListener: SDKListener { [weak self] state in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ protocol SecureBackupControllerProtocol {
|
|||||||
func enable() async -> Result<Void, SecureBackupControllerError>
|
func enable() async -> Result<Void, SecureBackupControllerError>
|
||||||
func disable() async -> Result<Void, SecureBackupControllerError>
|
func disable() async -> Result<Void, SecureBackupControllerError>
|
||||||
|
|
||||||
func generateRecoveryKey() async -> Result<String, SecureBackupControllerError>
|
func generateRecoveryKey(withPassphrase passphrase: String?) async -> Result<String, SecureBackupControllerError>
|
||||||
func confirmRecoveryKey(_ key: String) async -> Result<Void, SecureBackupControllerError>
|
func confirmRecoveryKey(_ key: String) async -> Result<Void, SecureBackupControllerError>
|
||||||
|
|
||||||
func waitForKeyBackupUpload(uploadStateSubject: CurrentValueSubject<SecureBackupSteadyState, Never>) async -> Result<Void, SecureBackupControllerError>
|
func waitForKeyBackupUpload(uploadStateSubject: CurrentValueSubject<SecureBackupSteadyState, Never>) async -> Result<Void, SecureBackupControllerError>
|
||||||
|
|||||||
@@ -748,6 +748,7 @@ class MockScreen: Identifiable {
|
|||||||
|
|
||||||
let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: userSession,
|
let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: userSession,
|
||||||
appSettings: appSettings,
|
appSettings: appSettings,
|
||||||
|
appHooks: AppHooks(),
|
||||||
userIndicatorController: UserIndicatorControllerMock(),
|
userIndicatorController: UserIndicatorControllerMock(),
|
||||||
navigationStackCoordinator: navigationStackCoordinator))
|
navigationStackCoordinator: navigationStackCoordinator))
|
||||||
retainedState.append(coordinator)
|
retainedState.append(coordinator)
|
||||||
|
|||||||
+1
-1
Submodule Enterprise updated: ee4aca0bd5...eaa8ac5101
Reference in New Issue
Block a user