mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-20 00:24:43 +02:00
222f3292a2
# Conflicts: # .github/workflows/ci-build.yml # .github/workflows/ci-tests.yml # .github/workflows/release-alpha.yml # .github/workflows/triage-move-labelled.yml # .github/workflows/triage-priority-bugs.yml # .gitignore # CHANGES.md # Config/AppConfiguration.swift # Config/AppIdentifiers.xcconfig # Config/AppVersion.xcconfig # Config/BuildSettings.swift # Config/CommonConfiguration.swift # Gemfile # Gemfile.lock # IDETemplateMacros.plist # Podfile # Podfile.lock # README.md # Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme # Riot/Assets/Images.xcassets/Common/reveal_password_button.imageset/reveal_password_button.png # Riot/Assets/Images.xcassets/Common/reveal_password_button.imageset/reveal_password_button@2x.png # Riot/Assets/Images.xcassets/Common/reveal_password_button.imageset/reveal_password_button@3x.png # Riot/Assets/Images.xcassets/People/people_floating_action.imageset/Contents.json # Riot/Assets/Images.xcassets/Rooms/rooms_floating_action.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Recovery/secrets_recovery_key.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Recovery/secrets_recovery_passphrase.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Setup/secrets_setup_key.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Setup/secrets_setup_passphrase.imageset/Contents.json # Riot/Assets/Images.xcassets/TabBar/tab_people.imageset/Contents.json # Riot/Assets/Images.xcassets/TabBar/tab_rooms.imageset/Contents.json # Riot/Assets/SharedImages.xcassets/AppIcon.appiconset/Contents.json # Riot/Assets/SharedImages.xcassets/horizontal_logo.imageset/Contents.json # Riot/Assets/ar.lproj/InfoPlist.strings # Riot/Assets/cs.lproj/Vector.strings # Riot/Assets/de.lproj/InfoPlist.strings # Riot/Assets/de.lproj/Localizable.strings # Riot/Assets/de.lproj/Vector.strings # Riot/Assets/en.lproj/Localizable.strings # Riot/Assets/en.lproj/Untranslated.strings # Riot/Assets/en.lproj/Vector.strings # Riot/Assets/es.lproj/InfoPlist.strings # Riot/Assets/es.lproj/Vector.strings # Riot/Assets/et.lproj/InfoPlist.strings # Riot/Assets/et.lproj/Vector.strings # Riot/Assets/fr.lproj/InfoPlist.strings # Riot/Assets/fr.lproj/Vector.strings # Riot/Assets/hu.lproj/InfoPlist.strings # Riot/Assets/hu.lproj/Vector.strings # Riot/Assets/id.lproj/InfoPlist.strings # Riot/Assets/id.lproj/Vector.strings # Riot/Assets/is.lproj/InfoPlist.strings # Riot/Assets/is.lproj/Vector.strings # Riot/Assets/it.lproj/InfoPlist.strings # Riot/Assets/it.lproj/Vector.strings # Riot/Assets/ja.lproj/InfoPlist.strings # Riot/Assets/ja.lproj/Localizable.strings # Riot/Assets/ja.lproj/Vector.strings # Riot/Assets/nl.lproj/InfoPlist.strings # Riot/Assets/nl.lproj/Vector.strings # Riot/Assets/pl.lproj/InfoPlist.strings # Riot/Assets/pl.lproj/Vector.strings # Riot/Assets/pt_BR.lproj/InfoPlist.strings # Riot/Assets/pt_BR.lproj/Vector.strings # Riot/Assets/ru.lproj/InfoPlist.strings # Riot/Assets/ru.lproj/Vector.strings # Riot/Assets/sk.lproj/InfoPlist.strings # Riot/Assets/sk.lproj/Vector.strings # Riot/Assets/sq.lproj/InfoPlist.strings # Riot/Assets/sq.lproj/Vector.strings # Riot/Assets/sv.lproj/InfoPlist.strings # Riot/Assets/sv.lproj/Vector.strings # Riot/Assets/third_party_licenses.html # Riot/Assets/uk.lproj/InfoPlist.strings # Riot/Assets/uk.lproj/Vector.strings # Riot/Assets/zh_Hans.lproj/InfoPlist.strings # Riot/Assets/zh_Hans.lproj/Localizable.strings # Riot/Assets/zh_Hans.lproj/Vector.strings # Riot/Assets/zh_Hant.lproj/Vector.strings # Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h # Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m # Riot/Categories/MXRestClient+Async.swift # Riot/Categories/MXSession+Riot.m # Riot/Categories/NSAttributedString.swift # Riot/Categories/Publisher+Riot.swift # Riot/Categories/RoomBubbleCellData.swift # Riot/Categories/UILabel.swift # Riot/Categories/UIScrollView.swift # Riot/Categories/UIView.swift # Riot/Categories/UIViewController.swift # Riot/Generated/Images.swift # Riot/Generated/Strings.swift # Riot/Generated/UntranslatedStrings.swift # Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift # Riot/Managers/LocalAuthentication/LocalAuthenticationService.swift # Riot/Managers/PushNotification/PushNotificationService.m # Riot/Managers/PushNotification/PushNotificationStore.swift # Riot/Managers/Settings/RiotSettings.swift # Riot/Managers/Settings/Shared/RiotSharedSettings.swift # Riot/Managers/Theme/Themes/DarkTheme.swift # Riot/Managers/Theme/Themes/DefaultTheme.swift # Riot/Managers/UISIAutoReporter/UISIAutoReporter.swift # Riot/Model/HomeserverConfiguration/HomeserverConfigurationBuilder.swift # Riot/Modules/Analytics/Analytics.swift # Riot/Modules/Analytics/AnalyticsUIElement.swift # Riot/Modules/Analytics/DecryptionFailureTracker.m # Riot/Modules/Application/AppCoordinator.swift # Riot/Modules/Application/LegacyAppDelegate.h # Riot/Modules/Application/LegacyAppDelegate.m # Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift # Riot/Modules/Common/Avatar/AvatarView.swift # Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h # Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m # Riot/Modules/Common/Recents/RecentsViewController.h # Riot/Modules/Common/Recents/RecentsViewController.m # Riot/Modules/Common/Recents/Views/RecentTableViewCell.m # Riot/Modules/Common/SwiftUI/VectorHostingController.swift # Riot/Modules/Common/Toasts/RoundedToastView.swift # Riot/Modules/Common/Toasts/ToastViewState.swift # Riot/Modules/Common/UserIndicators/UserIndicatorPresenter.swift # Riot/Modules/Common/UserIndicators/UserIndicatorStore.swift # Riot/Modules/Common/UserIndicators/ViewPresenters/ToastViewPresenter.swift # Riot/Modules/Common/WebViewController/WebViewViewController.m # Riot/Modules/Communities/Home/GroupHomeViewController.m # Riot/Modules/Communities/Members/GroupParticipantsViewController.m # Riot/Modules/Communities/Rooms/GroupRoomsViewController.m # Riot/Modules/Contacts/ContactsTableViewController.m # Riot/Modules/Contacts/ContactsTableViewController.xib # Riot/Modules/Contacts/Details/ContactDetailsViewController.m # Riot/Modules/Contacts/Views/ContactTableViewCell.m # Riot/Modules/Contacts/Views/ContactTableViewCell.xib # Riot/Modules/ContextMenu/ActionProviders/RoomActionProvider.swift # Riot/Modules/ContextMenu/Services/RoomContextActionService.swift # Riot/Modules/CreateRoom/CreateRoomCoordinator.swift # Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsCoordinator.swift # Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift # Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift # Riot/Modules/DeepLink/UniversalLinkParameters.swift # Riot/Modules/Favorites/FavouritesViewController.h # Riot/Modules/Favorites/FavouritesViewController.m # Riot/Modules/GlobalSearch/UnifiedSearchViewController.m # Riot/Modules/Home/HomeViewController.m # Riot/Modules/Home/Views/RoomCollectionViewCell.m # Riot/Modules/Integrations/WidgetPicker/WidgetPickerViewController.m # Riot/Modules/Integrations/Widgets/StickerPicker/StickerPickerViewController.m # Riot/Modules/KeyBackup/ManualExport/EncryptionKeysExportPresenter.swift # Riot/Modules/KeyVerification/Common/KeyVerificationCoordinator.swift # Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift # Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinator.swift # Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard # Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.swift # Riot/Modules/KeyVerification/User/SessionStatus/UserVerificationSessionStatusViewController.swift # Riot/Modules/LocationSharing/LocationManager.swift # Riot/Modules/LocationSharing/UserLocationService.swift # Riot/Modules/LocationSharing/UserLocationServiceProvider.swift # Riot/Modules/MatrixKit/Categories/NSBundle+MatrixKit.m # Riot/Modules/MatrixKit/Controllers/MXKAccountDetailsViewController.m # Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m # Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.h # Riot/Modules/MatrixKit/Controllers/MXKViewController.h # Riot/Modules/MatrixKit/Models/Account/MXKAccount.h # Riot/Modules/MatrixKit/Models/Account/MXKAccount.m # Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.h # Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m # Riot/Modules/MatrixKit/Models/Contact/MXKContact.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataStoring.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataWithAppendingMode.m # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m # Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m # Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift # Riot/Modules/MatrixKit/Utils/ErrorPresentation/MXKErrorPresentableBuilder.m # Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.h # Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m # Riot/Modules/MatrixKit/Utils/MXKTools.h # Riot/Modules/MatrixKit/Utils/MXKTools.m # Riot/Modules/MatrixKit/Views/Account/MXKAccountTableViewCell.m # Riot/Modules/MatrixKit/Views/MXKTableViewCell/MXKTableViewCellWithLabelAndTextField.xib # Riot/Modules/MatrixKit/Views/MXKTableViewCell/MXKTableViewCellWithTextFieldAndButton.m # Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarView.m # Riot/Modules/MatrixKit/Views/RoomMemberList/MXKRoomMemberTableViewCell.m # Riot/Modules/MediaPicker/MediaPickerViewController.m # Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift # Riot/Modules/MediaPickerV2/MediaPickerPresenter.swift # Riot/Modules/Onboarding/OnboardingCoordinator.swift # Riot/Modules/Onboarding/OnboardingCoordinatorBridgePresenter.swift # Riot/Modules/Onboarding/OnboardingCoordinatorProtocol.swift # Riot/Modules/People/PeopleViewController.h # Riot/Modules/People/PeopleViewController.m # Riot/Modules/Pills/PillTextAttachment.swift # Riot/Modules/Pills/PillsFormatter.swift # Riot/Modules/QRCode/QRCodeGenerator.swift # Riot/Modules/Room/CellData/RoomBubbleCellData.m # Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift # Riot/Modules/Room/CreationModal/RoomCreationEventsModal/RoomCreationEventsModalCoordinator.swift # Riot/Modules/Room/CreationModal/RoomCreationEventsModal/RoomCreationEventsModalViewModel.swift # Riot/Modules/Room/CreationModal/RoomCreationModalCoordinatorBridgePresenter.swift # Riot/Modules/Room/DataSources/RoomDataSource.m # Riot/Modules/Room/DataSources/RoomDataSource.swift # Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift # Riot/Modules/Room/Files/RoomFilesViewController.m # Riot/Modules/Room/Location/RoomTimelineLocationView.swift # Riot/Modules/Room/Location/RoomTimelineLocationView.xib # Riot/Modules/Room/MXKRoomViewController.h # Riot/Modules/Room/MXKRoomViewController.m # Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.h # Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m # Riot/Modules/Room/Members/RoomParticipantsViewController.h # Riot/Modules/Room/Members/RoomParticipantsViewController.m # Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift # Riot/Modules/Room/RoomCoordinator.swift # Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewState.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/Views/RoomInfoBasicView.swift # Riot/Modules/Room/RoomViewController.m # Riot/Modules/Room/Settings/RoomSettingsViewController.m # Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.xib # Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.m # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroCell.swift # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroCellContentView.swift # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroViewData.swift # Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipCollapsedBubbleCell.m # Riot/Modules/Room/TimelineCells/RoomTimelineCellIdentifier.h # Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellProvider.m # Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineStyle.swift # Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/FileWithoutThumbnail/Common/FileWithoutThumbnailBaseBubbleCell.swift # Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/FileWithoutThumbnail/Common/FileWithoutThumbnailCellContentView.swift # Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/FileWithoutThumbnail/Common/FileWithoutThumbnailCellContentView.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Encrypted/RoomIncomingEncryptedAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Encrypted/RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Encrypted/RoomOutgoingEncryptedAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Encrypted/RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Location/LocationPlainCell.swift # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Poll/PollPlainCell.swift # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Sticker/RoomSelectedStickerBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Encrypted/RoomIncomingEncryptedTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Encrypted/RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Encrypted/RoomOutgoingEncryptedTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Encrypted/RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellProvider.m # Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineStyle.swift # Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyle.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.xib # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionViewCell.xib # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionsView.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionsViewModel.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionsViewModelType.swift # Riot/Modules/Room/TimelineDecorations/Threads/Summary/ThreadSummaryView.swift # Riot/Modules/Room/VoiceMessages/VoiceMessageAudioConverter.swift # Riot/Modules/Room/VoiceMessages/VoiceMessageAudioRecorder.swift # Riot/Modules/Room/VoiceMessages/VoiceMessagePlaybackView.swift # Riot/Modules/Room/VoiceMessages/VoiceMessagePlaybackView.xib # Riot/Modules/Room/VoiceMessages/VoiceMessageToolbarView.swift # Riot/Modules/Rooms/RoomsViewController.h # Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.swift # Riot/Modules/Rooms/ShowDirectory/Cells/Room/DirectoryRoomTableViewCell.swift # Riot/Modules/Rooms/ShowDirectory/Cells/Room/DirectoryRoomTableViewCell.xib # Riot/Modules/Rooms/ShowDirectory/PublicRoomsDirectoryViewModel.swift # Riot/Modules/Rooms/ShowDirectory/ShowDirectoryViewController.swift # Riot/Modules/Rooms/ShowDirectory/ShowDirectoryViewModel.swift # Riot/Modules/Secrets/Recover/RecoverWithKey/SecretsRecoveryWithKeyCoordinator.swift # Riot/Modules/Secrets/Recover/RecoverWithKey/SecretsRecoveryWithKeyViewController.swift # Riot/Modules/Secrets/Recover/RecoverWithPassphrase/SecretsRecoveryWithPassphraseCoordinator.swift # Riot/Modules/Secrets/Recover/RecoverWithPassphrase/SecretsRecoveryWithPassphraseViewController.swift # Riot/Modules/Secrets/Recover/SecretsRecoveryCoordinator.swift # Riot/Modules/Secrets/Reset/SecretsResetViewController.storyboard # Riot/Modules/Secrets/Reset/SecretsResetViewController.swift # Riot/Modules/Secrets/Setup/RecoveryKey/SecretsSetupRecoveryKeyViewController.swift # Riot/Modules/Secrets/Setup/RecoveryPassphrase/SecretsSetupRecoveryPassphraseViewController.storyboard # Riot/Modules/Secrets/Setup/RecoveryPassphrase/SecretsSetupRecoveryPassphraseViewController.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewController.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModel.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModelType.swift # Riot/Modules/SecureBackup/Setup/SecureBackupSetupCoordinator.swift # Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewController.storyboard # Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewController.swift # Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewModel.swift # Riot/Modules/SetPinCode/PinCodePreferences.swift # Riot/Modules/SetPinCode/SetPinCoordinator.swift # Riot/Modules/SetPinCode/SetPinCoordinatorBridgePresenter.swift # Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift # Riot/Modules/SetPinCode/SetupBiometrics/SetupBiometricsCoordinator.swift # Riot/Modules/SetPinCode/SetupBiometrics/SetupBiometricsViewController.swift # Riot/Modules/SetPinCode/SetupBiometrics/SetupBiometricsViewModel.swift # Riot/Modules/Settings/DeactivateAccount/DeactivateAccountViewController.m # Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m # Riot/Modules/Settings/Security/SecurityViewController.m # Riot/Modules/Settings/SettingsViewController.m # Riot/Modules/SideMenu/SideMenuCoordinator.swift # Riot/Modules/SideMenu/SideMenuViewModel.swift # Riot/Modules/Spaces/SpaceList/SpaceListViewModel.swift # Riot/Modules/Spaces/SpaceMenu/SpaceMenuPresenter.swift # Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModel.swift # Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift # Riot/Modules/SplitView/SplitViewCoordinator.swift # Riot/Modules/SplitView/SplitViewCoordinatorType.swift # Riot/Modules/StartChat/StartChatViewController.m # Riot/Modules/TabBar/MasterTabBarController.h # Riot/Modules/TabBar/MasterTabBarController.m # Riot/Modules/TabBar/TabBarCoordinator.swift # Riot/Modules/TabBar/TabBarCoordinatorType.swift # Riot/Modules/Threads/ThreadList/ThreadListViewModel.swift # Riot/SupportingFiles/Info.plist # Riot/SupportingFiles/Riot-Bridging-Header.h # Riot/SupportingFiles/Riot.entitlements # Riot/Utils/EventFormatter+DTCoreTextFix.m # Riot/Utils/EventFormatter.m # Riot/Utils/Tools.h # Riot/Utils/Tools.m # Riot/Utils/URLValidator.swift # Riot/Utils/UniversalLink.h # Riot/Utils/UniversalLink.m # Riot/target.yml # RiotNSE/NotificationService.swift # RiotNSE/RiotNSE.entitlements # RiotNSE/target.yml # RiotShareExtension/Shared/View/ShareViewController.m # RiotShareExtension/SupportingFiles/Info.plist # RiotShareExtension/target.yml # RiotSwiftUI/Modules/AnalyticsPrompt/AnalyticsPromptViewModel.swift # RiotSwiftUI/Modules/AnalyticsPrompt/Coordinator/AnalyticsPromptCoordinator.swift # RiotSwiftUI/Modules/AnalyticsPrompt/Coordinator/AnalyticsPromptStrings.swift # RiotSwiftUI/Modules/AnalyticsPrompt/MockAnalyticsPromptScreenState.swift # RiotSwiftUI/Modules/AnalyticsPrompt/Test/UI/AnalyticsPromptUITests.swift # RiotSwiftUI/Modules/AnalyticsPrompt/View/AnalyticsPrompt.swift # RiotSwiftUI/Modules/AnalyticsPrompt/View/AnalyticsPromptCheckmarkItem.swift # RiotSwiftUI/Modules/Authentication/Common/AuthenticationHomeserverViewData.swift # RiotSwiftUI/Modules/Authentication/Common/AuthenticationModels.swift # RiotSwiftUI/Modules/Authentication/Common/AuthenticationServerInfoSection.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationRestClient.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationState.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginModels.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginParameters.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginWizard.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationParameters.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationWizard.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/SessionCreator.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/ThreePIDModels.swift # RiotSwiftUI/Modules/Authentication/Login/AuthenticationLoginModels.swift # RiotSwiftUI/Modules/Authentication/Login/Coordinator/AuthenticationLoginCoordinator.swift # RiotSwiftUI/Modules/Authentication/Login/Test/UI/AuthenticationLoginUITests.swift # RiotSwiftUI/Modules/Authentication/Login/Test/Unit/AuthenticationLoginViewModelTests.swift # RiotSwiftUI/Modules/Authentication/Login/View/AuthenticationLoginScreen.swift # RiotSwiftUI/Modules/Authentication/ReCaptcha/Test/UI/AuthenticationReCaptchaUITests.swift # RiotSwiftUI/Modules/Authentication/ReCaptcha/View/AuthenticationReCaptchaScreen.swift # RiotSwiftUI/Modules/Authentication/ReCaptcha/View/AuthenticationReCaptchaWebView.swift # RiotSwiftUI/Modules/Authentication/Registration/AuthenticationRegistrationModels.swift # RiotSwiftUI/Modules/Authentication/Registration/AuthenticationRegistrationViewModel.swift # RiotSwiftUI/Modules/Authentication/Registration/AuthenticationRegistrationViewModelProtocol.swift # RiotSwiftUI/Modules/Authentication/Registration/Coordinator/AuthenticationRegistrationCoordinator.swift # RiotSwiftUI/Modules/Authentication/Registration/MockAuthenticationRegistrationScreenState.swift # RiotSwiftUI/Modules/Authentication/Registration/Test/UI/AuthenticationRegistrationUITests.swift # RiotSwiftUI/Modules/Authentication/Registration/Test/Unit/AuthenticationRegistrationViewModelTests.swift # RiotSwiftUI/Modules/Authentication/Registration/View/AuthenticationRegistrationScreen.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/AuthenticationServerSelectionModels.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/AuthenticationServerSelectionViewModel.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/Coordinator/AuthenticationServerSelectionCoordinator.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/MockAuthenticationServerSelectionScreenState.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/Test/UI/AuthenticationServerSelectionUITests.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/Test/Unit/AuthenticationServerSelectionViewModelTests.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/View/AuthenticationServerSelectionScreen.swift # RiotSwiftUI/Modules/Authentication/Terms/AuthenticationTermsModels.swift # RiotSwiftUI/Modules/Authentication/Terms/AuthenticationTermsViewModel.swift # RiotSwiftUI/Modules/Authentication/Terms/Coordinator/AuthenticationTermsCoordinator.swift # RiotSwiftUI/Modules/Authentication/Terms/MockAuthenticationTermsScreenState.swift # RiotSwiftUI/Modules/Authentication/Terms/Test/UI/AuthenticationTermsUITests.swift # RiotSwiftUI/Modules/Authentication/Terms/View/AuthenticationTermsScreen.swift # RiotSwiftUI/Modules/Authentication/Terms/View/AuthenticationTermsToggleStyle.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailModels.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModel.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/Coordinator/AuthenticationVerifyEmailCoordinator.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/MockAuthenticationVerifyEmailScreenState.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/UI/AuthenticationVerifyEmailUITests.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/Unit/AuthenticationVerifyEmailViewModelTests.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailForm.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailScreen.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/AuthenticationVerifyMsisdnModels.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/AuthenticationVerifyMsisdnViewModel.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/Coordinator/AuthenticationVerifyMsisdnCoordinator.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/MockAuthenticationVerifyMsisdnScreenState.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/Test/UI/AuthenticationVerifyMsisdnUITests.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/Test/Unit/AuthenticationVerifyMsisdnViewModelTests.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/View/AuthenticationVerifyMsisdnForm.swift # RiotSwiftUI/Modules/Common/ActivityIndicator/ActivityIndicator.swift # RiotSwiftUI/Modules/Common/ActivityIndicator/ActivityIndicatorModifier.swift # RiotSwiftUI/Modules/Common/Avatar/Service/MatrixSDK/AvatarService.swift # RiotSwiftUI/Modules/Common/Avatar/Service/Mock/MockAvatarService.swift # RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift # RiotSwiftUI/Modules/Common/Avatar/View/PlaceholderAvatarImage.swift # RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift # RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarServiceProtocol.swift # RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift # RiotSwiftUI/Modules/Common/Bridging/VectorContentView.swift # RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift # RiotSwiftUI/Modules/Common/EffectsScene/EffectsScene.swift # RiotSwiftUI/Modules/Common/EffectsScene/EffectsView.swift # RiotSwiftUI/Modules/Common/Extensions/Publisher.swift # RiotSwiftUI/Modules/Common/Mock/MockAppScreens.swift # RiotSwiftUI/Modules/Common/Mock/MockScreenState.swift # RiotSwiftUI/Modules/Common/Mock/ScreenList.swift # RiotSwiftUI/Modules/Common/Mock/ScreenStateInfo.swift # RiotSwiftUI/Modules/Common/Mock/StateRenderer.swift # RiotSwiftUI/Modules/Common/Test/UI/MockScreenTest.swift # RiotSwiftUI/Modules/Common/Test/UI/XCUIApplication+Riot.swift # RiotSwiftUI/Modules/Common/Test/XCTestPublisherExtensions.swift # RiotSwiftUI/Modules/Common/Theme/ThemeIdentifierExtensions.swift # RiotSwiftUI/Modules/Common/Theme/ThemeKey.swift # RiotSwiftUI/Modules/Common/Theme/ThemePublisher.swift # RiotSwiftUI/Modules/Common/Theme/ThemeSwiftUI.swift # RiotSwiftUI/Modules/Common/Theme/ThemeUsersColorsExtension.swift # RiotSwiftUI/Modules/Common/Theme/Themes/DarkThemeSwiftUI.swift # RiotSwiftUI/Modules/Common/Theme/Themes/DefaultThemeSwiftUI.swift # RiotSwiftUI/Modules/Common/Util/BorderModifier.swift # RiotSwiftUI/Modules/Common/Util/BorderedInputFieldStyle.swift # RiotSwiftUI/Modules/Common/Util/ClearViewModifier.swift # RiotSwiftUI/Modules/Common/Util/InlineTextButton.swift # RiotSwiftUI/Modules/Common/Util/MultilineTextField.swift # RiotSwiftUI/Modules/Common/Util/OptionButton.swift # RiotSwiftUI/Modules/Common/Util/PrimaryActionButtonStyle.swift # RiotSwiftUI/Modules/Common/Util/RadioButton.swift # RiotSwiftUI/Modules/Common/Util/RoundedBorderTextEditor.swift # RiotSwiftUI/Modules/Common/Util/RoundedBorderTextField.swift # RiotSwiftUI/Modules/Common/Util/RoundedCornerShape.swift # RiotSwiftUI/Modules/Common/Util/SafeBindingCollectionEnumerator.swift # RiotSwiftUI/Modules/Common/Util/ScreenTrackerViewModifier.swift # RiotSwiftUI/Modules/Common/Util/SearchBar.swift # RiotSwiftUI/Modules/Common/Util/SecondaryActionButtonStyle.swift # RiotSwiftUI/Modules/Common/Util/StyledText.swift # RiotSwiftUI/Modules/Common/Util/ThemableButton.swift # RiotSwiftUI/Modules/Common/Util/ThemableNavigationBar.swift # RiotSwiftUI/Modules/Common/Util/ThemableTextEditor.swift # RiotSwiftUI/Modules/Common/Util/ThemableTextField.swift # RiotSwiftUI/Modules/Common/Util/WaitOverlay.swift # RiotSwiftUI/Modules/Common/ViewFrameReader/FramePreferenceKey.swift # RiotSwiftUI/Modules/Common/ViewFrameReader/ViewFrameReader.swift # RiotSwiftUI/Modules/Common/ViewModel/StateStoreViewModel.swift # RiotSwiftUI/Modules/Onboarding/Avatar/Coordinator/OnboardingAvatarCoordinator.swift # RiotSwiftUI/Modules/Onboarding/Avatar/MockOnboardingAvatarScreenState.swift # RiotSwiftUI/Modules/Onboarding/Avatar/Test/UI/OnboardingAvatarUITests.swift # RiotSwiftUI/Modules/Onboarding/Avatar/Test/Unit/OnboardingAvatarViewModelTests.swift # RiotSwiftUI/Modules/Onboarding/Celebration/Test/UI/OnboardingCelebrationUITests.swift # RiotSwiftUI/Modules/Onboarding/Celebration/View/OnboardingCelebrationScreen.swift # RiotSwiftUI/Modules/Onboarding/Common/OnboardingIcon.swift # RiotSwiftUI/Modules/Onboarding/Common/OnboardingMetrics.swift # RiotSwiftUI/Modules/Onboarding/Congratulations/OnboardingCongratulationsModels.swift # RiotSwiftUI/Modules/Onboarding/Congratulations/Test/UI/OnboardingCongratulationsUITests.swift # RiotSwiftUI/Modules/Onboarding/Congratulations/View/OnboardingCongratulationsScreen.swift # RiotSwiftUI/Modules/Onboarding/DisplayName/Coordinator/OnboardingDisplayNameCoordinator.swift # RiotSwiftUI/Modules/Onboarding/DisplayName/Test/UI/OnboardingDisplayNameUITests.swift # RiotSwiftUI/Modules/Onboarding/DisplayName/View/OnboardingDisplayNameScreen.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/OnboardingSplashScreenModels.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/View/OnboardingSplashScreen.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/View/OnboardingSplashScreenPage.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/View/OnboardingSplashScreenPageIndicator.swift # RiotSwiftUI/Modules/Onboarding/UseCase/Coordinator/OnboardingUseCaseSelectionCoordinator.swift # RiotSwiftUI/Modules/Onboarding/UseCase/OnboardingUseCaseModels.swift # RiotSwiftUI/Modules/Onboarding/UseCase/Test/UI/OnboardingUseCaseUITests.swift # RiotSwiftUI/Modules/Onboarding/UseCase/View/OnboardingUseCaseSelectionScreen.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Coordinator/LiveLocationSharingViewerCoordinator.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/LiveLocationSharingViewerModels.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/LiveLocationSharingViewerViewModel.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/LiveLocationSharingViewerViewModelProtocol.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/MockLiveLocationSharingViewerScreenState.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Service/LiveLocationSharingViewerServiceProtocol.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Service/MatrixSDK/LiveLocationSharingViewerService.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Service/Mock/MockLiveLocationSharingViewerService.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Test/UI/LiveLocationSharingViewerUITests.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Test/Unit/LiveLocationSharingViewerViewModelTests.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/View/LiveLocationListItem.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/View/LiveLocationSharingViewer.swift # RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift # RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift # RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift # RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingViewModel.swift # RiotSwiftUI/Modules/Room/LocationSharing/Service/MatrixSDK/LocationSharingService.swift # RiotSwiftUI/Modules/Room/LocationSharing/Service/Mock/MockLocationSharingService.swift # RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift # RiotSwiftUI/Modules/Room/LocationSharing/Test/Unit/LocationSharingViewModelTests.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingMapView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingMarkerView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingOptionButton.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/MapCreditsView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/UserLocationAnnotationView.swift # RiotSwiftUI/Modules/Room/NotificationSettings/Coordinator/RoomNotificationSettingsCoordinator.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormItemButtonStyle.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormPickerItem.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionFooter.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionHeader.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettings.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettingsHeader.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/VectorForm.swift # RiotSwiftUI/Modules/Room/NotificationSettings/ViewModel/RoomNotificationSettingsSwiftUIViewModel.swift # RiotSwiftUI/Modules/Room/PollEditForm/Coordinator/PollEditFormCoordinator.swift # RiotSwiftUI/Modules/Room/PollEditForm/PollEditFormScreenState.swift # RiotSwiftUI/Modules/Room/PollEditForm/PollEditFormViewModel.swift # RiotSwiftUI/Modules/Room/PollEditForm/Test/UI/PollEditFormUITests.swift # RiotSwiftUI/Modules/Room/PollEditForm/Test/Unit/PollEditFormViewModelTests.swift # RiotSwiftUI/Modules/Room/PollEditForm/View/PollEditForm.swift # RiotSwiftUI/Modules/Room/PollEditForm/View/PollEditFormAnswerOptionView.swift # RiotSwiftUI/Modules/Room/PollEditForm/View/PollEditFormTypePicker.swift # RiotSwiftUI/Modules/Room/RoomAccess/Coordinator/RoomAccessCoordinator.swift # RiotSwiftUI/Modules/Room/RoomAccess/Coordinator/RoomAccessCoordinatorBridgePresenter.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Coordinator/RoomAccessTypeChooserCoordinator.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/MockRoomAccessTypeChooserScreenState.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/RoomAccessTypeChooserViewModel.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/RoomAccessTypeChooserViewModelProtocol.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Service/MatrixSDK/RoomAccessTypeChooserService.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Service/Mock/MockRoomAccessTypeChooserService.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Service/RoomAccessTypeChooserServiceProtocol.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Test/UI/RoomAccessTypeChooserUITests.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Test/Unit/RoomAccessTypeChooserViewModelTests.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/View/RoomAccessTypeChooser.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/View/RoomAccessTypeChooserRow.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomRestrictedAccessSpaceChooser/Coordinator/RoomRestrictedAccessSpaceChooserViewProvider.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomRestrictedAccessSpaceChooser/View/RoomRestrictedAccessSpaceChooserSelector.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/Coordinator/RoomSuggestionCoordinator.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/Coordinator/RoomSuggestionCoordinatorBridgePresenter.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/RoomSuggestionSpaceChooser/Coordinator/RoomSuggestionSpaceChooserViewProvider.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/RoomSuggestionSpaceChooser/View/RoomSuggestionSpaceChooserSelector.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Coordinator/RoomUpgradeCoordinator.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/MockRoomUpgradeScreenState.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/RoomUpgradeViewModel.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/RoomUpgradeViewModelProtocol.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Service/MatrixSDK/RoomUpgradeService.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Service/Mock/MockRoomUpgradeService.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Service/RoomUpgradeServiceProtocol.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Test/UI/RoomUpgradeUITests.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Test/Unit/RoomUpgradeViewModelTests.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/View/RoomUpgrade.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/Coordinator/StaticLocationViewingCoordinator.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/MockStaticLocationViewingScreenState.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/StaticLocationViewingModels.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/StaticLocationViewingViewModel.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/StaticLocationViewingViewModelProtocol.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/Test/UI/StaticLocationViewingUITests.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/Test/Unit/StaticLocationViewingViewModelTests.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/View/StaticLocationView.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Coordinator/TimelinePollCoordinator.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Coordinator/TimelinePollProvider.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Test/UI/TimelinePollUITests.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Test/Unit/TimelinePollViewModelTests.swift # RiotSwiftUI/Modules/Room/TimelinePoll/TimelinePollScreenState.swift # RiotSwiftUI/Modules/Room/TimelinePoll/TimelinePollViewModel.swift # RiotSwiftUI/Modules/Room/TimelinePoll/TimelinePollViewModelProtocol.swift # RiotSwiftUI/Modules/Room/TimelinePoll/View/TimelinePollAnswerOptionButton.swift # RiotSwiftUI/Modules/Room/TimelinePoll/View/TimelinePollView.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinatorBridge.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionService.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionServiceProtocol.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Test/UI/UserSuggestionUITests.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Test/Unit/UserSuggestionServiceTests.swift # RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionScreenState.swift # RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionViewModel.swift # RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionList.swift # RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListItem.swift # RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListWithInput.swift # RiotSwiftUI/Modules/Settings/Notifications/Coordinator/NotificationSettingsBridgePresenter.swift # RiotSwiftUI/Modules/Settings/Notifications/Coordinator/NotificationSettingsCoordinator.swift # RiotSwiftUI/Modules/Settings/Notifications/Model/NotificationSettingsScreen.swift # RiotSwiftUI/Modules/Settings/Notifications/Service/MatrixSDK/MXNotificationSettingsService.swift # RiotSwiftUI/Modules/Settings/Notifications/Service/Mock/MockNotificationSettingsService.swift # RiotSwiftUI/Modules/Settings/Notifications/Service/NotificationSettingsServiceType.swift # RiotSwiftUI/Modules/Settings/Notifications/View/Chip.swift # RiotSwiftUI/Modules/Settings/Notifications/View/Chips.swift # RiotSwiftUI/Modules/Settings/Notifications/View/ChipsInput.swift # RiotSwiftUI/Modules/Settings/Notifications/View/DefaultNotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/View/FormInputFieldStyle.swift # RiotSwiftUI/Modules/Settings/Notifications/View/MentionsAndKeywordNotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/View/NotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/View/NotificationSettingsKeywords.swift # RiotSwiftUI/Modules/Settings/Notifications/View/OtherNotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/ViewModel/NotificationSettingsViewModel.swift # RiotSwiftUI/Modules/Spaces/AddRoomSelector/Coordinator/AddRoomSelectorViewProvider.swift # RiotSwiftUI/Modules/Spaces/AddRoomSelector/View/AddRoomSelector.swift # RiotSwiftUI/Modules/Spaces/LeaveSpace/Coordinator/LeaveSpaceViewProvider.swift # RiotSwiftUI/Modules/Spaces/LeaveSpace/View/LeaveSpace.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Coordinator/MatrixItemChooserCoordinator.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MatrixItemChooserViewModel.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MatrixItemChooserViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MockMatrixItemChooserScreenState.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Service/MatrixItemChooserServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Service/MatrixSDK/MatrixItemChooserService.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Service/Mock/MockMatrixItemChooserService.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Test/UI/MatrixItemChooserUITests.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Test/Unit/MatrixItemChooserViewModelTests.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooser.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserListRow.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserSectionHeader.swift # RiotSwiftUI/Modules/Spaces/RoomAncestorSelector/Coordinator/RoomAncestorSelectorViewProvider.swift # RiotSwiftUI/Modules/Spaces/RoomAncestorSelector/View/RoomAncestorSelector.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/Coordinator/SpaceCreationCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Coordinator/SpaceCreationEmailInvitesCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/MatrixSDK/SpaceCreationEmailInvitesService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/SpaceCreationEmailInvitesServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Test/UI/SpaceCreationEmailInvitesUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Test/Unit/SpaceCreationEmailInvitesViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/View/SpaceCreationEmailInvites.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/ViewModel/SpaceCreationEmailInvitesViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/ViewModel/SpaceCreationEmailInvitesViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMatrixItemChooser/Coordinator/SpaceCreationMatrixItemChooserViewProvider.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMatrixItemChooser/View/SpaceCreationMatrixItemChooser.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Coordinator/SpaceCreationMenuCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Test/UI/SpaceCreationMenuUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Test/Unit/SpaceCreationMenuViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/View/SpaceCreationMenu.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/ViewModel/SpaceCreationMenuViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/ViewModel/SpaceCreationMenuViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Coordinator/SpaceCreationPostProcessCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/MatrixSDK/SpaceCreationPostProcessService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/SpaceCreationPostProcessServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Test/UI/SpaceCreationPostProcessUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Test/Unit/SpaceCreationPostProcessViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/View/SpaceCreationPostProcess.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/View/SpaceCreationPostProcessItem.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/ViewModel/SpaceCreationPostProcessViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/ViewModel/SpaceCreationPostProcessViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Coordinator/SpaceCreationRoomsCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Service/Mock/MockSpaceCreationRoomsScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Test/UI/SpaceCreationRoomsUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Test/Unit/SpaceCreationRoomsViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/View/SpaceCreationRooms.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/ViewModel/SpaceCreationRoomsViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/ViewModel/SpaceCreationRoomsViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Coordinator/SpaceCreationSettingsCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/MatrixSDK/SpaceCreationSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/SpaceCreationSettingsServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Test/UI/SpaceCreationSettingsUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Test/Unit/SpaceCreationSettingsViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/View/SpaceCreationSettings.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/ViewModel/SpaceCreationSettingsViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinatorBridgePresenter.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Coordinator/SpaceSettingsCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/MockSpaceSettingsScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/Mock/MockSpaceSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/SpaceSettingsServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Test/UI/SpaceSettingsUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Test/Unit/SpaceSettingsViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettings.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettingsOptionListItem.swift # RiotSwiftUI/Modules/Template/SimpleScreenExample/Test/UI/TemplateSimpleScreenUITests.swift # RiotSwiftUI/Modules/Template/SimpleUserProfileExample/Test/UI/TemplateUserProfileUITests.swift # RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/Test/UI/TemplateRoomChatUITests.swift # RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/Test/UI/TemplateRoomListUITests.swift # RiotSwiftUI/RiotSwiftUIApp.swift # RiotSwiftUI/target.yml # RiotSwiftUI/targetUITests.yml # RiotTests/MatrixKitTests/MXKEventFormatter+Tests.h # RiotTests/MatrixKitTests/MXKEventFormatterTests.m # RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift # RiotTests/MatrixKitTests/MatrixKitTests-Bridging-Header.h # RiotTests/Modules/Authentication/AuthenticationServiceTests.swift # RiotTests/OnboardingTests.swift # RiotTests/PillsFormatterTests.swift # RiotTests/target.yml # SiriIntents/IntentHandler.m # SiriIntents/target.yml # Tools/SwiftGen/swiftgen-config.yml # Tools/Templates/buildable/SimpleScreenTemplate/SimpleScreenTemplateViewController.storyboard # fastlane/.env.default # fastlane/Fastfile # project.yml
1884 lines
72 KiB
Objective-C
1884 lines
72 KiB
Objective-C
/*
|
|
Copyright 2020 New Vector Ltd
|
|
Copyright (c) 2021 BWI GmbH
|
|
|
|
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 "SecurityViewController.h"
|
|
|
|
#import "ManageSessionViewController.h"
|
|
|
|
#import <OLMKit/OLMKit.h>
|
|
|
|
#import "AvatarGenerator.h"
|
|
|
|
#import "ThemeService.h"
|
|
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
@import DesignKit;
|
|
|
|
// Dev flag to have more options
|
|
//#define CROSS_SIGNING_AND_BACKUP_DEV
|
|
|
|
enum
|
|
{
|
|
SECTION_PIN_CODE,
|
|
SECTION_CRYPTO_SESSIONS,
|
|
SECTION_SECURE_BACKUP,
|
|
SECTION_CROSSSIGNING,
|
|
SECTION_CRYPTOGRAPHY,
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
SECTION_KEYBACKUP,
|
|
#endif
|
|
SECTION_ADVANCED,
|
|
SECTION_COUNT
|
|
};
|
|
|
|
enum {
|
|
CROSSSIGNING_INFO,
|
|
CROSSSIGNING_FIRST_ACTION, // Bootstrap, Reset, Verify this session, Request keys
|
|
CROSSSIGNING_SECOND_ACTION, // Reset
|
|
};
|
|
|
|
enum {
|
|
PIN_CODE_SETTING,
|
|
PIN_CODE_CHANGE,
|
|
PIN_CODE_BIOMETRICS,
|
|
PIN_CODE_COUNT
|
|
};
|
|
|
|
enum {
|
|
CRYPTOGRAPHY_INFO,
|
|
CRYPTOGRAPHY_EXPORT, // TODO: To move to SECTION_KEYBACKUP
|
|
CRYPTOGRAPHY_COUNT
|
|
};
|
|
|
|
enum {
|
|
ADVANCED_BLACKLIST_UNVERIFIED_DEVICES,
|
|
ADVANCED_COUNT
|
|
};
|
|
|
|
|
|
@interface SecurityViewController () <
|
|
SettingsSecureBackupTableViewSectionDelegate,
|
|
KeyBackupSetupCoordinatorBridgePresenterDelegate,
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
SettingsKeyBackupTableViewSectionDelegate,
|
|
KeyBackupRecoverCoordinatorBridgePresenterDelegate,
|
|
#endif
|
|
UIDocumentInteractionControllerDelegate,
|
|
SecretsRecoveryCoordinatorBridgePresenterDelegate,
|
|
SecureBackupSetupCoordinatorBridgePresenterDelegate,
|
|
SetPinCoordinatorBridgePresenterDelegate,
|
|
TableViewSectionsDelegate>
|
|
{
|
|
// Current alert (if any).
|
|
UIAlertController *currentAlert;
|
|
|
|
// Devices
|
|
NSMutableArray<MXDevice *> *devicesArray;
|
|
|
|
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
|
|
id kThemeServiceDidChangeThemeNotificationObserver;
|
|
|
|
// The view used to export e2e keys
|
|
MXKEncryptionKeysExportView *exportView;
|
|
|
|
// The document interaction Controller used to export e2e keys
|
|
UIDocumentInteractionController *documentInteractionController;
|
|
NSURL *keyExportsFile;
|
|
NSTimer *keyExportsFileDeletionTimer;
|
|
|
|
// The current pushed view controller
|
|
UIViewController *pushedViewController;
|
|
|
|
SettingsSecureBackupTableViewSection *secureBackupSection;
|
|
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
SettingsKeyBackupTableViewSection *keyBackupSection;
|
|
#endif
|
|
|
|
KeyBackupSetupCoordinatorBridgePresenter *keyBackupSetupCoordinatorBridgePresenter;
|
|
KeyBackupRecoverCoordinatorBridgePresenter *keyBackupRecoverCoordinatorBridgePresenter;
|
|
SecretsRecoveryCoordinatorBridgePresenter *secretsRecoveryCoordinatorBridgePresenter;
|
|
}
|
|
|
|
@property (nonatomic, strong) TableViewSections *tableViewSections;
|
|
@property (nonatomic) BOOL isLoadingDevices;
|
|
@property (nonatomic, strong) MXKeyBackupVersion *currentkeyBackupVersion;
|
|
@property (nonatomic, strong) SecureBackupSetupCoordinatorBridgePresenter *secureBackupSetupCoordinatorBridgePresenter;
|
|
@property (nonatomic, strong) SetPinCoordinatorBridgePresenter *setPinCoordinatorBridgePresenter;
|
|
@property (nonatomic, strong) CrossSigningSetupCoordinatorBridgePresenter *crossSigningSetupCoordinatorBridgePresenter;
|
|
|
|
@property (nonatomic) AnalyticsScreenTracker *screenTracker;
|
|
|
|
@end
|
|
|
|
@implementation SecurityViewController
|
|
|
|
#pragma mark - Setup & Teardown
|
|
|
|
+ (SecurityViewController*)instantiateWithMatrixSession:(MXSession*)matrixSession
|
|
{
|
|
SecurityViewController* viewController = [[UIStoryboard storyboardWithName:@"Security" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
|
|
[viewController addMatrixSession:matrixSession];
|
|
return viewController;
|
|
}
|
|
|
|
|
|
#pragma mark - View life cycle
|
|
|
|
- (void)finalizeInit
|
|
{
|
|
[super finalizeInit];
|
|
|
|
// Setup `MXKViewControllerHandling` properties
|
|
self.enableBarTintColorStatusChange = NO;
|
|
self.rageShakeManager = [RageShakeManager sharedManager];
|
|
|
|
self.screenTracker = [[AnalyticsScreenTracker alloc] initWithScreen:AnalyticsScreenSettingsSecurity];
|
|
}
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
// Do any additional setup after loading the view, typically from a nib.
|
|
|
|
self.navigationItem.title = [VectorL10n securitySettingsTitle];
|
|
[self vc_removeBackTitle];
|
|
|
|
[self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]];
|
|
[self.tableView registerNib:MXKTableViewCellWithTextView.nib forCellReuseIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier]];
|
|
[self.tableView registerNib:MXKTableViewCellWithButton.nib forCellReuseIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
|
|
[self.tableView registerNib:SectionFooterView.nib forHeaderFooterViewReuseIdentifier:[SectionFooterView defaultReuseIdentifier]];
|
|
|
|
// Enable self sizing cells and footers
|
|
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
|
self.tableView.estimatedRowHeight = 50;
|
|
self.tableView.sectionFooterHeight = UITableViewAutomaticDimension;
|
|
self.tableView.estimatedSectionFooterHeight = 50;
|
|
|
|
if (self.mainSession.crypto.backup)
|
|
{
|
|
MXDeviceInfo *deviceInfo = [self.mainSession.crypto deviceWithDeviceId:self.mainSession.myDeviceId ofUser:self.mainSession.myUserId];
|
|
|
|
if (deviceInfo)
|
|
{
|
|
secureBackupSection = [[SettingsSecureBackupTableViewSection alloc] initWithRecoveryService:self.mainSession.crypto.recoveryService keyBackup:self.mainSession.crypto.backup userDevice:deviceInfo];
|
|
secureBackupSection.delegate = self;
|
|
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
keyBackupSection = [[SettingsKeyBackupTableViewSection alloc] initWithKeyBackup:self.mainSession.crypto.backup userDevice:deviceInfo];
|
|
keyBackupSection.delegate = self;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Observe user interface theme change.
|
|
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
|
|
[self userInterfaceThemeDidChange];
|
|
|
|
}];
|
|
[self userInterfaceThemeDidChange];
|
|
|
|
[self registerUserDevicesChangesNotification];
|
|
|
|
self.tableViewSections = [TableViewSections new];
|
|
self.tableViewSections.delegate = self;
|
|
|
|
[self updateSections];
|
|
}
|
|
|
|
- (void)userInterfaceThemeDidChange
|
|
{
|
|
[ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar];
|
|
|
|
self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor;
|
|
|
|
// Check the table view style to select its bg color.
|
|
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? ThemeService.shared.theme.backgroundColor : ThemeService.shared.theme.headerBackgroundColor);
|
|
self.view.backgroundColor = self.tableView.backgroundColor;
|
|
self.tableView.separatorColor = ThemeService.shared.theme.lineBreakColor;
|
|
|
|
[self reloadData];
|
|
|
|
[self setNeedsStatusBarAppearanceUpdate];
|
|
}
|
|
|
|
- (UIStatusBarStyle)preferredStatusBarStyle
|
|
{
|
|
return ThemeService.shared.theme.statusBarStyle;
|
|
}
|
|
|
|
- (void)didReceiveMemoryWarning
|
|
{
|
|
[super didReceiveMemoryWarning];
|
|
// Dispose of any resources that can be recreated.
|
|
}
|
|
|
|
- (void)destroy
|
|
{
|
|
// Release the potential pushed view controller
|
|
[self releasePushedViewController];
|
|
|
|
if (documentInteractionController)
|
|
{
|
|
[documentInteractionController dismissPreviewAnimated:NO];
|
|
[documentInteractionController dismissMenuAnimated:NO];
|
|
documentInteractionController = nil;
|
|
}
|
|
|
|
if (kThemeServiceDidChangeThemeNotificationObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:kThemeServiceDidChangeThemeNotificationObserver];
|
|
kThemeServiceDidChangeThemeNotificationObserver = nil;
|
|
}
|
|
|
|
keyBackupSetupCoordinatorBridgePresenter = nil;
|
|
keyBackupRecoverCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
[self.screenTracker trackScreen];
|
|
|
|
// Release the potential pushed view controller
|
|
[self releasePushedViewController];
|
|
|
|
// Refresh display
|
|
[self reloadData];
|
|
|
|
// Refresh the current device information in parallel
|
|
[self loadCurrentDeviceInformation];
|
|
|
|
// Refresh devices in parallel
|
|
[self loadDevices];
|
|
|
|
[self loadCrossSigning];
|
|
}
|
|
|
|
- (void)viewWillDisappear:(BOOL)animated
|
|
{
|
|
[super viewWillDisappear:animated];
|
|
|
|
if (currentAlert)
|
|
{
|
|
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
|
currentAlert = nil;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Internal methods
|
|
|
|
- (void)updateSections
|
|
{
|
|
NSMutableArray<Section*> *sections = [NSMutableArray array];
|
|
|
|
BOOL isSecureBackupRequired = self.mainSession.vc_homeserverConfiguration.encryption.isSecureBackupRequired;
|
|
|
|
// Pin code section
|
|
Section *pinCodeSection = [Section sectionWithTag:SECTION_PIN_CODE];
|
|
|
|
// Header and footer
|
|
if ([PinCodePreferences shared].isBiometricsAvailable)
|
|
{
|
|
pinCodeSection.headerTitle = [VectorL10n pinProtectionSettingsSectionHeaderWithBiometrics:[PinCodePreferences shared].localizedBiometricsName];
|
|
} else {
|
|
pinCodeSection.headerTitle = [VectorL10n pinProtectionSettingsSectionHeader];
|
|
}
|
|
if (PinCodePreferences.shared.isPinSet)
|
|
{
|
|
pinCodeSection.footerTitle = VectorL10n.pinProtectionSettingsSectionFooter;
|
|
}
|
|
|
|
// Rows
|
|
[pinCodeSection addRowWithTag:PIN_CODE_SETTING];
|
|
|
|
if ([PinCodePreferences shared].isPinSet)
|
|
{
|
|
[pinCodeSection addRowWithTag:PIN_CODE_CHANGE];
|
|
}
|
|
|
|
if ([PinCodePreferences shared].isBiometricsAvailable)
|
|
{
|
|
[pinCodeSection addRowWithTag:PIN_CODE_BIOMETRICS];
|
|
}
|
|
|
|
[sections addObject:pinCodeSection];
|
|
|
|
// Crypto sessions section
|
|
|
|
if (RiotSettings.shared.settingsSecurityScreenShowSessions)
|
|
{
|
|
Section *sessionsSection = [Section sectionWithTag:SECTION_CRYPTO_SESSIONS];
|
|
|
|
sessionsSection.headerTitle = [VectorL10n securitySettingsCryptoSessions];
|
|
|
|
if (self.showLoadingDevicesInformation)
|
|
{
|
|
sessionsSection.footerTitle = VectorL10n.securitySettingsCryptoSessionsLoading;
|
|
}
|
|
else
|
|
{
|
|
if (BwiBuildSettings.bwiShowSessionSettingsFooter) {
|
|
sessionsSection.footerTitle = VectorL10n.securitySettingsCryptoSessionsDescription2;
|
|
}
|
|
[sessionsSection addRowsWithCount:devicesArray.count];
|
|
}
|
|
|
|
[sections addObject:sessionsSection];
|
|
}
|
|
|
|
// Secure backup
|
|
|
|
if (!isSecureBackupRequired)
|
|
{
|
|
Section *secureBackupSection = [Section sectionWithTag:SECTION_SECURE_BACKUP];
|
|
secureBackupSection.headerTitle = [VectorL10n securitySettingsSecureBackup];
|
|
secureBackupSection.footerTitle = VectorL10n.securitySettingsSecureBackupDescription;
|
|
|
|
[secureBackupSection addRowsWithCount:self->secureBackupSection.numberOfRows];
|
|
|
|
[sections addObject:secureBackupSection];
|
|
}
|
|
|
|
// Cross-Signing
|
|
|
|
if (!BuildSettings.disableSelfUserVerification) {
|
|
Section *crossSigningSection = [Section sectionWithTag:SECTION_CROSSSIGNING];
|
|
crossSigningSection.headerTitle = [VectorL10n securitySettingsCrosssigning];
|
|
|
|
[crossSigningSection addRowsWithCount:[self numberOfRowsInCrossSigningSection]];
|
|
|
|
[sections addObject:crossSigningSection];
|
|
}
|
|
|
|
// Cryptography
|
|
|
|
Section *cryptographySection = [Section sectionWithTag:SECTION_CRYPTOGRAPHY];
|
|
cryptographySection.headerTitle = [VectorL10n securitySettingsCryptography];
|
|
|
|
if (RiotSettings.shared.settingsSecurityScreenShowCryptographyInfo)
|
|
{
|
|
[cryptographySection addRowWithTag:CRYPTOGRAPHY_INFO];
|
|
}
|
|
|
|
if (RiotSettings.shared.settingsSecurityScreenShowCryptographyExport && !isSecureBackupRequired)
|
|
{
|
|
[cryptographySection addRowWithTag:CRYPTOGRAPHY_EXPORT];
|
|
}
|
|
|
|
if (cryptographySection.rows.count)
|
|
{
|
|
[sections addObject:cryptographySection];
|
|
}
|
|
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
|
|
// Keybackup
|
|
|
|
Section *keybackupSection = [Section sectionWithTag:SECTION_KEYBACKUP];
|
|
keybackupSection.headerTitle = [VectorL10n securitySettingsBackup];
|
|
|
|
[keybackupSection addRowsWithCount:self->keyBackupSection.numberOfRows];
|
|
|
|
[sections addObject:keybackupSection];
|
|
|
|
#endif
|
|
|
|
// Advanced
|
|
|
|
if (RiotSettings.shared.settingsSecurityScreenShowAdvancedUnverifiedDevices)
|
|
{
|
|
Section *advancedSection = [Section sectionWithTag:SECTION_ADVANCED];
|
|
advancedSection.headerTitle = VectorL10n.securitySettingsAdvanced;
|
|
advancedSection.footerTitle = VectorL10n.securitySettingsBlacklistUnverifiedDevicesDescription;
|
|
|
|
[advancedSection addRowWithTag:ADVANCED_BLACKLIST_UNVERIFIED_DEVICES];
|
|
[sections addObject:advancedSection];
|
|
}
|
|
|
|
// Update sections
|
|
|
|
self.tableViewSections.sections = sections;
|
|
}
|
|
|
|
- (BOOL)showLoadingDevicesInformation
|
|
{
|
|
return self.isLoadingDevices && devicesArray.count == 0;
|
|
}
|
|
|
|
- (void)pushViewController:(UIViewController*)viewController
|
|
{
|
|
// Keep ref on pushed view controller
|
|
pushedViewController = viewController;
|
|
[self.navigationController pushViewController:viewController animated:YES];
|
|
}
|
|
|
|
- (void)releasePushedViewController
|
|
{
|
|
if (pushedViewController)
|
|
{
|
|
if ([pushedViewController isKindOfClass:[UINavigationController class]])
|
|
{
|
|
UINavigationController *navigationController = (UINavigationController*)pushedViewController;
|
|
for (id subViewController in navigationController.viewControllers)
|
|
{
|
|
if ([subViewController respondsToSelector:@selector(destroy)])
|
|
{
|
|
[subViewController destroy];
|
|
}
|
|
}
|
|
}
|
|
else if ([pushedViewController respondsToSelector:@selector(destroy)])
|
|
{
|
|
[(id)pushedViewController destroy];
|
|
}
|
|
|
|
pushedViewController = nil;
|
|
}
|
|
}
|
|
|
|
- (void)reset
|
|
{
|
|
// Remove observers
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
- (void)loadCurrentDeviceInformation
|
|
{
|
|
// Refresh the current device information
|
|
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
|
|
[account loadDeviceInformation:^{
|
|
|
|
// Refresh all the table (A slide down animation is observed when we limit the refresh to the concerned section).
|
|
// Note: The use of 'reloadData' handles the case where the account has been logged out.
|
|
[self reloadData];
|
|
|
|
} failure:nil];
|
|
}
|
|
|
|
- (NSAttributedString*)cryptographyInformation
|
|
{
|
|
// TODO Handle multi accounts
|
|
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
|
|
|
|
// Crypto information
|
|
NSMutableAttributedString *cryptoInformationString = [[NSMutableAttributedString alloc]
|
|
initWithString:[VectorL10n settingsCryptoDeviceName]
|
|
attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont systemFontOfSize:17]}];
|
|
[cryptoInformationString appendAttributedString:[[NSMutableAttributedString alloc]
|
|
initWithString:account.device.displayName ? account.device.displayName : @""
|
|
attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont systemFontOfSize:17]}]];
|
|
|
|
[cryptoInformationString appendAttributedString:[[NSMutableAttributedString alloc]
|
|
initWithString:[VectorL10n settingsCryptoDeviceId]
|
|
attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont systemFontOfSize:17]}]];
|
|
[cryptoInformationString appendAttributedString:[[NSMutableAttributedString alloc]
|
|
initWithString:account.device.deviceId ? account.device.deviceId : @""
|
|
attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont systemFontOfSize:17]}]];
|
|
|
|
[cryptoInformationString appendAttributedString:[[NSMutableAttributedString alloc]
|
|
initWithString:[VectorL10n settingsCryptoDeviceKey]
|
|
attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont systemFontOfSize:17]}]];
|
|
NSString *fingerprint = account.mxSession.crypto.deviceEd25519Key;
|
|
if (fingerprint)
|
|
{
|
|
fingerprint = [MXTools addWhiteSpacesToString:fingerprint every:4];
|
|
}
|
|
[cryptoInformationString appendAttributedString:[[NSMutableAttributedString alloc]
|
|
initWithString:fingerprint ? fingerprint : @""
|
|
attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont boldSystemFontOfSize:17]}]];
|
|
|
|
return cryptoInformationString;
|
|
}
|
|
|
|
- (void)loadDevices
|
|
{
|
|
self.isLoadingDevices = YES;
|
|
|
|
// Refresh the account devices list
|
|
MXWeakify(self);
|
|
[self.mainSession.matrixRestClient devices:^(NSArray<MXDevice *> *devices) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
self.isLoadingDevices = NO;
|
|
|
|
if (devices)
|
|
{
|
|
self->devicesArray = [NSMutableArray arrayWithArray:devices];
|
|
|
|
// Sort devices according to the last seen date.
|
|
NSComparator comparator = ^NSComparisonResult(MXDevice *deviceA, MXDevice *deviceB) {
|
|
|
|
if (deviceA.lastSeenTs > deviceB.lastSeenTs)
|
|
{
|
|
return NSOrderedAscending;
|
|
}
|
|
if (deviceA.lastSeenTs < deviceB.lastSeenTs)
|
|
{
|
|
return NSOrderedDescending;
|
|
}
|
|
|
|
return NSOrderedSame;
|
|
};
|
|
|
|
// Sort devices list
|
|
[self->devicesArray sortUsingComparator:comparator];
|
|
}
|
|
else
|
|
{
|
|
self->devicesArray = nil;
|
|
|
|
}
|
|
|
|
// Refresh all the table (A slide down animation is observed when we limit the refresh to the concerned section).
|
|
// Note: The use of 'reloadData' handles the case where the account has been logged out.
|
|
[self reloadData];
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
self.isLoadingDevices = NO;
|
|
|
|
// Display the data that has been loaded last time
|
|
// Note: The use of 'reloadData' handles the case where the account has been logged out.
|
|
[self reloadData];
|
|
|
|
}];
|
|
}
|
|
|
|
- (void)reloadData
|
|
{
|
|
// Update table view sections and trigger a tableView reloadData
|
|
[self updateSections];
|
|
}
|
|
|
|
|
|
#pragma mark - Data update
|
|
|
|
- (void)registerUserDevicesChangesNotification
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(onDeviceInfoTrustLevelDidChangeNotification:)
|
|
name:MXDeviceInfoTrustLevelDidChangeNotification
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(crossSigningInfoTrustLevelDidChangeNotification:)
|
|
name:MXCrossSigningInfoTrustLevelDidChangeNotification
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(onDidUpdateUsersDevicesNotification:)
|
|
name:MXDeviceListDidUpdateUsersDevicesNotification
|
|
object:nil];
|
|
}
|
|
|
|
- (void)onDidUpdateUsersDevicesNotification:(NSNotification*)notification
|
|
{
|
|
NSDictionary *usersDevices = notification.userInfo;
|
|
|
|
if ([usersDevices.allKeys containsObject:self.mainSession.myUserId])
|
|
{
|
|
[self loadDevices];
|
|
}
|
|
}
|
|
|
|
- (void)onDeviceInfoTrustLevelDidChangeNotification:(NSNotification*)notification
|
|
{
|
|
MXDeviceInfo *deviceInfo = notification.object;
|
|
|
|
NSString *userId = deviceInfo.userId;
|
|
if ([userId isEqualToString:self.mainSession.myUserId])
|
|
{
|
|
[self loadDevices];
|
|
}
|
|
}
|
|
|
|
- (void)crossSigningInfoTrustLevelDidChangeNotification:(NSNotification*)notification
|
|
{
|
|
MXCrossSigningInfo *crossSigningInfo = notification.object;
|
|
|
|
NSString *userId = crossSigningInfo.userId;
|
|
if ([userId isEqualToString:self.mainSession.myUserId])
|
|
{
|
|
[self loadDevices];
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - Cross-signing
|
|
|
|
- (void)loadCrossSigning
|
|
{
|
|
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
|
|
|
|
[crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) {
|
|
if (stateUpdated)
|
|
{
|
|
[self reloadData];
|
|
}
|
|
} failure:^(NSError * _Nonnull error) {
|
|
MXLogDebug(@"[SecurityVC] loadCrossSigning: Cannot refresh cross-signing state. Error: %@", error);
|
|
}];
|
|
}
|
|
|
|
- (NSInteger)numberOfRowsInCrossSigningSection
|
|
{
|
|
NSInteger numberOfRowsInCrossSigningSection;
|
|
|
|
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
|
|
switch (crossSigning.state)
|
|
{
|
|
case MXCrossSigningStateNotBootstrapped: // Action: Bootstrap
|
|
case MXCrossSigningStateCanCrossSign: // Action: Reset
|
|
numberOfRowsInCrossSigningSection = CROSSSIGNING_FIRST_ACTION + 1;
|
|
break;
|
|
case MXCrossSigningStateCrossSigningExists: // Actions: Verify this session, Reset
|
|
case MXCrossSigningStateTrustCrossSigning: // Actions: Request keys, Reset
|
|
numberOfRowsInCrossSigningSection = CROSSSIGNING_SECOND_ACTION + 1;
|
|
break;
|
|
}
|
|
|
|
return numberOfRowsInCrossSigningSection;
|
|
}
|
|
|
|
- (NSAttributedString*)crossSigningInformation
|
|
{
|
|
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
|
|
|
|
NSString *crossSigningInformation;
|
|
switch (crossSigning.state)
|
|
{
|
|
case MXCrossSigningStateNotBootstrapped:
|
|
crossSigningInformation = [VectorL10n securitySettingsCrosssigningInfoNotBootstrapped];
|
|
break;
|
|
case MXCrossSigningStateCrossSigningExists:
|
|
crossSigningInformation = [VectorL10n securitySettingsCrosssigningInfoExists];
|
|
break;
|
|
case MXCrossSigningStateTrustCrossSigning:
|
|
crossSigningInformation = [VectorL10n securitySettingsCrosssigningInfoTrusted];
|
|
break;
|
|
case MXCrossSigningStateCanCrossSign:
|
|
crossSigningInformation = [VectorL10n securitySettingsCrosssigningInfoOk];
|
|
|
|
if (![self.mainSession.crypto.recoveryService hasSecretLocally:MXSecretId.crossSigningMaster])
|
|
{
|
|
crossSigningInformation = [crossSigningInformation stringByAppendingString:@"\n\n⚠️ The MSK is missing. Verify this device again or use the Secure Backup below to synchronise your keys accross your devices"];
|
|
}
|
|
break;
|
|
}
|
|
|
|
return [[NSAttributedString alloc] initWithString:crossSigningInformation
|
|
attributes:@{
|
|
NSForegroundColorAttributeName : ThemeService.shared.theme.textPrimaryColor,
|
|
NSFontAttributeName: [UIFont systemFontOfSize:17]
|
|
}];
|
|
}
|
|
|
|
- (UITableViewCell*)crossSigningButtonCellInTableView:(UITableView*)tableView forAction:(NSInteger)action
|
|
{
|
|
// Get a button cell
|
|
MXKTableViewCellWithButton *buttonCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
|
|
if (!buttonCell)
|
|
{
|
|
buttonCell = [[MXKTableViewCellWithButton alloc] init];
|
|
}
|
|
|
|
[buttonCell.mxkButton setTintColor:ThemeService.shared.theme.tintColor];
|
|
buttonCell.mxkButton.titleLabel.font = [UIFont systemFontOfSize:17];
|
|
|
|
[buttonCell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
|
|
buttonCell.mxkButton.accessibilityIdentifier = nil;
|
|
|
|
// And customise it
|
|
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
|
|
switch (crossSigning.state)
|
|
{
|
|
case MXCrossSigningStateNotBootstrapped: // Action: Bootstrap
|
|
[self setUpcrossSigningButtonCellForBootstrap:buttonCell];
|
|
break;
|
|
case MXCrossSigningStateCanCrossSign: // Action: Reset
|
|
[self setUpcrossSigningButtonCellForReset:buttonCell];
|
|
break;
|
|
case MXCrossSigningStateCrossSigningExists: // Actions: Verify this session, Reset
|
|
switch (action)
|
|
{
|
|
case CROSSSIGNING_FIRST_ACTION:
|
|
[self setUpcrossSigningButtonCellForCompletingSecurity:buttonCell];
|
|
break;
|
|
case CROSSSIGNING_SECOND_ACTION:
|
|
[self setUpcrossSigningButtonCellForReset:buttonCell];
|
|
break;
|
|
}
|
|
break;
|
|
case MXCrossSigningStateTrustCrossSigning: // Actions: Request keys, Reset
|
|
switch (action)
|
|
{
|
|
case CROSSSIGNING_FIRST_ACTION:
|
|
// By verifying our device again, it will get cross-signing keys by gossiping
|
|
[self setUpcrossSigningButtonCellForCompletingSecurity:buttonCell];
|
|
break;
|
|
case CROSSSIGNING_SECOND_ACTION:
|
|
[self setUpcrossSigningButtonCellForReset:buttonCell];
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return buttonCell;
|
|
}
|
|
|
|
- (void)setUpcrossSigningButtonCellForBootstrap:(MXKTableViewCellWithButton*)buttonCell
|
|
{
|
|
NSString *btnTitle = [VectorL10n securitySettingsCrosssigningBootstrap];
|
|
[buttonCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
|
[buttonCell.mxkButton setTitle:btnTitle forState:UIControlStateHighlighted];
|
|
|
|
[buttonCell.mxkButton addTarget:self action:@selector(setupCrossSigning:) forControlEvents:UIControlEventTouchUpInside];
|
|
}
|
|
|
|
- (void)setupCrossSigning:(id)sender
|
|
{
|
|
[self setupCrossSigningWithTitle:@"Set up cross-signing" // TODO
|
|
message:[VectorL10n securitySettingsUserPasswordDescription]
|
|
success:^{
|
|
} failure:^(NSError *error) {
|
|
}];
|
|
}
|
|
|
|
- (void)setupCrossSigningWithTitle:(NSString*)title
|
|
message:(NSString*)message
|
|
success:(void (^)(void))success
|
|
failure:(void (^)(NSError *error))failure
|
|
|
|
{
|
|
[self startActivityIndicator];
|
|
|
|
MXWeakify(self);
|
|
|
|
void (^animationCompletion)(void) = ^void () {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
[self stopActivityIndicator];
|
|
[self.crossSigningSetupCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{}];
|
|
self.crossSigningSetupCoordinatorBridgePresenter = nil;
|
|
};
|
|
|
|
CrossSigningSetupCoordinatorBridgePresenter *crossSigningSetupCoordinatorBridgePresenter = [[CrossSigningSetupCoordinatorBridgePresenter alloc] initWithSession:self.mainSession];
|
|
|
|
[crossSigningSetupCoordinatorBridgePresenter presentWith:title
|
|
message:message
|
|
from:self
|
|
animated:YES
|
|
success:^{
|
|
animationCompletion();
|
|
[self reloadData];
|
|
success();
|
|
} cancel:^{
|
|
animationCompletion();
|
|
failure(nil);
|
|
} failure:^(NSError * _Nonnull error) {
|
|
animationCompletion();
|
|
[self reloadData];
|
|
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
|
failure(error);
|
|
}];
|
|
|
|
self.crossSigningSetupCoordinatorBridgePresenter = crossSigningSetupCoordinatorBridgePresenter;
|
|
}
|
|
|
|
- (void)resetCrossSigning:(id)sender
|
|
{
|
|
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
|
|
|
// Double confirmation
|
|
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Are you sure?" // TODO
|
|
message:@"Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from." // TODO
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Reset"
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action)
|
|
{
|
|
// Setup and reset are the same thing
|
|
[self setupCrossSigning:nil];
|
|
}]];
|
|
|
|
[alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
|
style:UIAlertActionStyleCancel
|
|
handler:nil]];
|
|
|
|
[self presentViewController:alertController animated:YES completion:nil];
|
|
currentAlert = alertController;
|
|
}
|
|
|
|
- (void)setUpcrossSigningButtonCellForReset:(MXKTableViewCellWithButton*)buttonCell
|
|
{
|
|
NSString *btnTitle = [VectorL10n securitySettingsCrosssigningReset];
|
|
[buttonCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
|
[buttonCell.mxkButton setTitle:btnTitle forState:UIControlStateHighlighted];
|
|
|
|
buttonCell.mxkButton.tintColor = ThemeService.shared.theme.warningColor;
|
|
|
|
[buttonCell.mxkButton addTarget:self action:@selector(resetCrossSigning:) forControlEvents:UIControlEventTouchUpInside];
|
|
}
|
|
|
|
- (void)setUpcrossSigningButtonCellForCompletingSecurity:(MXKTableViewCellWithButton*)buttonCell
|
|
{
|
|
NSString *btnTitle = [VectorL10n securitySettingsCrosssigningCompleteSecurity];
|
|
[buttonCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
|
[buttonCell.mxkButton setTitle:btnTitle forState:UIControlStateHighlighted];
|
|
|
|
[buttonCell.mxkButton addTarget:self action:@selector(presentCompleteSecurity) forControlEvents:UIControlEventTouchUpInside];
|
|
}
|
|
|
|
- (void)displayComingSoon
|
|
{
|
|
[[AppDelegate theDelegate] showAlertWithTitle:nil message:[VectorL10n securitySettingsComingSoon:AppInfo.current.displayName :AppInfo.current.displayName]];
|
|
}
|
|
|
|
|
|
#pragma mark - SSSS
|
|
|
|
- (NSString*)secureBackupInformation
|
|
{
|
|
NSString *secureBackupInformation;
|
|
|
|
MXRecoveryService *recoveryService = self.mainSession.crypto.recoveryService;
|
|
|
|
if (recoveryService.hasRecovery)
|
|
{
|
|
NSMutableString *mutableString = [@"Your account has a Secure Backup.\n" mutableCopy];
|
|
|
|
// Check all keys that should be in the SSSSS
|
|
// TODO: Check obsoletes ones but need spec update
|
|
|
|
BOOL hasWarning = NO;
|
|
NSString *keyState = [self informationForSecret:MXSecretId.crossSigningMaster secretName:@"Cross-signing" hasWarning:&hasWarning];
|
|
if (keyState)
|
|
{
|
|
[mutableString appendString:keyState];
|
|
}
|
|
|
|
keyState = [self informationForSecret:MXSecretId.crossSigningSelfSigning secretName:@"Self signing" hasWarning:&hasWarning];
|
|
if (keyState)
|
|
{
|
|
[mutableString appendString:keyState];
|
|
}
|
|
|
|
keyState = [self informationForSecret:MXSecretId.crossSigningUserSigning secretName:@"User signing" hasWarning:&hasWarning];
|
|
if (keyState)
|
|
{
|
|
[mutableString appendString:keyState];
|
|
}
|
|
|
|
keyState = [self informationForSecret:MXSecretId.keyBackup secretName:@"Message Backup" hasWarning:&hasWarning];
|
|
if (keyState)
|
|
{
|
|
[mutableString appendString:keyState];
|
|
}
|
|
else
|
|
{
|
|
if (self.mainSession.crypto.backup.keyBackupVersion)
|
|
{
|
|
[mutableString appendString:@"\n\n⚠️ The key of your current Message backup is not in the Secure Backup. Restore it first (see below)."];
|
|
}
|
|
else
|
|
{
|
|
[mutableString appendString:@"\n\n⚠️ Consider create a Message Backup (see below)."];
|
|
}
|
|
}
|
|
|
|
if (!hasWarning)
|
|
{
|
|
[mutableString appendFormat:@"\n\nIf you are facing an issue, synchronise your Secure Backup."];
|
|
}
|
|
|
|
secureBackupInformation = mutableString;
|
|
}
|
|
else
|
|
{
|
|
if (self.canSetupSecureBackup)
|
|
{
|
|
secureBackupInformation = [NSString stringWithFormat:@"No Secure Backup. Create one.\n-----\nKeys to back up: %@", recoveryService.secretsStoredLocally];
|
|
}
|
|
else
|
|
{
|
|
secureBackupInformation = [NSString stringWithFormat:@"No Secure Backup. Set up cross-signing first (see above)"];
|
|
}
|
|
}
|
|
|
|
return secureBackupInformation;
|
|
}
|
|
|
|
- (nullable NSString*)informationForSecret:(NSString*)secretId secretName:(NSString*)secretName hasWarning:(BOOL*)hasWarning
|
|
{
|
|
NSString *information;
|
|
|
|
MXRecoveryService *recoveryService = self.mainSession.crypto.recoveryService;
|
|
|
|
if ([recoveryService hasSecretWithSecretId:secretId])
|
|
{
|
|
if ([recoveryService hasSecretLocally:secretId])
|
|
{
|
|
information = [NSString stringWithFormat:@"\n ✅ %@ is in the backup", secretName];
|
|
}
|
|
else
|
|
{
|
|
information = [NSString stringWithFormat:@"\n ⚠️ %@ is in the backup but not locally. Tap Synchronise", secretName];
|
|
*hasWarning |= YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ([recoveryService hasSecretLocally:secretId])
|
|
{
|
|
information = [NSString stringWithFormat:@"\n ⚠️ %@ is not in the backup. Tap Synchronise", secretName];
|
|
*hasWarning |= YES;
|
|
}
|
|
}
|
|
|
|
return information;
|
|
}
|
|
|
|
- (BOOL)canSetupSecureBackup
|
|
{
|
|
// Accept to create a setup only if we have the 3 cross-signing keys
|
|
// This is the path to have a sane state
|
|
MXRecoveryService *recoveryService = self.mainSession.crypto.recoveryService;
|
|
|
|
NSArray *crossSigningServiceSecrets = @[
|
|
MXSecretId.crossSigningMaster,
|
|
MXSecretId.crossSigningSelfSigning,
|
|
MXSecretId.crossSigningUserSigning];
|
|
|
|
return ([recoveryService.secretsStoredLocally mx_intersectArray:crossSigningServiceSecrets].count
|
|
== crossSigningServiceSecrets.count);
|
|
}
|
|
|
|
- (void)setupSecureBackup
|
|
{
|
|
if (self.canSetupSecureBackup)
|
|
{
|
|
[self setupSecureBackup2];
|
|
}
|
|
else
|
|
{
|
|
// Set up cross-signing first
|
|
[self setupCrossSigningWithTitle:[VectorL10n secureKeyBackupSetupIntroTitle]
|
|
message:[VectorL10n securitySettingsUserPasswordDescription]
|
|
success:^{
|
|
[self setupSecureBackup2];
|
|
} failure:^(NSError *error) {
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)setupSecureBackup2
|
|
{
|
|
SecureBackupSetupCoordinatorBridgePresenter *secureBackupSetupCoordinatorBridgePresenter = [[SecureBackupSetupCoordinatorBridgePresenter alloc] initWithSession:self.mainSession allowOverwrite:YES];
|
|
secureBackupSetupCoordinatorBridgePresenter.delegate = self;
|
|
|
|
[secureBackupSetupCoordinatorBridgePresenter presentFrom:self animated:YES];
|
|
|
|
self.secureBackupSetupCoordinatorBridgePresenter = secureBackupSetupCoordinatorBridgePresenter;
|
|
}
|
|
|
|
|
|
#pragma mark - Segues
|
|
|
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
|
{
|
|
// Keep ref on destinationViewController
|
|
[super prepareForSegue:segue sender:sender];
|
|
|
|
// FIXME add night mode
|
|
}
|
|
|
|
#pragma mark - UITableView data source
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
|
{
|
|
return self.tableViewSections.sections.count;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
{
|
|
Section *tableSection = [self.tableViewSections sectionAtIndex:section];
|
|
return tableSection.rows.count;
|
|
}
|
|
|
|
- (MXKTableViewCellWithLabelAndSwitch*)getLabelAndSwitchCell:(UITableView*)tableView forIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
MXKTableViewCellWithLabelAndSwitch *cell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath];
|
|
|
|
cell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
|
|
cell.mxkSwitchTrailingConstraint.constant = 15;
|
|
|
|
cell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
|
|
[cell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventValueChanged];
|
|
|
|
// Force layout before reusing a cell (fix switch displayed outside the screen)
|
|
[cell layoutIfNeeded];
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (MXKTableViewCell*)getDefaultTableViewCell:(UITableView*)tableView
|
|
{
|
|
MXKTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCell defaultReuseIdentifier]];
|
|
if (!cell)
|
|
{
|
|
cell = [[MXKTableViewCell alloc] init];
|
|
}
|
|
else
|
|
{
|
|
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
|
|
cell.accessoryType = UITableViewCellAccessoryNone;
|
|
cell.accessoryView = nil;
|
|
cell.imageView.image = nil;
|
|
}
|
|
cell.textLabel.accessibilityIdentifier = nil;
|
|
cell.textLabel.font = [UIFont systemFontOfSize:17];
|
|
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
cell.contentView.backgroundColor = UIColor.clearColor;
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (MXKTableViewCell*)deviceCellWithDevice:(MXDevice*)device forTableView:(UITableView*)tableView
|
|
{
|
|
MXKTableViewCell *cell = [self getDefaultTableViewCell:tableView];
|
|
NSString *name = device.displayName;
|
|
NSString *deviceId = device.deviceId;
|
|
cell.textLabel.text = (name.length ? [NSString stringWithFormat:@"%@ (%@)", name, deviceId] : [NSString stringWithFormat:@"(%@)", deviceId]);
|
|
cell.textLabel.numberOfLines = 0;
|
|
[cell vc_setAccessoryDisclosureIndicatorWithCurrentTheme];
|
|
|
|
if ([deviceId isEqualToString:self.mainSession.matrixRestClient.credentials.deviceId])
|
|
{
|
|
cell.textLabel.font = [UIFont boldSystemFontOfSize:17];
|
|
}
|
|
|
|
cell.imageView.image = [self shieldImageForDevice:deviceId];
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (UIImage*)shieldImageForDevice:(NSString*)deviceId
|
|
{
|
|
if (!self.mainSession.crypto.crossSigning.canCrossSign)
|
|
{
|
|
if ([deviceId isEqualToString:self.mainSession.myDeviceId])
|
|
{
|
|
return AssetImages.encryptionWarning.image;
|
|
}
|
|
else
|
|
{
|
|
return AssetImages.encryptionNormal.image;
|
|
}
|
|
}
|
|
|
|
UIImage* shieldImageForDevice = AssetImages.encryptionWarning.image;
|
|
MXDeviceInfo *device = [self.mainSession.crypto deviceWithDeviceId:deviceId ofUser:self.mainSession.myUser.userId];
|
|
if (device.trustLevel.isVerified)
|
|
{
|
|
shieldImageForDevice = AssetImages.encryptionTrusted.image;
|
|
}
|
|
|
|
return shieldImageForDevice;
|
|
}
|
|
|
|
- (MXKTableViewCellWithTextView*)textViewCellForTableView:(UITableView*)tableView atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
MXKTableViewCellWithTextView *textViewCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier] forIndexPath:indexPath];
|
|
|
|
textViewCell.mxkTextView.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
textViewCell.mxkTextView.font = [UIFont systemFontOfSize:17];
|
|
textViewCell.mxkTextView.backgroundColor = [UIColor clearColor];
|
|
textViewCell.mxkTextViewLeadingConstraint.constant = tableView.vc_separatorInset.left;
|
|
textViewCell.mxkTextViewTrailingConstraint.constant = tableView.vc_separatorInset.right;
|
|
textViewCell.mxkTextView.accessibilityIdentifier = nil;
|
|
|
|
return textViewCell;
|
|
}
|
|
|
|
- (MXKTableViewCellWithButton *)buttonCellForTableView:(UITableView*)tableView atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
MXKTableViewCellWithButton *cell = [self.tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath];
|
|
|
|
if (!cell)
|
|
{
|
|
cell = [[MXKTableViewCellWithButton alloc] init];
|
|
}
|
|
else
|
|
{
|
|
// Fix https://github.com/vector-im/riot-ios/issues/1354
|
|
cell.mxkButton.titleLabel.text = nil;
|
|
cell.mxkButton.enabled = YES;
|
|
}
|
|
|
|
cell.mxkButton.titleLabel.font = [UIFont systemFontOfSize:17];
|
|
[cell.mxkButton setTintColor:ThemeService.shared.theme.tintColor];
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (MXKTableViewCellWithButton *)buttonCellWithTitle:(NSString*)title
|
|
action:(SEL)action
|
|
forTableView:(UITableView*)tableView
|
|
atIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
MXKTableViewCellWithButton *cell = [self buttonCellForTableView:tableView atIndexPath:indexPath];
|
|
|
|
|
|
[cell.mxkButton setTitle:title forState:UIControlStateNormal];
|
|
[cell.mxkButton setTitle:title forState:UIControlStateHighlighted];
|
|
|
|
[cell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
|
|
[cell.mxkButton addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
|
|
cell.mxkButton.accessibilityIdentifier = nil;
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
NSIndexPath *tagsIndexPath = [self.tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
|
|
NSInteger sectionTag = tagsIndexPath.section;
|
|
NSInteger rowTag = tagsIndexPath.row;
|
|
|
|
// set the cell to a default value to avoid application crashes
|
|
UITableViewCell *cell = [[UITableViewCell alloc] init];
|
|
cell.backgroundColor = [UIColor redColor];
|
|
|
|
MXSession* session = self.mainSession;
|
|
if (sectionTag == SECTION_PIN_CODE)
|
|
{
|
|
if (rowTag == PIN_CODE_SETTING)
|
|
{
|
|
if ([PinCodePreferences shared].forcePinProtection)
|
|
{
|
|
cell = [self getDefaultTableViewCell:tableView];
|
|
cell.textLabel.text = [VectorL10n pinProtectionSettingsEnabledForced];
|
|
}
|
|
else
|
|
{
|
|
MXKTableViewCellWithLabelAndSwitch *switchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
|
|
|
|
switchCell.mxkLabel.text = [VectorL10n pinProtectionSettingsEnablePin];
|
|
switchCell.mxkSwitch.on = [PinCodePreferences shared].isPinSet;
|
|
[switchCell.mxkSwitch addTarget:self action:@selector(enablePinCodeSwitchValueChanged:) forControlEvents:UIControlEventValueChanged];
|
|
|
|
cell = switchCell;
|
|
}
|
|
|
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
}
|
|
else if (rowTag == PIN_CODE_CHANGE)
|
|
{
|
|
cell = [self buttonCellWithTitle:[VectorL10n pinProtectionSettingsChangePin] action:@selector(changePinCode:) forTableView:tableView atIndexPath:indexPath];
|
|
}
|
|
else if (rowTag == PIN_CODE_BIOMETRICS)
|
|
{
|
|
MXKTableViewCellWithLabelAndSwitch *switchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
|
|
|
|
switchCell.mxkLabel.text = [VectorL10n biometricsSettingsEnableX:[PinCodePreferences shared].localizedBiometricsName];
|
|
switchCell.mxkSwitch.on = [PinCodePreferences shared].isBiometricsSet;
|
|
switchCell.mxkSwitch.enabled = [PinCodePreferences shared].isBiometricsAvailable;
|
|
[switchCell.mxkSwitch addTarget:self action:@selector(enableBiometricsSwitchValueChanged:) forControlEvents:UIControlEventValueChanged];
|
|
|
|
cell = switchCell;
|
|
}
|
|
}
|
|
else if (sectionTag == SECTION_CRYPTO_SESSIONS)
|
|
{
|
|
cell = [self deviceCellWithDevice:devicesArray[rowTag] forTableView:tableView];
|
|
}
|
|
else if (sectionTag == SECTION_SECURE_BACKUP)
|
|
{
|
|
cell = [secureBackupSection cellForRowAtRow:rowTag];
|
|
}
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
else if (section == SECTION_KEYBACKUP)
|
|
{
|
|
cell = [keyBackupSection cellForRowAtRow:row];
|
|
}
|
|
#endif
|
|
else if (sectionTag == SECTION_CROSSSIGNING)
|
|
{
|
|
switch (rowTag)
|
|
{
|
|
case CROSSSIGNING_INFO:
|
|
{
|
|
MXKTableViewCellWithTextView *cryptoCell = [self textViewCellForTableView:tableView atIndexPath:indexPath];
|
|
cryptoCell.mxkTextView.attributedText = [self crossSigningInformation];
|
|
cell = cryptoCell;
|
|
break;
|
|
}
|
|
case CROSSSIGNING_FIRST_ACTION:
|
|
cell = [self crossSigningButtonCellInTableView:tableView forAction:CROSSSIGNING_FIRST_ACTION];
|
|
break;
|
|
case CROSSSIGNING_SECOND_ACTION:
|
|
cell = [self crossSigningButtonCellInTableView:tableView forAction:CROSSSIGNING_SECOND_ACTION];
|
|
break;
|
|
}
|
|
}
|
|
else if (sectionTag == SECTION_CRYPTOGRAPHY)
|
|
{
|
|
switch (rowTag)
|
|
{
|
|
case CRYPTOGRAPHY_INFO:
|
|
{
|
|
MXKTableViewCellWithTextView *cryptoCell = [self textViewCellForTableView:tableView atIndexPath:indexPath];
|
|
cryptoCell.mxkTextView.attributedText = [self cryptographyInformation];
|
|
cell = cryptoCell;
|
|
break;
|
|
}
|
|
case CRYPTOGRAPHY_EXPORT:
|
|
{
|
|
MXKTableViewCellWithButton *exportKeysBtnCell = [self buttonCellWithTitle:[VectorL10n securitySettingsExportKeysManually]
|
|
action:@selector(exportEncryptionKeys:)
|
|
forTableView:tableView
|
|
atIndexPath:indexPath];
|
|
cell = exportKeysBtnCell;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (sectionTag == SECTION_ADVANCED)
|
|
{
|
|
switch (rowTag)
|
|
{
|
|
case ADVANCED_BLACKLIST_UNVERIFIED_DEVICES:
|
|
{
|
|
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
|
|
|
|
labelAndSwitchCell.mxkLabel.text = [VectorL10n securitySettingsBlacklistUnverifiedDevices];
|
|
labelAndSwitchCell.mxkSwitch.on = session.crypto.globalBlacklistUnverifiedDevices;
|
|
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
|
labelAndSwitchCell.mxkSwitch.enabled = YES;
|
|
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleBlacklistUnverifiedDevices:) forControlEvents:UIControlEventValueChanged];
|
|
|
|
cell = labelAndSwitchCell;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
|
{
|
|
Section *tableSection = [self.tableViewSections sectionAtIndex:section];
|
|
return tableSection.headerTitle;
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
|
|
{
|
|
if ([view isKindOfClass:UITableViewHeaderFooterView.class])
|
|
{
|
|
// Customize label style
|
|
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
|
|
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent;
|
|
tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote;
|
|
}
|
|
}
|
|
|
|
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
|
|
{
|
|
NSString *footerTitle = [_tableViewSections sectionAtIndex:section].footerTitle;
|
|
|
|
if (!footerTitle)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
SectionFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionFooterView.defaultReuseIdentifier];
|
|
[view updateWithTheme:ThemeService.shared.theme];
|
|
view.leadingInset = tableView.vc_separatorInset.left;
|
|
[view updateWithText:footerTitle];
|
|
|
|
return view;
|
|
}
|
|
|
|
#pragma mark - UITableView delegate
|
|
|
|
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
|
|
{
|
|
cell.backgroundColor = ThemeService.shared.theme.backgroundColor;
|
|
|
|
if (cell.selectionStyle != UITableViewCellSelectionStyleNone)
|
|
{
|
|
// Update the selected background view
|
|
if (ThemeService.shared.theme.selectedBackgroundColor)
|
|
{
|
|
cell.selectedBackgroundView = [[UIView alloc] init];
|
|
cell.selectedBackgroundView.backgroundColor = ThemeService.shared.theme.selectedBackgroundColor;
|
|
}
|
|
else
|
|
{
|
|
if (tableView.style == UITableViewStylePlain)
|
|
{
|
|
cell.selectedBackgroundView = nil;
|
|
}
|
|
else
|
|
{
|
|
cell.selectedBackgroundView.backgroundColor = nil;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (self.tableView == tableView)
|
|
{
|
|
NSIndexPath *tagsIndexPath = [self.tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
|
|
NSInteger section = tagsIndexPath.section;
|
|
NSInteger row = tagsIndexPath.row;
|
|
|
|
if (section == SECTION_CRYPTO_SESSIONS)
|
|
{
|
|
NSUInteger deviceIndex = row;
|
|
if (deviceIndex < devicesArray.count)
|
|
{
|
|
MXDevice *device = devicesArray[deviceIndex];
|
|
|
|
if (self.mainSession.crypto.crossSigning.state == MXCrossSigningStateNotBootstrapped)
|
|
{
|
|
// Display the device details. The verification will fail there.
|
|
ManageSessionViewController *viewController = [ManageSessionViewController instantiateWithMatrixSession:self.mainSession andDevice:device];
|
|
|
|
[self pushViewController:viewController];
|
|
}
|
|
else if (self.mainSession.crypto.crossSigning.canCrossSign)
|
|
{
|
|
ManageSessionViewController *viewController = [ManageSessionViewController instantiateWithMatrixSession:self.mainSession andDevice:device];
|
|
|
|
[self pushViewController:viewController];
|
|
}
|
|
else
|
|
{
|
|
if ([device.deviceId isEqualToString:self.mainSession.matrixRestClient.credentials.deviceId])
|
|
{
|
|
[self presentCompleteSecurity];
|
|
}
|
|
else
|
|
{
|
|
[self presentShouldCompleteSecurityAlert];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
}
|
|
}
|
|
|
|
- (void)presentCompleteSecurity
|
|
{
|
|
[[AppDelegate theDelegate] presentCompleteSecurityForSession:self.mainSession];
|
|
}
|
|
|
|
- (void)presentShouldCompleteSecurityAlert
|
|
{
|
|
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
|
|
|
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[VectorL10n securitySettingsCompleteSecurityAlertTitle]
|
|
message:[VectorL10n securitySettingsCompleteSecurityAlertMessage]
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
[self presentCompleteSecurity];
|
|
}]];
|
|
|
|
[alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n later]
|
|
style:UIAlertActionStyleCancel
|
|
handler:nil]];
|
|
|
|
[self presentViewController:alertController animated:YES completion:nil];
|
|
currentAlert = alertController;
|
|
[currentAlert mxk_setAccessibilityIdentifier: @"SettingsVCCompleteSecurity"];
|
|
}
|
|
|
|
#pragma mark - UIDocumentInteractionControllerDelegate
|
|
|
|
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application
|
|
{
|
|
// If iOS wants to call this method, this is the right time to remove the file
|
|
[self deleteKeyExportFile];
|
|
}
|
|
|
|
- (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *)controller
|
|
{
|
|
documentInteractionController = nil;
|
|
}
|
|
|
|
#pragma mark - actions
|
|
|
|
- (void)exportEncryptionKeys:(UITapGestureRecognizer *)recognizer
|
|
{
|
|
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
|
|
|
exportView = [[MXKEncryptionKeysExportView alloc] initWithMatrixSession:self.mainSession];
|
|
currentAlert = exportView.alertController;
|
|
|
|
// Use a temporary file for the export
|
|
keyExportsFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"element-keys.txt"]];
|
|
|
|
// Make sure the file is empty
|
|
[self deleteKeyExportFile];
|
|
|
|
// Show the export dialog
|
|
MXWeakify(self);
|
|
[exportView showInViewController:self toExportKeysToFile:keyExportsFile onComplete:^(BOOL success) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
self->currentAlert = nil;
|
|
self->exportView = nil;
|
|
|
|
if (success)
|
|
{
|
|
// Let another app handling this file
|
|
self->documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:self->keyExportsFile];
|
|
[self->documentInteractionController setDelegate:self];
|
|
|
|
if ([self->documentInteractionController presentOptionsMenuFromRect:self.view.bounds inView:self.view animated:YES])
|
|
{
|
|
// We want to delete the temp keys file after it has been processed by the other app.
|
|
// We use [UIDocumentInteractionControllerDelegate didEndSendingToApplication] for that
|
|
// but it is not reliable for all cases (see http://stackoverflow.com/a/21867096).
|
|
// So, arm a timer to auto delete the file after 10mins.
|
|
self->keyExportsFileDeletionTimer = [NSTimer scheduledTimerWithTimeInterval:600 target:self selector:@selector(deleteKeyExportFile) userInfo:self repeats:NO];
|
|
}
|
|
else
|
|
{
|
|
self->documentInteractionController = nil;
|
|
[self deleteKeyExportFile];
|
|
}
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)deleteKeyExportFile
|
|
{
|
|
// Cancel the deletion timer if it is still here
|
|
if (keyExportsFileDeletionTimer)
|
|
{
|
|
[keyExportsFileDeletionTimer invalidate];
|
|
keyExportsFileDeletionTimer = nil;
|
|
}
|
|
|
|
// And delete the file
|
|
if (keyExportsFile && [[NSFileManager defaultManager] fileExistsAtPath:keyExportsFile.path])
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:keyExportsFile.path error:nil];
|
|
}
|
|
}
|
|
|
|
- (void)toggleBlacklistUnverifiedDevices:(id)sender
|
|
{
|
|
UISwitch *switchButton = (UISwitch*)sender;
|
|
|
|
self.mainSession.crypto.globalBlacklistUnverifiedDevices = switchButton.on;
|
|
|
|
[self.tableView reloadData];
|
|
}
|
|
|
|
- (void)enablePinCodeSwitchValueChanged:(UISwitch *)sender
|
|
{
|
|
SetPinCoordinatorViewMode viewMode = sender.isOn ? SetPinCoordinatorViewModeSetPin : SetPinCoordinatorViewModeConfirmPinToDeactivate;
|
|
self.setPinCoordinatorBridgePresenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:self.mainSession viewMode:viewMode];
|
|
self.setPinCoordinatorBridgePresenter.delegate = self;
|
|
[self.setPinCoordinatorBridgePresenter presentFrom:self animated:YES];
|
|
}
|
|
|
|
- (void)enableBiometricsSwitchValueChanged:(UISwitch *)sender
|
|
{
|
|
SetPinCoordinatorViewMode viewMode = sender.isOn ? SetPinCoordinatorViewModeSetupBiometricsFromSettings : SetPinCoordinatorViewModeConfirmBiometricsToDeactivate;
|
|
self.setPinCoordinatorBridgePresenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:self.mainSession viewMode:viewMode];
|
|
self.setPinCoordinatorBridgePresenter.delegate = self;
|
|
[self.setPinCoordinatorBridgePresenter presentFrom:self animated:YES];
|
|
}
|
|
|
|
- (void)changePinCode:(UIButton *)sender
|
|
{
|
|
SetPinCoordinatorViewMode viewMode = SetPinCoordinatorViewModeChangePin;
|
|
self.setPinCoordinatorBridgePresenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:self.mainSession viewMode:viewMode];
|
|
self.setPinCoordinatorBridgePresenter.delegate = self;
|
|
[self.setPinCoordinatorBridgePresenter presentFrom:self animated:YES];
|
|
}
|
|
|
|
|
|
#pragma mark - SettingsSecureBackupTableViewSectionDelegate
|
|
|
|
- (void)settingsSecureBackupTableViewSectionDidUpdate:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection
|
|
{
|
|
[self reloadData];
|
|
}
|
|
|
|
- (MXKTableViewCellWithTextView *)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection textCellForRow:(NSInteger)textCellForRow
|
|
{
|
|
MXKTableViewCellWithTextView *cell;
|
|
|
|
NSIndexPath *indexPath = [self.tableViewSections exactIndexPathForRowTag:textCellForRow sectionTag:SECTION_SECURE_BACKUP];
|
|
|
|
if (indexPath)
|
|
{
|
|
cell = [self textViewCellForTableView:self.tableView atIndexPath:indexPath];
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (MXKTableViewCellWithButton *)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection buttonCellForRow:(NSInteger)buttonCellForRow
|
|
{
|
|
MXKTableViewCellWithButton *cell;
|
|
|
|
NSIndexPath *indexPath = [self.tableViewSections exactIndexPathForRowTag:buttonCellForRow sectionTag:SECTION_SECURE_BACKUP];
|
|
|
|
if (indexPath)
|
|
{
|
|
cell = [self buttonCellForTableView:self.tableView atIndexPath:indexPath];
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (void)settingsSecureBackupTableViewSectionShowSecureBackupReset:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection
|
|
{
|
|
[self setupSecureBackup];
|
|
}
|
|
|
|
- (void)settingsSecureBackupTableViewSectionShowKeyBackupCreate:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection
|
|
{
|
|
[self showKeyBackupSetupFromSignOutFlow:NO];
|
|
}
|
|
|
|
- (void)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection showKeyBackupRecover:(MXKeyBackupVersion *)keyBackupVersion
|
|
{
|
|
self.currentkeyBackupVersion = keyBackupVersion;
|
|
|
|
// If key backup key is stored in SSSS, ask for secrets recovery before restoring key backup.
|
|
if (!self.mainSession.crypto.backup.hasPrivateKeyInCryptoStore
|
|
&& self.mainSession.crypto.recoveryService.hasRecovery
|
|
&& [self.mainSession.crypto.recoveryService hasSecretWithSecretId:MXSecretId.keyBackup])
|
|
{
|
|
[self showSecretsRecovery];
|
|
}
|
|
else
|
|
{
|
|
[self showKeyBackupRecover:keyBackupVersion fromViewController:self];
|
|
}
|
|
}
|
|
|
|
- (void)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection showKeyBackupDeleteConfirm:(MXKeyBackupVersion *)keyBackupVersion
|
|
{
|
|
MXWeakify(self);
|
|
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
|
|
|
currentAlert =
|
|
[UIAlertController alertControllerWithTitle:[VectorL10n settingsKeyBackupDeleteConfirmationPromptTitle]
|
|
message:[VectorL10n settingsKeyBackupDeleteConfirmationPromptMsg]
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
|
style:UIAlertActionStyleCancel
|
|
handler:^(UIAlertAction * action) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
self->currentAlert = nil;
|
|
}]];
|
|
|
|
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n settingsKeyBackupButtonDelete]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
self->currentAlert = nil;
|
|
|
|
[self->secureBackupSection deleteKeyBackupWithKeyBackupVersion:keyBackupVersion];
|
|
}]];
|
|
|
|
[currentAlert mxk_setAccessibilityIdentifier: @"SettingsVCDeleteKeyBackup"];
|
|
[self presentViewController:currentAlert animated:YES completion:nil];
|
|
}
|
|
|
|
- (void)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection showActivityIndicator:(BOOL)show
|
|
{
|
|
if (show)
|
|
{
|
|
[self startActivityIndicator];
|
|
}
|
|
else
|
|
{
|
|
[self stopActivityIndicator];
|
|
}
|
|
}
|
|
|
|
- (void)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection showError:(NSError *)error
|
|
{
|
|
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
|
}
|
|
|
|
#pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
|
|
|
|
- (void)showKeyBackupSetupFromSignOutFlow:(BOOL)showFromSignOutFlow
|
|
{
|
|
keyBackupSetupCoordinatorBridgePresenter = [[KeyBackupSetupCoordinatorBridgePresenter alloc] initWithSession:self.mainSession];
|
|
|
|
[keyBackupSetupCoordinatorBridgePresenter presentFrom:self
|
|
isStartedFromSignOut:showFromSignOutFlow
|
|
animated:true];
|
|
|
|
keyBackupSetupCoordinatorBridgePresenter.delegate = self;
|
|
}
|
|
|
|
- (void)keyBackupSetupCoordinatorBridgePresenterDelegateDidCancel:(KeyBackupSetupCoordinatorBridgePresenter *)bridgePresenter {
|
|
[keyBackupSetupCoordinatorBridgePresenter dismissWithAnimated:true];
|
|
keyBackupSetupCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)keyBackupSetupCoordinatorBridgePresenterDelegateDidSetupRecoveryKey:(KeyBackupSetupCoordinatorBridgePresenter *)bridgePresenter {
|
|
[keyBackupSetupCoordinatorBridgePresenter dismissWithAnimated:true];
|
|
keyBackupSetupCoordinatorBridgePresenter = nil;
|
|
|
|
[secureBackupSection reload];
|
|
}
|
|
|
|
#pragma mark - SettingsKeyBackupTableViewSectionDelegate
|
|
#ifdef CROSS_SIGNING_AND_BACKUP_DEV
|
|
- (void)settingsKeyBackupTableViewSectionDidUpdate:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection
|
|
{
|
|
[self reloadData];
|
|
}
|
|
|
|
- (MXKTableViewCellWithTextView *)settingsKeyBackupTableViewSection:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection textCellForRow:(NSInteger)textCellForRow
|
|
{
|
|
MXKTableViewCellWithTextView *cell;
|
|
|
|
NSIndexPath *indexPath = [self.tableViewSections exactIndexPathForRowTag:textCellForRow sectionTag:SECTION_KEYBACKUP];
|
|
|
|
if (indexPath)
|
|
{
|
|
cell = [self textViewCellForTableView:self.tableView atIndexPath:indexPath];
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (MXKTableViewCellWithButton *)settingsKeyBackupTableViewSection:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection buttonCellForRow:(NSInteger)buttonCellForRow
|
|
{
|
|
MXKTableViewCellWithButton *cell;
|
|
|
|
NSIndexPath *indexPath = [self.tableViewSections exactIndexPathForRowTag:buttonCellForRow sectionTag:SECTION_KEYBACKUP];
|
|
|
|
if (indexPath)
|
|
{
|
|
cell = [self buttonCellForTableView:self.tableView atIndexPath:indexPath];
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (void)settingsKeyBackupTableViewSectionShowKeyBackupSetup:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection
|
|
{
|
|
[self showKeyBackupSetupFromSignOutFlow:NO];
|
|
}
|
|
|
|
- (void)settingsKeyBackup:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection showKeyBackupRecover:(MXKeyBackupVersion *)keyBackupVersion
|
|
{
|
|
self.currentkeyBackupVersion = keyBackupVersion;
|
|
|
|
// If key backup key is stored in SSSS ask for secrets recovery before restoring key backup.
|
|
if (!self.mainSession.crypto.backup.hasPrivateKeyInCryptoStore
|
|
&& self.mainSession.crypto.recoveryService.hasRecovery
|
|
&& [self.mainSession.crypto.recoveryService hasSecretWithSecretId:MXSecretId.keyBackup])
|
|
{
|
|
[self showSecretsRecovery];
|
|
}
|
|
else
|
|
{
|
|
[self showKeyBackupRecover:keyBackupVersion fromViewController:self];
|
|
}
|
|
}
|
|
|
|
- (void)settingsKeyBackup:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection showKeyBackupDeleteConfirm:(MXKeyBackupVersion *)keyBackupVersion
|
|
{
|
|
MXWeakify(self);
|
|
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
|
|
|
currentAlert =
|
|
[UIAlertController alertControllerWithTitle:[VectorL10n settingsKeyBackupDeleteConfirmationPromptTitle]
|
|
message:[VectorL10n settingsKeyBackupDeleteConfirmationPromptMsg]
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
|
style:UIAlertActionStyleCancel
|
|
handler:^(UIAlertAction * action) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
self->currentAlert = nil;
|
|
}]];
|
|
|
|
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n settingsKeyBackupButtonDelete]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
self->currentAlert = nil;
|
|
|
|
[self->keyBackupSection deleteWithKeyBackupVersion:keyBackupVersion];
|
|
}]];
|
|
|
|
[currentAlert mxk_setAccessibilityIdentifier: @"SettingsVCDeleteKeyBackup"];
|
|
[self presentViewController:currentAlert animated:YES completion:nil];
|
|
}
|
|
|
|
- (void)settingsKeyBackup:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection showActivityIndicator:(BOOL)show
|
|
{
|
|
if (show)
|
|
{
|
|
[self startActivityIndicator];
|
|
}
|
|
else
|
|
{
|
|
[self stopActivityIndicator];
|
|
}
|
|
}
|
|
|
|
- (void)settingsKeyBackup:(SettingsKeyBackupTableViewSection *)settingsKeyBackupTableViewSection showError:(NSError *)error
|
|
{
|
|
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
|
}
|
|
|
|
#endif
|
|
|
|
#pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
|
|
|
|
- (void)showKeyBackupRecover:(MXKeyBackupVersion*)keyBackupVersion fromViewController:(UIViewController*)presentingViewController
|
|
{
|
|
keyBackupRecoverCoordinatorBridgePresenter = [[KeyBackupRecoverCoordinatorBridgePresenter alloc] initWithSession:self.mainSession keyBackupVersion:keyBackupVersion];
|
|
|
|
[keyBackupRecoverCoordinatorBridgePresenter presentFrom:presentingViewController animated:true];
|
|
keyBackupRecoverCoordinatorBridgePresenter.delegate = self;
|
|
}
|
|
|
|
- (void)pushKeyBackupRecover:(MXKeyBackupVersion*)keyBackupVersion fromNavigationController:(UINavigationController*)navigationController
|
|
{
|
|
keyBackupRecoverCoordinatorBridgePresenter = [[KeyBackupRecoverCoordinatorBridgePresenter alloc] initWithSession:self.mainSession keyBackupVersion:keyBackupVersion];
|
|
|
|
[keyBackupRecoverCoordinatorBridgePresenter pushFrom:navigationController animated:YES];
|
|
keyBackupRecoverCoordinatorBridgePresenter.delegate = self;
|
|
}
|
|
|
|
- (void)keyBackupRecoverCoordinatorBridgePresenterDidCancel:(KeyBackupRecoverCoordinatorBridgePresenter *)bridgePresenter {
|
|
[keyBackupRecoverCoordinatorBridgePresenter dismissWithAnimated:true];
|
|
keyBackupRecoverCoordinatorBridgePresenter = nil;
|
|
secretsRecoveryCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)keyBackupRecoverCoordinatorBridgePresenterDidRecover:(KeyBackupRecoverCoordinatorBridgePresenter *)bridgePresenter {
|
|
[keyBackupRecoverCoordinatorBridgePresenter dismissWithAnimated:true];
|
|
keyBackupRecoverCoordinatorBridgePresenter = nil;
|
|
secretsRecoveryCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
#pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
|
|
|
|
- (void)showSecretsRecovery
|
|
{
|
|
secretsRecoveryCoordinatorBridgePresenter = [[SecretsRecoveryCoordinatorBridgePresenter alloc] initWithSession:self.mainSession recoveryGoal:SecretsRecoveryGoalBridgeKeyBackup];
|
|
|
|
[secretsRecoveryCoordinatorBridgePresenter presentFrom:self animated:true];
|
|
secretsRecoveryCoordinatorBridgePresenter.delegate = self;
|
|
}
|
|
|
|
- (void)secretsRecoveryCoordinatorBridgePresenterDelegateDidCancel:(SecretsRecoveryCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
|
{
|
|
[secretsRecoveryCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
|
secretsRecoveryCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)secretsRecoveryCoordinatorBridgePresenterDelegateDidComplete:(SecretsRecoveryCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
|
{
|
|
UIViewController *presentedViewController = [coordinatorBridgePresenter toPresentable];
|
|
|
|
if (coordinatorBridgePresenter.recoveryGoal == SecretsRecoveryGoalBridgeKeyBackup)
|
|
{
|
|
// Go to the true key backup recovery screen
|
|
if ([presentedViewController isKindOfClass:UINavigationController.class])
|
|
{
|
|
UINavigationController *navigationController = (UINavigationController*)self.presentedViewController;
|
|
[self pushKeyBackupRecover:self.currentkeyBackupVersion fromNavigationController:navigationController];
|
|
}
|
|
else
|
|
{
|
|
[self showKeyBackupRecover:self.currentkeyBackupVersion fromViewController:presentedViewController];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[secretsRecoveryCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
|
secretsRecoveryCoordinatorBridgePresenter = nil;
|
|
}
|
|
}
|
|
|
|
#pragma mark - SecureBackupSetupCoordinatorBridgePresenterDelegate
|
|
|
|
- (void)secureBackupSetupCoordinatorBridgePresenterDelegateDidComplete:(SecureBackupSetupCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
|
{
|
|
[self.secureBackupSetupCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
|
self.secureBackupSetupCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)secureBackupSetupCoordinatorBridgePresenterDelegateDidCancel:(SecureBackupSetupCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
|
{
|
|
[self.secureBackupSetupCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
|
self.secureBackupSetupCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
#pragma mark - SetPinCoordinatorBridgePresenterDelegate
|
|
|
|
- (void)setPinCoordinatorBridgePresenterDelegateDidComplete:(SetPinCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
|
{
|
|
[self.tableView reloadData];
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
}
|
|
|
|
- (void)setPinCoordinatorBridgePresenterDelegateDidCancel:(SetPinCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
|
{
|
|
[self.tableView reloadData];
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
}
|
|
|
|
#pragma mark - TableViewSectionsDelegate
|
|
|
|
- (void)tableViewSectionsDidUpdateSections:(TableViewSections *)sections
|
|
{
|
|
[self.tableView reloadData];
|
|
}
|
|
|
|
@end
|