diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index a0a309d47..5beb441be 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -567,7 +567,7 @@ Tap the + to start adding people."; "settings_key_backup_info" = "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages."; "settings_key_backup_info_checking" = "Checking…"; "settings_key_backup_info_none" = "Your keys are not being backed up from this session."; -"settings_key_backup_info_signout_warning" = "Connect this session to key backup before signing out to avoid losing any keys that may only be on this device."; +"settings_key_backup_info_signout_warning" = "Back up your keys before signing out to avoid losing them."; "settings_key_backup_info_version" = "Key Backup Version: %@"; "settings_key_backup_info_algorithm" = "Algorithm: %@"; "settings_key_backup_info_valid" = "This session is backing up your keys."; @@ -1094,6 +1094,9 @@ Tap the + to start adding people."; "key_backup_setup_success_from_recovery_key_make_copy_action" = "Make a Copy"; "key_backup_setup_success_from_recovery_key_made_copy_action" = "I've made a copy"; +// Success from secure backup +"key_backup_setup_success_from_secure_backup_info" = "Your keys are being backed up."; + // MARK: Key backup recover "key_backup_recover_title" = "Secure Messages"; diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index d592e4f76..c66d40f6a 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -97,6 +97,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromRecoveryKeyViewController.self) } + internal enum KeyBackupSetupSuccessFromSecureBackupViewController: StoryboardType { + internal static let storyboardName = "KeyBackupSetupSuccessFromSecureBackupViewController" + + internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromSecureBackupViewController.self) + } internal enum KeyVerificationDataLoadingViewController: StoryboardType { internal static let storyboardName = "KeyVerificationDataLoadingViewController" diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index c128b61b5..7d6a543c2 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1806,6 +1806,10 @@ internal enum VectorL10n { internal static var keyBackupSetupSuccessFromRecoveryKeyRecoveryKeyTitle: String { return VectorL10n.tr("Vector", "key_backup_setup_success_from_recovery_key_recovery_key_title") } + /// Your keys are being backed up. + internal static var keyBackupSetupSuccessFromSecureBackupInfo: String { + return VectorL10n.tr("Vector", "key_backup_setup_success_from_secure_backup_info") + } /// Success! internal static var keyBackupSetupSuccessTitle: String { return VectorL10n.tr("Vector", "key_backup_setup_success_title") @@ -4262,7 +4266,7 @@ internal enum VectorL10n { internal static var settingsKeyBackupInfoProgressDone: String { return VectorL10n.tr("Vector", "settings_key_backup_info_progress_done") } - /// Connect this session to key backup before signing out to avoid losing any keys that may only be on this device. + /// Back up your keys before signing out to avoid losing them. internal static var settingsKeyBackupInfoSignoutWarning: String { return VectorL10n.tr("Vector", "settings_key_backup_info_signout_warning") } diff --git a/Riot/Modules/KeyBackup/Setup/KeyBackupSetupCoordinator.swift b/Riot/Modules/KeyBackup/Setup/KeyBackupSetupCoordinator.swift index e5dd5561b..b1b96be83 100644 --- a/Riot/Modules/KeyBackup/Setup/KeyBackupSetupCoordinator.swift +++ b/Riot/Modules/KeyBackup/Setup/KeyBackupSetupCoordinator.swift @@ -44,11 +44,11 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType { // MARK: - Public methods func start() { - - // Set key backup setup intro as root controller - let keyBackupSetupIntroViewController = self.createSetupIntroViewController() - keyBackupSetupIntroViewController.delegate = self - self.navigationRouter.setRootModule(keyBackupSetupIntroViewController) + if self.session.crypto.recoveryService.hasRecovery() { + showUnlockSecureBackup() + } else { + showSetupIntro() + } } func toPresentable() -> UIViewController { @@ -57,6 +57,13 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType { // MARK: - Private methods + private func showSetupIntro() { + // Set key backup setup intro as root controller + let keyBackupSetupIntroViewController = self.createSetupIntroViewController() + keyBackupSetupIntroViewController.delegate = self + self.navigationRouter.setRootModule(keyBackupSetupIntroViewController) + } + private func createSetupIntroViewController() -> KeyBackupSetupIntroViewController { let backupState = self.session.crypto.backup?.state ?? MXKeyBackupStateUnknown @@ -80,6 +87,17 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType { return KeyBackupSetupIntroViewController.instantiate(isABackupAlreadyExists: isABackupAlreadyExists, encryptionKeysExportPresenter: encryptionKeysExportPresenter) } + private func showUnlockSecureBackup() { + let recoveryGoal: SecretsRecoveryGoal = .unlockSecureBackup { (privateKey, completion) in + self.createKeyBackupUsingSecureBackup(privateKey: privateKey, completion: completion) + } + + let coordinator = SecretsRecoveryCoordinator(session: self.session, recoveryMode: .passphraseOrKey, recoveryGoal: recoveryGoal, navigationRouter: self.navigationRouter) + coordinator.delegate = self + coordinator.start() + self.add(childCoordinator: coordinator) + } + private func showSetupPassphrase(animated: Bool) { let keyBackupSetupPassphraseCoordinator = KeyBackupSetupPassphraseCoordinator(session: self.session) keyBackupSetupPassphraseCoordinator.delegate = self @@ -104,6 +122,34 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType { viewController.delegate = self self.navigationRouter.push(viewController, animated: animated, popCompletion: nil) } + + private func showSetupWithSecureBackupSuccess(animated: Bool) { + + let viewController = KeyBackupSetupSuccessFromSecureBackupViewController.instantiate() + viewController.delegate = self + self.navigationRouter.push(viewController, animated: animated, popCompletion: nil) + } + + private func createKeyBackupUsingSecureBackup(privateKey: Data, completion: @escaping (Result) -> Void) { + guard let keyBackup = session.crypto.backup, let recoveryService = session.crypto.recoveryService else { + return + } + + keyBackup.prepareKeyBackupVersion(withPassword: nil, success: { megolmBackupCreationInfo in + keyBackup.createKeyBackupVersion(megolmBackupCreationInfo, success: { _ in + recoveryService.updateRecovery(forSecrets: [MXSecretId.keyBackup.takeUnretainedValue() as String], withPrivateKey: privateKey) { + completion(.success(Void())) + } failure: { error in + completion(.failure(error)) + } + + }, failure: { error in + completion(.failure(error)) + }) + }, failure: { error in + completion(.failure(error)) + }) + } } // MARK: - KeyBackupSetupIntroViewControllerDelegate @@ -133,6 +179,17 @@ extension KeyBackupSetupCoordinator: KeyBackupSetupPassphraseCoordinatorDelegate } } +// MARK: - SecretsRecoveryCoordinatorDelegate +extension KeyBackupSetupCoordinator: SecretsRecoveryCoordinatorDelegate { + func secretsRecoveryCoordinatorDidRecover(_ coordinator: SecretsRecoveryCoordinatorType) { + self.showSetupWithSecureBackupSuccess(animated: true) + } + + func secretsRecoveryCoordinatorDidCancel(_ coordinator: SecretsRecoveryCoordinatorType) { + self.delegate?.keyBackupSetupCoordinatorDidCancel(self) + } +} + // MARK: - KeyBackupSetupSuccessFromPassphraseViewControllerDelegate extension KeyBackupSetupCoordinator: KeyBackupSetupSuccessFromPassphraseViewControllerDelegate { func keyBackupSetupSuccessFromPassphraseViewControllerDidTapDoneAction(_ viewController: KeyBackupSetupSuccessFromPassphraseViewController) { @@ -146,3 +203,10 @@ extension KeyBackupSetupCoordinator: KeyBackupSetupSuccessFromRecoveryKeyViewCon self.delegate?.keyBackupSetupCoordinatorDidSetupRecoveryKey(self) } } + +// MARK: - KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate +extension KeyBackupSetupCoordinator: KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate { + func keyBackupSetupSuccessFromSecureBackupViewControllerDidTapDoneAction(_ viewController: KeyBackupSetupSuccessFromSecureBackupViewController) { + self.delegate?.keyBackupSetupCoordinatorDidSetupRecoveryKey(self) + } +} diff --git a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.storyboard b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.storyboard new file mode 100644 index 000000000..1020489c2 --- /dev/null +++ b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.storyboard @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.swift b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.swift new file mode 100644 index 000000000..c369cb5e9 --- /dev/null +++ b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.swift @@ -0,0 +1,120 @@ +/* + Copyright 2021 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +protocol KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate: class { + func keyBackupSetupSuccessFromSecureBackupViewControllerDidTapDoneAction(_ viewController: KeyBackupSetupSuccessFromSecureBackupViewController) +} + +final class KeyBackupSetupSuccessFromSecureBackupViewController: UIViewController { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var keyBackupLogoImageView: UIImageView! + @IBOutlet private weak var titleLabel: UILabel! + @IBOutlet private weak var informationLabel: UILabel! + + @IBOutlet private weak var doneButtonBackgroundView: UIView! + @IBOutlet private weak var doneButton: UIButton! + + // MARK: Private + + private var theme: Theme! + + // MARK: Public + + weak var delegate: KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate? + + // MARK: - Setup + + class func instantiate() -> KeyBackupSetupSuccessFromSecureBackupViewController { + let viewController = StoryboardScene.KeyBackupSetupSuccessFromSecureBackupViewController.initialScene.instantiate() + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = VectorL10n.keyBackupSetupTitle + + self.setupViews() + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // Hide back button + self.navigationItem.setHidesBackButton(true, animated: animated) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func setupViews() { + + let keybackupLogoImage = Asset.Images.keyBackupLogo.image.withRenderingMode(.alwaysTemplate) + self.keyBackupLogoImageView.image = keybackupLogoImage + + self.titleLabel.text = VectorL10n.keyBackupSetupSuccessTitle + self.informationLabel.text = VectorL10n.keyBackupSetupSuccessFromSecureBackupInfo + + self.doneButton.setTitle(VectorL10n.keyBackupSetupSuccessFromPassphraseDoneAction, for: .normal) + } + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + self.keyBackupLogoImageView.tintColor = theme.textPrimaryColor + self.titleLabel.textColor = theme.textPrimaryColor + self.informationLabel.textColor = theme.textPrimaryColor + + self.doneButtonBackgroundView.backgroundColor = theme.backgroundColor + theme.applyStyle(onButton: self.doneButton) + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + // MARK: - Actions + + @IBAction private func doneButtonAction(_ sender: Any) { + self.delegate?.keyBackupSetupSuccessFromSecureBackupViewControllerDidTapDoneAction(self) + } +} diff --git a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift index a302825dc..4eb879b1c 100644 --- a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift +++ b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift @@ -23,7 +23,7 @@ import UIKit func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, buttonCellForRow: Int) -> MXKTableViewCellWithButton - func settingsSecureBackupTableViewSectionShowKeyBackupSetup(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection) + func settingsSecureBackupTableViewSectionShowKeyBackupCreate(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection) func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion) func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showKeyBackupDeleteConfirm keyBackupVersion: MXKeyBackupVersion) @@ -33,7 +33,7 @@ import UIKit private enum BackupRows { case info(text: String) - case setupAction + case createKeyBackupAction case restoreFromKeyBackupAction(keyBackupVersion: MXKeyBackupVersion, title: String) case deleteKeyBackupAction(keyBackupVersion: MXKeyBackupVersion) } @@ -89,8 +89,8 @@ private enum BackupRows { let infoCell: MXKTableViewCellWithTextView = delegate.settingsSecureBackupTableViewSection(self, textCellForRow: row) infoCell.mxkTextView.text = infoText cell = infoCell - case .setupAction: - cell = self.buttonCellForSetup(atRow: row) + case .createKeyBackupAction: + cell = self.buttonCellForCreateKeyBackup(atRow: row) case .restoreFromKeyBackupAction(keyBackupVersion: let keyBackupVersion, let title): cell = self.buttonCellForRestoreFromKeyBackup(keyBackupVersion: keyBackupVersion, title: title, atRow: row) case .deleteKeyBackupAction(keyBackupVersion: let keyBackupVersion): @@ -128,16 +128,15 @@ private enum BackupRows { case .noBackup: -// let noBackup = VectorL10n.settingsSecureBackupInfoNone -// let info = VectorL10n.settingsSecureBackupInfo -// let signoutWarning = VectorL10n.settingsSecureBackupInfoSignoutWarning -// let strings = [noBackup, "", info, "", signoutWarning] -// let backupInfoText = strings.joined(separator: "\n") - let backupInfoText = "TODO" + let noBackup = VectorL10n.settingsKeyBackupInfoNone + let signoutWarning = VectorL10n.settingsKeyBackupInfoSignoutWarning + let strings = [noBackup, "", signoutWarning] + let backupInfoText = strings.joined(separator: "\n") backupRows = [ + .info(text: VectorL10n.securitySettingsSecureBackupDescription), .info(text: backupInfoText), - .setupAction + .createKeyBackupAction ] case .backup(let keyBackupVersion, let keyBackupVersionTrust), @@ -247,7 +246,7 @@ private enum BackupRows { // MARK: - Button cells - private func buttonCellForSetup(atRow row: Int) -> UITableViewCell { + private func buttonCellForCreateKeyBackup(atRow row: Int) -> UITableViewCell { guard let delegate = self.delegate else { return UITableViewCell() @@ -260,7 +259,7 @@ private enum BackupRows { cell.mxkButton.setTitle(btnTitle, for: .highlighted) cell.mxkButton.vc_addAction { - self.viewModel.process(viewAction: .setup) + self.viewModel.process(viewAction: .createKeyBackup) } return cell @@ -319,8 +318,8 @@ extension SettingsSecureBackupTableViewSection: SettingsSecureBackupViewModelVie } } - func settingsSecureBackupViewModelShowKeyBackupSetup(_ viewModel: SettingsSecureBackupViewModelType) { - self.delegate?.settingsSecureBackupTableViewSectionShowKeyBackupSetup(self) + func settingsSecureBackupViewModelShowKeyBackupCreate(_ viewModel: SettingsSecureBackupViewModelType) { + self.delegate?.settingsSecureBackupTableViewSectionShowKeyBackupCreate(self) } func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion) { diff --git a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewAction.swift b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewAction.swift index cd8379542..8187c7fd1 100644 --- a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewAction.swift +++ b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewAction.swift @@ -18,7 +18,7 @@ import UIKit enum SettingsSecureBackupViewAction { case load - case setup + case createKeyBackup case restoreFromKeyBackup(MXKeyBackupVersion) case confirmDeleteKeyBackup(MXKeyBackupVersion) case deleteKeyBackup(MXKeyBackupVersion) diff --git a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModel.swift b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModel.swift index c716d70d4..e4151663f 100644 --- a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModel.swift +++ b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModel.swift @@ -46,8 +46,8 @@ final class SettingsSecureBackupViewModel: SettingsSecureBackupViewModelType { case .load: viewDelegate.settingsSecureBackupViewModel(self, didUpdateViewState: .checkingBackup) self.checkKeyBackupState() - case .setup: - viewDelegate.settingsSecureBackupViewModelShowKeyBackupSetup(self) + case .createKeyBackup: + viewDelegate.settingsSecureBackupViewModelShowKeyBackupCreate(self) case .restoreFromKeyBackup(let keyBackupVersion): viewDelegate.settingsSecureBackupViewModel(self, showKeyBackupRecover: keyBackupVersion) case .confirmDeleteKeyBackup(let keyBackupVersion): diff --git a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModelType.swift b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModelType.swift index eac9a14d6..cb3df7ae5 100644 --- a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModelType.swift +++ b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupViewModelType.swift @@ -20,7 +20,7 @@ protocol SettingsSecureBackupViewModelViewDelegate: class { func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, didUpdateViewState viewState: SettingsSecureBackupViewState) func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, didUpdateNetworkRequestViewState networkRequestViewSate: SettingsSecureBackupNetworkRequestViewState) - func settingsSecureBackupViewModelShowKeyBackupSetup(_ viewModel: SettingsSecureBackupViewModelType) + func settingsSecureBackupViewModelShowKeyBackupCreate(_ viewModel: SettingsSecureBackupViewModelType) func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion) func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupDeleteConfirm keyBackupVersion: MXKeyBackupVersion) } diff --git a/Riot/Modules/Settings/Security/SecurityViewController.m b/Riot/Modules/Settings/Security/SecurityViewController.m index ae7ac4dd1..d1271a6e2 100644 --- a/Riot/Modules/Settings/Security/SecurityViewController.m +++ b/Riot/Modules/Settings/Security/SecurityViewController.m @@ -1720,7 +1720,7 @@ TableViewSectionsDelegate> return cell; } -- (void)settingsSecureBackupTableViewSectionShowKeyBackupSetup:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection +- (void)settingsSecureBackupTableViewSectionShowKeyBackupCreate:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection { [self showKeyBackupSetupFromSignOutFlow:NO]; }