From 5da191c4e7594ff68d75af4870b74872c473cb74 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 8 Apr 2020 14:09:55 +0200 Subject: [PATCH] Key Backup: Add a screen for recovering with the local private key --- Riot.xcodeproj/project.pbxproj | 40 +++++ Riot/Assets/en.lproj/Vector.strings | 3 + Riot/Generated/Storyboards.swift | 5 + Riot/Generated/Strings.swift | 4 + .../Recover/KeyBackupRecoverCoordinator.swift | 27 ++- ...ackupRecoverDataLoadingViewModelType.swift | 37 ++++ ...ckupRecoverFromPrivateKeyCoordinator.swift | 69 ++++++++ ...RecoverFromPrivateKeyCoordinatorType.swift | 29 ++++ ...ackupRecoverFromPrivateKeyViewAction.swift | 25 +++ ...verFromPrivateKeyViewController.storyboard | 97 +++++++++++ ...pRecoverFromPrivateKeyViewController.swift | 158 ++++++++++++++++++ ...BackupRecoverFromPrivateKeyViewModel.swift | 89 ++++++++++ ...upRecoverFromPrivateKeyViewModelType.swift | 37 ++++ ...BackupRecoverFromPrivateKeyViewState.swift | 26 +++ ...eyBackupRecoverSuccessViewController.swift | 4 +- 15 files changed, 645 insertions(+), 5 deletions(-) create mode 100644 Riot/Modules/KeyBackup/Recover/Loading/KeyBackupRecoverDataLoadingViewModelType.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinator.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinatorType.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewAction.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.storyboard create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModelType.swift create mode 100644 Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewState.swift diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 86c886df8..2501eb67c 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -57,6 +57,14 @@ 324A2054225FC571004FE8B0 /* DeviceVerificationIncomingCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324A204C225FC571004FE8B0 /* DeviceVerificationIncomingCoordinatorType.swift */; }; 324A2055225FC571004FE8B0 /* DeviceVerificationIncomingViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324A204D225FC571004FE8B0 /* DeviceVerificationIncomingViewModelType.swift */; }; 324A2056225FC571004FE8B0 /* DeviceVerificationIncomingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324A204E225FC571004FE8B0 /* DeviceVerificationIncomingCoordinator.swift */; }; + 32607D6C243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D64243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.swift */; }; + 32607D6D243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D65243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinatorType.swift */; }; + 32607D6E243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D66243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModelType.swift */; }; + 32607D6F243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32607D67243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.storyboard */; }; + 32607D70243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D68243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModel.swift */; }; + 32607D71243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D69243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift */; }; + 32607D72243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D6A243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewAction.swift */; }; + 32607D73243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32607D6B243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinator.swift */; }; 3275FD8C21A5A2C500B9C13D /* TermsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3275FD8B21A5A2C500B9C13D /* TermsView.swift */; }; 3281BCF72201FA4200F4A383 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3281BCF62201FA4200F4A383 /* UIControl.swift */; }; 3284A35120A07C210044F922 /* postMessageAPI.js in Resources */ = {isa = PBXBuildFile; fileRef = 3284A35020A07C210044F922 /* postMessageAPI.js */; }; @@ -787,6 +795,14 @@ 325789A5237AB241009388E6 /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/InfoPlist.strings; sourceTree = ""; }; 325789A6237AB27F009388E6 /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/Localizable.strings; sourceTree = ""; }; 325789A7237AB297009388E6 /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/Vector.strings; sourceTree = ""; }; + 32607D64243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyViewController.swift; sourceTree = ""; }; + 32607D65243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyCoordinatorType.swift; sourceTree = ""; }; + 32607D66243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyViewModelType.swift; sourceTree = ""; }; + 32607D67243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = KeyBackupRecoverFromPrivateKeyViewController.storyboard; sourceTree = ""; }; + 32607D68243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyViewModel.swift; sourceTree = ""; }; + 32607D69243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyViewState.swift; sourceTree = ""; }; + 32607D6A243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyViewAction.swift; sourceTree = ""; }; + 32607D6B243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPrivateKeyCoordinator.swift; sourceTree = ""; }; 3267EFB320E379FD00FF1CAA /* CHANGES.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.rst; sourceTree = ""; }; 3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; fileEncoding = 4; path = Podfile; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS.rst; sourceTree = ""; }; @@ -1848,6 +1864,21 @@ path = Incoming; sourceTree = ""; }; + 32607D63243E0A55006674CC /* PrivateKey */ = { + isa = PBXGroup; + children = ( + 32607D64243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.swift */, + 32607D65243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinatorType.swift */, + 32607D66243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModelType.swift */, + 32607D67243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.storyboard */, + 32607D68243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModel.swift */, + 32607D69243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift */, + 32607D6A243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewAction.swift */, + 32607D6B243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinator.swift */, + ); + path = PrivateKey; + sourceTree = ""; + }; 32863A572384070300D07C4A /* Shared */ = { isa = PBXGroup; children = ( @@ -4074,6 +4105,7 @@ B19EFA3821F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift */, B19EFA3A21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift */, B140B4A721F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift */, + 32607D63243E0A55006674CC /* PrivateKey */, B1E5368A21FB6FC0001F3AFF /* Passphrase */, B14F142522144F6400FA0595 /* RecoveryKey */, B1107EC62200B0190038014B /* Success */, @@ -4544,6 +4576,7 @@ 3232AB1522564D9100AD6A5C /* flat-swift4-vector.stencil in Resources */, F083BDE61E7009ED00A9B29C /* busy.mp3 in Resources */, B1B5574C20EE6C4D00210D55 /* MediaAlbumContentViewController.xib in Resources */, + 32607D6F243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.storyboard in Resources */, B1B557E820EF60F500210D55 /* MessagesSearchResultTextMsgBubbleCell.xib in Resources */, B1B558D920EF768F00210D55 /* RoomOutgoingEncryptedAttachmentBubbleCell.xib in Resources */, B1B5573020EE6C4D00210D55 /* BugReportViewController.xib in Resources */, @@ -4823,6 +4856,7 @@ buildActionMask = 2147483647; files = ( B1B557D120EF5E3500210D55 /* MediaAlbumTableCell.m in Sources */, + 32607D71243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift in Sources */, 324A2053225FC571004FE8B0 /* DeviceVerificationIncomingViewModel.swift in Sources */, B1B557A120EF58AD00210D55 /* ContactTableViewCell.m in Sources */, B1CE83DE2422817200D07506 /* KeyVerificationVerifyBySASViewModelType.swift in Sources */, @@ -4847,6 +4881,7 @@ B1B5598820EFC3E000210D55 /* WidgetManager.m in Sources */, B1DB4F0E22316FFF0065DBFA /* UserNameColorGenerator.swift in Sources */, B157FAA123264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorType.swift in Sources */, + 32607D6C243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewController.swift in Sources */, B1057789221304EC00334B1E /* KeyBackupSetupSuccessFromPassphraseViewController.swift in Sources */, B1DCC61922E5E17100625807 /* EmojiPickerCoordinatorType.swift in Sources */, B1C3360122F1ED600021BA8D /* MediaPickerCoordinatorType.swift in Sources */, @@ -4863,6 +4898,7 @@ B1BD71C1238EA92100BA92E2 /* WidgetPermissionViewModel.swift in Sources */, B1B557E320EF60B900210D55 /* MessagesSearchResultAttachmentBubbleCell.m in Sources */, B1CE9F062216FB09000FAE6A /* EncryptionKeysExportPresenter.swift in Sources */, + 32607D72243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewAction.swift in Sources */, B1B5574420EE6C4D00210D55 /* CallViewController.m in Sources */, B12D7A0023E2462200FACEDC /* UserVerificationStartCoordinatorType.swift in Sources */, B1B5572220EE6C4D00210D55 /* RoomSettingsViewController.m in Sources */, @@ -4874,6 +4910,7 @@ B1B558E820EF768F00210D55 /* RoomIncomingAttachmentWithPaginationTitleBubbleCell.m in Sources */, B1B558F320EF768F00210D55 /* RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, B12D79FE23E2462200FACEDC /* UserVerificationStartViewController.swift in Sources */, + 32607D73243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinator.swift in Sources */, B1B557BD20EF5B4500210D55 /* KeyboardGrowingTextView.m in Sources */, B1A68593229E807A00D6C09A /* RoomBubbleCellLayout.swift in Sources */, B1B558F420EF768F00210D55 /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, @@ -4890,6 +4927,7 @@ B1DCC61C22E5E17100625807 /* EmojiPickerViewAction.swift in Sources */, B1098BDF21ECE09F000DDA48 /* Strings.swift in Sources */, B1BEE71523DF2ACF0003A4CB /* UserVerificationCoordinator.swift in Sources */, + 32607D70243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModel.swift in Sources */, B1B558C420EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, B1963B2E228F1C4900CBA17F /* BubbleReactionViewData.swift in Sources */, B1C3361C22F32B4A0021BA8D /* SingleImagePickerPresenter.swift in Sources */, @@ -5156,6 +5194,7 @@ B14F143322144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModel.swift in Sources */, B1B336C0242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewModelType.swift in Sources */, 32A6001822C661100042C1D9 /* EditHistoryViewModel.swift in Sources */, + 32607D6E243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModelType.swift in Sources */, B1B558D020EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, B1B558CF20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */, B140B4A221F87F7100E3F5FE /* OperationQueue.swift in Sources */, @@ -5281,6 +5320,7 @@ B12D79FF23E2462200FACEDC /* UserVerificationStartViewState.swift in Sources */, B1B558CE20EF768F00210D55 /* RoomOutgoingEncryptedAttachmentBubbleCell.m in Sources */, B1B5577D20EE84BF00210D55 /* CircleButton.m in Sources */, + 32607D6D243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinatorType.swift in Sources */, 32BF995521FA2AB700698084 /* SettingsKeyBackupViewAction.swift in Sources */, B109D6F1222D8C400061B6D9 /* UIApplication.swift in Sources */, B1BEE73723DF44A60003A4CB /* UserVerificationSessionsStatusViewState.swift in Sources */, diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 2c84b2de8..0e536c1fd 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -951,6 +951,9 @@ "key_backup_recover_invalid_recovery_key_title" = "Recovery Key Mismatch"; "key_backup_recover_invalid_recovery_key" = "Backup could not be decrypted with this key: please verify that you entered the correct recovery key."; +// Recover from private key +"key_backup_recover_from_private_key_info" = "Restoring backup…"; + // Recover from passphrase "key_backup_recover_from_passphrase_info" = "Use your recovery passphrase to unlock your secure message history"; diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index fc80cf7ba..69b27dd66 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -37,6 +37,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromPassphraseViewController.self) } + internal enum KeyBackupRecoverFromPrivateKeyViewController: StoryboardType { + internal static let storyboardName = "KeyBackupRecoverFromPrivateKeyViewController" + + internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromPrivateKeyViewController.self) + } internal enum KeyBackupRecoverFromRecoveryKeyViewController: StoryboardType { internal static let storyboardName = "KeyBackupRecoverFromRecoveryKeyViewController" diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index b9f23f4fa..13e0da4c0 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1330,6 +1330,10 @@ internal enum VectorL10n { internal static var keyBackupRecoverFromPassphraseRecoverAction: String { return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_recover_action") } + /// Restoring backup… + internal static var keyBackupRecoverFromPrivateKeyInfo: String { + return VectorL10n.tr("Vector", "key_backup_recover_from_private_key_info") + } /// Use your recovery key to unlock your secure message history internal static var keyBackupRecoverFromRecoveryKeyInfo: String { return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_info") diff --git a/Riot/Modules/KeyBackup/Recover/KeyBackupRecoverCoordinator.swift b/Riot/Modules/KeyBackup/Recover/KeyBackupRecoverCoordinator.swift index 3912c1715..4bff0e7a8 100644 --- a/Riot/Modules/KeyBackup/Recover/KeyBackupRecoverCoordinator.swift +++ b/Riot/Modules/KeyBackup/Recover/KeyBackupRecoverCoordinator.swift @@ -43,11 +43,15 @@ final class KeyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType { // MARK: - Public func start() { - + let rootCoordinator: Coordinator & Presentable + // Check if we have the private key locally + if self.session.crypto.backup.hasPrivateKeyInCryptoStore { + rootCoordinator = createRecoverFromPrivateKeyCoordinator() + } // Check if a passphrase has been set for given backup - if let megolmBackupAuthData = MXMegolmBackupAuthData(fromJSON: self.keyBackupVersion.authData), megolmBackupAuthData.privateKeySalt != nil { + else if let megolmBackupAuthData = MXMegolmBackupAuthData(fromJSON: self.keyBackupVersion.authData), megolmBackupAuthData.privateKeySalt != nil { rootCoordinator = self.createRecoverFromPassphraseCoordinator() } else { rootCoordinator = self.createRecoverFromRecoveryKeyCoordinator() @@ -66,6 +70,12 @@ final class KeyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType { // MARK: - Private + private func createRecoverFromPrivateKeyCoordinator() -> KeyBackupRecoverFromPrivateKeyCoordinator { + let coordinator = KeyBackupRecoverFromPrivateKeyCoordinator(keyBackup: self.session.crypto.backup, keyBackupVersion: self.keyBackupVersion) + coordinator.delegate = self + return coordinator + } + private func createRecoverFromPassphraseCoordinator() -> KeyBackupRecoverFromPassphraseCoordinator { let coordinator = KeyBackupRecoverFromPassphraseCoordinator(keyBackup: self.session.crypto.backup, keyBackupVersion: self.keyBackupVersion) coordinator.delegate = self @@ -97,6 +107,17 @@ final class KeyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType { } } +// MARK: - KeyBackupRecoverFromPassphraseCoordinatorDelegate +extension KeyBackupRecoverCoordinator: KeyBackupRecoverFromPrivateKeyCoordinatorDelegate { + func keyBackupRecoverFromPrivateKeyCoordinatorDidRecover(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) { + self.showRecoverSuccess() + } + + func keyBackupRecoverFromPrivateKeyCoordinatorDidCancel(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) { + self.delegate?.keyBackupRecoverCoordinatorDidCancel(self) + } +} + // MARK: - KeyBackupRecoverFromPassphraseCoordinatorDelegate extension KeyBackupRecoverCoordinator: KeyBackupRecoverFromPassphraseCoordinatorDelegate { func keyBackupRecoverFromPassphraseCoordinatorDidRecover(_ keyBackupRecoverFromPassphraseCoordinator: KeyBackupRecoverFromPassphraseCoordinatorType) { @@ -125,7 +146,7 @@ extension KeyBackupRecoverCoordinator: KeyBackupRecoverFromRecoveryKeyCoordinato // MARK: - KeyBackupRecoverSuccessViewControllerDelegate extension KeyBackupRecoverCoordinator: KeyBackupRecoverSuccessViewControllerDelegate { - func KeyBackupRecoverSuccessViewControllerDidTapDone(_ keyBackupRecoverSuccessViewController: KeyBackupRecoverSuccessViewController) { + func keyBackupRecoverSuccessViewControllerDidTapDone(_ keyBackupRecoverSuccessViewController: KeyBackupRecoverSuccessViewController) { self.delegate?.keyBackupRecoverCoordinatorDidRecover(self) } } diff --git a/Riot/Modules/KeyBackup/Recover/Loading/KeyBackupRecoverDataLoadingViewModelType.swift b/Riot/Modules/KeyBackup/Recover/Loading/KeyBackupRecoverDataLoadingViewModelType.swift new file mode 100644 index 000000000..1ef8aab16 --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/Loading/KeyBackupRecoverDataLoadingViewModelType.swift @@ -0,0 +1,37 @@ +// File created from ScreenTemplate +// $ createScreen.sh KeyBackup/Recover/Loading KeyBackupRecoverDataLoading +/* + Copyright 2020 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 Foundation + +protocol KeyBackupRecoverDataLoadingViewModelViewDelegate: class { + func keyBackupRecoverDataLoadingViewModel(_ viewModel: KeyBackupRecoverDataLoadingViewModelType, didUpdateViewState viewSate: KeyBackupRecoverDataLoadingViewState) +} + +protocol KeyBackupRecoverDataLoadingViewModelCoordinatorDelegate: class { + func keyBackupRecoverDataLoadingViewModelDidRecover(_ viewModel: KeyBackupRecoverDataLoadingViewModelType) + func keyBackupRecoverDataLoadingViewModelDidCancel(_ viewModel: KeyBackupRecoverDataLoadingViewModelType) +} + +/// Protocol describing the view model used by `KeyBackupRecoverDataLoadingViewController` +protocol KeyBackupRecoverDataLoadingViewModelType { + + var viewDelegate: KeyBackupRecoverDataLoadingViewModelViewDelegate? { get set } + var coordinatorDelegate: KeyBackupRecoverDataLoadingViewModelCoordinatorDelegate? { get set } + + func process(viewAction: KeyBackupRecoverDataLoadingViewAction) +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinator.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinator.swift new file mode 100644 index 000000000..2512039e0 --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinator.swift @@ -0,0 +1,69 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2020 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 Foundation +import UIKit + +final class KeyBackupRecoverFromPrivateKeyCoordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private var keyBackupRecoverFromPrivateKeyViewModel: KeyBackupRecoverFromPrivateKeyViewModelType + private let keyBackupRecoverFromPrivateKeyViewController: KeyBackupRecoverFromPrivateKeyViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: KeyBackupRecoverFromPrivateKeyCoordinatorDelegate? + + // MARK: - Setup + + init(keyBackup: MXKeyBackup, keyBackupVersion: MXKeyBackupVersion) { + + let keyBackupRecoverFromPrivateKeyViewModel = KeyBackupRecoverFromPrivateKeyViewModel(keyBackup: keyBackup, keyBackupVersion: keyBackupVersion) + let keyBackupRecoverFromPrivateKeyViewController = KeyBackupRecoverFromPrivateKeyViewController.instantiate(with: keyBackupRecoverFromPrivateKeyViewModel) + self.keyBackupRecoverFromPrivateKeyViewModel = keyBackupRecoverFromPrivateKeyViewModel + self.keyBackupRecoverFromPrivateKeyViewController = keyBackupRecoverFromPrivateKeyViewController + } + + // MARK: - Public methods + + func start() { + self.keyBackupRecoverFromPrivateKeyViewModel.coordinatorDelegate = self + } + + func toPresentable() -> UIViewController { + return self.keyBackupRecoverFromPrivateKeyViewController + } +} + +// MARK: - KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate +extension KeyBackupRecoverFromPrivateKeyCoordinator: KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate { + + func keyBackupRecoverFromPrivateKeyViewModelDidRecover(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) { + self.delegate?.keyBackupRecoverFromPrivateKeyCoordinatorDidRecover(self) + } + + func keyBackupRecoverFromPrivateKeyViewModelDidCancel(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) { + self.delegate?.keyBackupRecoverFromPrivateKeyCoordinatorDidCancel(self) + } +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinatorType.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinatorType.swift new file mode 100644 index 000000000..b50aa9667 --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyCoordinatorType.swift @@ -0,0 +1,29 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2020 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 Foundation + +protocol KeyBackupRecoverFromPrivateKeyCoordinatorDelegate: class { + func keyBackupRecoverFromPrivateKeyCoordinatorDidRecover(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) + func keyBackupRecoverFromPrivateKeyCoordinatorDidCancel(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) +} + +/// `KeyBackupRecoverFromPrivateKeyCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +protocol KeyBackupRecoverFromPrivateKeyCoordinatorType: Coordinator, Presentable { + var delegate: KeyBackupRecoverFromPrivateKeyCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewAction.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewAction.swift new file mode 100644 index 000000000..5ad5a61bf --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewAction.swift @@ -0,0 +1,25 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2020 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 Foundation + +/// KeyBackupRecoverFromPrivateKeyViewController view actions exposed to view model +enum KeyBackupRecoverFromPrivateKeyViewAction { + case recover + case cancel +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.storyboard b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.storyboard new file mode 100644 index 000000000..1c8ba341c --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.storyboard @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.swift new file mode 100644 index 000000000..1aaf96e62 --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewController.swift @@ -0,0 +1,158 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2020 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 + +final class KeyBackupRecoverFromPrivateKeyViewController: UIViewController { + + // MARK: - Constants + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var shieldImageView: UIImageView! + + @IBOutlet private weak var informationLabel: UILabel! + + // MARK: Private + + private var viewModel: KeyBackupRecoverFromPrivateKeyViewModelType! + private var theme: Theme! + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + // MARK: - Setup + + class func instantiate(with viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) -> KeyBackupRecoverFromPrivateKeyViewController { + let viewController = StoryboardScene.KeyBackupRecoverFromPrivateKeyViewController.initialScene.instantiate() + viewController.viewModel = viewModel + 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.keyBackupRecoverTitle + + self.setupViews() + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + self.viewModel.viewDelegate = self + + self.viewModel.process(viewAction: .recover) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + + // MARK: - Private + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in + self?.cancelButtonAction() + } + self.navigationItem.rightBarButtonItem = cancelBarButtonItem + + let shieldImage = Asset.Images.keyBackupLogo.image.withRenderingMode(.alwaysTemplate) + self.shieldImageView.image = shieldImage + + self.informationLabel.text = VectorL10n.keyBackupRecoverFromPrivateKeyInfo + } + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + self.shieldImageView.tintColor = theme.textPrimaryColor + + self.informationLabel.textColor = theme.textPrimaryColor + } + + private func render(viewState: KeyBackupRecoverFromPrivateKeyViewState) { + switch viewState { + case .loading: + self.renderLoading() + case .loaded: + self.renderLoaded() + case .error(let error): + self.render(error: error) + } + } + + private func renderLoading() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + + private func renderLoaded() { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + } + + private func render(error: Error) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil) + } + + + // MARK: - Actions + + private func cancelButtonAction() { + self.viewModel.process(viewAction: .cancel) + } +} + + +// MARK: - KeyBackupRecoverFromPrivateKeyViewModelViewDelegate +extension KeyBackupRecoverFromPrivateKeyViewController: KeyBackupRecoverFromPrivateKeyViewModelViewDelegate { + + func keyBackupRecoverFromPrivateKeyViewModel(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType, didUpdateViewState viewSate: KeyBackupRecoverFromPrivateKeyViewState) { + self.render(viewState: viewSate) + } +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift new file mode 100644 index 000000000..6e697b612 --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift @@ -0,0 +1,89 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2020 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 Foundation + +final class KeyBackupRecoverFromPrivateKeyViewModel: KeyBackupRecoverFromPrivateKeyViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let keyBackup: MXKeyBackup + private var currentHTTPOperation: MXHTTPOperation? + private let keyBackupVersion: MXKeyBackupVersion + + // MARK: Public + + weak var viewDelegate: KeyBackupRecoverFromPrivateKeyViewModelViewDelegate? + weak var coordinatorDelegate: KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate? + + // MARK: - Setup + + init(keyBackup: MXKeyBackup, keyBackupVersion: MXKeyBackupVersion) { + self.keyBackup = keyBackup + self.keyBackupVersion = keyBackupVersion + } + + deinit { + } + + // MARK: - Public + + func process(viewAction: KeyBackupRecoverFromPrivateKeyViewAction) { + switch viewAction { + case .recover: + self.recoverWithPrivateKey() + case .cancel: + self.coordinatorDelegate?.keyBackupRecoverFromPrivateKeyViewModelDidCancel(self) + } + } + + // MARK: - Private + + private func recoverWithPrivateKey() { + + self.update(viewState: .loading) + + self.currentHTTPOperation = keyBackup.restoreUsingPrivateKey(inCryptoStore: keyBackupVersion, room: nil, session: nil, success: { [weak self] (_, _) in + guard let sself = self else { + return + } + + // Trust on decrypt + sself.currentHTTPOperation = sself.keyBackup.trust(sself.keyBackupVersion, trust: true, success: { [weak sself] () in + guard let ssself = sself else { + return + } + + ssself.update(viewState: .loaded) + ssself.coordinatorDelegate?.keyBackupRecoverFromPrivateKeyViewModelDidRecover(ssself) + + }, failure: { [weak sself] error in + sself?.update(viewState: .error(error)) + }) + + }, failure: { [weak self] error in + self?.update(viewState: .error(error)) + }) + } + + private func update(viewState: KeyBackupRecoverFromPrivateKeyViewState) { + self.viewDelegate?.keyBackupRecoverFromPrivateKeyViewModel(self, didUpdateViewState: viewState) + } +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModelType.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModelType.swift new file mode 100644 index 000000000..ed030362f --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModelType.swift @@ -0,0 +1,37 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2020 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 Foundation + +protocol KeyBackupRecoverFromPrivateKeyViewModelViewDelegate: class { + func keyBackupRecoverFromPrivateKeyViewModel(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType, didUpdateViewState viewSate: KeyBackupRecoverFromPrivateKeyViewState) +} + +protocol KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate: class { + func keyBackupRecoverFromPrivateKeyViewModelDidRecover(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) + func keyBackupRecoverFromPrivateKeyViewModelDidCancel(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) +} + +/// Protocol describing the view model used by `KeyBackupRecoverFromPrivateKeyViewController` +protocol KeyBackupRecoverFromPrivateKeyViewModelType { + + var viewDelegate: KeyBackupRecoverFromPrivateKeyViewModelViewDelegate? { get set } + var coordinatorDelegate: KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate? { get set } + + func process(viewAction: KeyBackupRecoverFromPrivateKeyViewAction) +} diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewState.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewState.swift new file mode 100644 index 000000000..fcfe3afa2 --- /dev/null +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewState.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey +/* + Copyright 2019 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 Foundation + +/// KeyBackupRecoverFromPrivateKeyViewController view state +enum KeyBackupRecoverFromPrivateKeyViewState { + case loading + case loaded + case error(Error) +} diff --git a/Riot/Modules/KeyBackup/Recover/Success/KeyBackupRecoverSuccessViewController.swift b/Riot/Modules/KeyBackup/Recover/Success/KeyBackupRecoverSuccessViewController.swift index 8d126897d..dd5a834da 100644 --- a/Riot/Modules/KeyBackup/Recover/Success/KeyBackupRecoverSuccessViewController.swift +++ b/Riot/Modules/KeyBackup/Recover/Success/KeyBackupRecoverSuccessViewController.swift @@ -17,7 +17,7 @@ import UIKit protocol KeyBackupRecoverSuccessViewControllerDelegate: class { - func KeyBackupRecoverSuccessViewControllerDidTapDone(_ keyBackupRecoverSuccessViewController: KeyBackupRecoverSuccessViewController) + func keyBackupRecoverSuccessViewControllerDidTapDone(_ keyBackupRecoverSuccessViewController: KeyBackupRecoverSuccessViewController) } final class KeyBackupRecoverSuccessViewController: UIViewController { @@ -115,6 +115,6 @@ final class KeyBackupRecoverSuccessViewController: UIViewController { } @IBAction private func doneButtonAction(_ sender: Any) { - self.delegate?.KeyBackupRecoverSuccessViewControllerDidTapDone(self) + self.delegate?.keyBackupRecoverSuccessViewControllerDidTapDone(self) } }