mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 07:42:40 +00:00
Merge pull request #3373 from vector-im/riot_3361
Secure backup: Create and delete key backup with 4S
This commit is contained in:
commit
e277a9733c
6 changed files with 145 additions and 7 deletions
|
@ -934,6 +934,12 @@
|
|||
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Use a Security Passphrase";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Enter a secret phrase only you know, and generate a key for backup.";
|
||||
|
||||
"secure_key_backup_setup_existing_backup_error_title" = "A backup for messages already exists";
|
||||
"secure_key_backup_setup_existing_backup_error_info" = "Unlock it to reuse it in the secure backup or delete it to create a new messages backup in the secure backup.";
|
||||
"secure_key_backup_setup_existing_backup_error_unlock_it" = "Unlock it";
|
||||
"secure_key_backup_setup_existing_backup_error_delete_it" = "Delete it";
|
||||
|
||||
|
||||
// Cancel
|
||||
|
||||
"secure_key_backup_setup_cancel_alert_title" = "Are your sure?";
|
||||
|
|
|
@ -3062,6 +3062,22 @@ internal enum VectorL10n {
|
|||
internal static var secureKeyBackupSetupCancelAlertTitle: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_cancel_alert_title")
|
||||
}
|
||||
/// Delete it
|
||||
internal static var secureKeyBackupSetupExistingBackupErrorDeleteIt: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_existing_backup_error_delete_it")
|
||||
}
|
||||
/// Unlock it to reuse it in the secure backup or delete it to create a new messages backup in the secure backup.
|
||||
internal static var secureKeyBackupSetupExistingBackupErrorInfo: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_existing_backup_error_info")
|
||||
}
|
||||
/// A backup for messages already exists
|
||||
internal static var secureKeyBackupSetupExistingBackupErrorTitle: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_existing_backup_error_title")
|
||||
}
|
||||
/// Unlock it
|
||||
internal static var secureKeyBackupSetupExistingBackupErrorUnlockIt: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_existing_backup_error_unlock_it")
|
||||
}
|
||||
/// Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.
|
||||
internal static var secureKeyBackupSetupIntroInfo: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_info")
|
||||
|
|
|
@ -59,7 +59,7 @@ final class SecretsSetupRecoveryKeyViewModel: SecretsSetupRecoveryKeyViewModelTy
|
|||
private func createSecureKey() {
|
||||
self.update(viewState: .loading)
|
||||
|
||||
self.recoveryService.createRecovery(forSecrets: nil, withPassphrase: self.passphrase, success: { secretStorageKeyCreationInfo in
|
||||
self.recoveryService.createRecovery(forSecrets: nil, withPassphrase: self.passphrase, createServicesBackups: true, success: { secretStorageKeyCreationInfo in
|
||||
self.update(viewState: .loaded(secretStorageKeyCreationInfo.recoveryKey))
|
||||
}, failure: { error in
|
||||
self.update(viewState: .error(error))
|
||||
|
|
|
@ -19,7 +19,8 @@ import UIKit
|
|||
protocol SecureBackupSetupIntroViewControllerDelegate: class {
|
||||
func secureBackupSetupIntroViewControllerDidTapUseKey(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController)
|
||||
func secureBackupSetupIntroViewControllerDidTapUsePassphrase(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController)
|
||||
func secureBackupSetupIntroViewControllerDidCancel(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController)
|
||||
func secureBackupSetupIntroViewControllerDidCancel(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController, showSkipAlert: Bool)
|
||||
func secureBackupSetupIntroViewControllerDidTapConnectToKeyBackup(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController)
|
||||
}
|
||||
|
||||
@objcMembers
|
||||
|
@ -39,10 +40,17 @@ final class SecureBackupSetupIntroViewController: UIViewController {
|
|||
|
||||
private var theme: Theme!
|
||||
|
||||
private var activityIndicatorPresenter: ActivityIndicatorPresenter!
|
||||
private var errorPresenter: MXKErrorPresentation!
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var delegate: SecureBackupSetupIntroViewControllerDelegate?
|
||||
|
||||
// This is evil
|
||||
// TODO: refactor it
|
||||
weak var keyBackup: MXKeyBackup?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
class func instantiate() -> SecureBackupSetupIntroViewController {
|
||||
|
@ -61,10 +69,18 @@ final class SecureBackupSetupIntroViewController: UIViewController {
|
|||
self.vc_removeBackTitle()
|
||||
|
||||
self.setupViews()
|
||||
self.activityIndicatorPresenter = ActivityIndicatorPresenter()
|
||||
self.errorPresenter = MXKErrorAlertPresentation()
|
||||
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
self.update(theme: self.theme)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
self.checkKeyBackup()
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
@ -76,7 +92,7 @@ final class SecureBackupSetupIntroViewController: UIViewController {
|
|||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.delegate?.secureBackupSetupIntroViewControllerDidCancel(self)
|
||||
self.delegate?.secureBackupSetupIntroViewControllerDidCancel(self, showSkipAlert: true)
|
||||
}
|
||||
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
|
||||
|
||||
|
@ -107,6 +123,19 @@ final class SecureBackupSetupIntroViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
private func renderLoading() {
|
||||
self.activityIndicatorPresenter.presentActivityIndicator(on: self.view, animated: true)
|
||||
}
|
||||
|
||||
private func renderLoaded() {
|
||||
self.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
}
|
||||
|
||||
private func render(error: Error) {
|
||||
self.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
|
||||
}
|
||||
|
||||
private func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
|
@ -130,4 +159,59 @@ final class SecureBackupSetupIntroViewController: UIViewController {
|
|||
@objc private func themeDidChange() {
|
||||
self.update(theme: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
// TODO: To remove
|
||||
private func checkKeyBackup() {
|
||||
guard let keyBackup = self.keyBackup else {
|
||||
return
|
||||
}
|
||||
|
||||
// If a backup already exists and we do not have the private key,
|
||||
// we need to get this private key first. Ask the user to make a key backup restore to catch it
|
||||
if keyBackup.keyBackupVersion != nil && keyBackup.hasPrivateKeyInCryptoStore == false {
|
||||
|
||||
let alertContoller = UIAlertController(title: VectorL10n.secureKeyBackupSetupExistingBackupErrorTitle,
|
||||
message: VectorL10n.secureKeyBackupSetupExistingBackupErrorInfo,
|
||||
preferredStyle: .alert)
|
||||
|
||||
let connectAction = UIAlertAction(title: VectorL10n.secureKeyBackupSetupExistingBackupErrorUnlockIt, style: .default) { (_) in
|
||||
self.delegate?.secureBackupSetupIntroViewControllerDidTapConnectToKeyBackup(self)
|
||||
}
|
||||
|
||||
let resetAction = UIAlertAction(title: VectorL10n.secureKeyBackupSetupExistingBackupErrorDeleteIt, style: .destructive) { (_) in
|
||||
self.deleteKeybackup()
|
||||
}
|
||||
|
||||
let cancelAction = UIAlertAction(title: VectorL10n.cancel, style: .cancel) { (_) in
|
||||
self.delegate?.secureBackupSetupIntroViewControllerDidCancel(self, showSkipAlert: false)
|
||||
}
|
||||
|
||||
alertContoller.addAction(connectAction)
|
||||
alertContoller.addAction(resetAction)
|
||||
alertContoller.addAction(cancelAction)
|
||||
|
||||
self.present(alertContoller, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteKeybackup() {
|
||||
guard let keyBackup = self.keyBackup, let keybackupVersion = keyBackup.keyBackupVersion?.version else {
|
||||
return
|
||||
}
|
||||
|
||||
self.renderLoading()
|
||||
keyBackup.deleteVersion(keybackupVersion, success: { [weak self] in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.renderLoaded()
|
||||
self.checkKeyBackup()
|
||||
}, failure: { [weak self] (error) in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.render(error: error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,10 @@ final class SecureBackupSetupCoordinator: SecureBackupSetupCoordinatorType {
|
|||
// MARK: Private
|
||||
|
||||
private let navigationRouter: NavigationRouterType
|
||||
private let session: MXSession
|
||||
private let recoveryService: MXRecoveryService
|
||||
|
||||
private let keyBackup: MXKeyBackup?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
// Must be used only internally
|
||||
|
@ -39,7 +41,9 @@ final class SecureBackupSetupCoordinator: SecureBackupSetupCoordinatorType {
|
|||
|
||||
init(session: MXSession) {
|
||||
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
|
||||
self.session = session
|
||||
self.recoveryService = session.crypto.recoveryService
|
||||
self.keyBackup = session.crypto.backup
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
@ -58,6 +62,7 @@ final class SecureBackupSetupCoordinator: SecureBackupSetupCoordinatorType {
|
|||
private func createIntro() -> SecureBackupSetupIntroViewController {
|
||||
let introViewController = SecureBackupSetupIntroViewController.instantiate()
|
||||
introViewController.delegate = self
|
||||
introViewController.keyBackup = self.keyBackup
|
||||
return introViewController
|
||||
}
|
||||
|
||||
|
@ -109,6 +114,18 @@ final class SecureBackupSetupCoordinator: SecureBackupSetupCoordinatorType {
|
|||
self.navigationRouter.present(alertController, animated: true)
|
||||
}
|
||||
|
||||
private func showKeyBackupRestore() {
|
||||
guard let keyBackupVersion = self.keyBackup?.keyBackupVersion else {
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = KeyBackupRecoverCoordinator(session: self.session, keyBackupVersion: keyBackupVersion, navigationRouter: self.navigationRouter)
|
||||
|
||||
self.add(childCoordinator: coordinator)
|
||||
coordinator.delegate = self
|
||||
coordinator.start() // Will trigger view controller push
|
||||
}
|
||||
|
||||
private func didCancel(showSkipAlert: Bool = true) {
|
||||
if showSkipAlert {
|
||||
self.showCancelAlert()
|
||||
|
@ -133,8 +150,12 @@ extension SecureBackupSetupCoordinator: SecureBackupSetupIntroViewControllerDele
|
|||
self.showSetupPassphrase()
|
||||
}
|
||||
|
||||
func secureBackupSetupIntroViewControllerDidCancel(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController) {
|
||||
self.didCancel()
|
||||
func secureBackupSetupIntroViewControllerDidCancel(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController, showSkipAlert: Bool) {
|
||||
self.didCancel(showSkipAlert: showSkipAlert)
|
||||
}
|
||||
|
||||
func secureBackupSetupIntroViewControllerDidTapConnectToKeyBackup(_ secureBackupSetupIntroViewController: SecureBackupSetupIntroViewController) {
|
||||
self.showKeyBackupRestore()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,3 +190,14 @@ extension SecureBackupSetupCoordinator: SecretsSetupRecoveryPassphraseCoordinato
|
|||
self.didCancel()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KeyBackupRecoverCoordinatorDelegate
|
||||
extension SecureBackupSetupCoordinator: KeyBackupRecoverCoordinatorDelegate {
|
||||
func keyBackupRecoverCoordinatorDidCancel(_ keyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType) {
|
||||
self.navigationRouter.popToRootModule(animated: true)
|
||||
}
|
||||
|
||||
func keyBackupRecoverCoordinatorDidRecover(_ keyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType) {
|
||||
self.navigationRouter.popToRootModule(animated: true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -871,7 +871,7 @@ SecureBackupSetupCoordinatorBridgePresenterDelegate>
|
|||
if (recoveryService)
|
||||
{
|
||||
[self startActivityIndicator];
|
||||
[recoveryService deleteRecoveryWithSuccess:^{
|
||||
[recoveryService deleteRecoveryWithDeleteServicesBackups:YES success:^{
|
||||
[self stopActivityIndicator];
|
||||
[self reloadData];
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
|
|
Loading…
Reference in a new issue