Merge commit '5d625330b03d7fad12bdb5482b3c3fe19c32be88' into feature/basis_merge_1824

# 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
This commit is contained in:
Frank Rotermund
2022-09-19 11:31:20 +02:00
773 changed files with 15324 additions and 7024 deletions
@@ -16,10 +16,14 @@
import Foundation
protocol AuthenticationRestClient {
protocol AuthenticationRestClient: AnyObject {
// MARK: Configuration
var homeserver: String! { get }
var identityServer: String! { get set }
var credentials: MXCredentials! { get }
var identityServer: String! { get }
var acceptableContentTypes: Set<String>! { get set }
init(homeServer: URL, unrecognizedCertificateHandler handler: MXHTTPClientOnUnrecognizedCertificate?)
// MARK: Login
var loginFallbackURL: URL { get }
@@ -17,6 +17,13 @@
import Foundation
protocol AuthenticationServiceDelegate: AnyObject {
/// The authentication service encountered an unrecognized certificate and needs to
/// prompt the user to find out whether or not it should be trusted.
/// - Parameters:
/// - service: The authentication service.
/// - unrecognizedCertificate: The certificate data to be trusted.
/// - completion: A completion handler called one the user accepts/rejects the certificate.
func authenticationService(_ service: AuthenticationService, needsPromptFor unrecognizedCertificate: Data?, completion: @escaping (Bool) -> Void)
/// The authentication service received an SSO login token via a deep link.
/// This only occurs when SSOAuthenticationPresenter uses an SFSafariViewController.
/// - Parameters:
@@ -25,8 +32,12 @@ protocol AuthenticationServiceDelegate: AnyObject {
/// - transactionID: The transaction ID generated during SSO page presentation.
/// - Returns: `true` if the SSO login can be continued.
func authenticationService(_ service: AuthenticationService, didReceive ssoLoginToken: String, with transactionID: String) -> Bool
func authenticationService(_ service: AuthenticationService,
didUpdateStateWithLink link: UniversalLink)
}
@objcMembers
class AuthenticationService: NSObject {
/// The shared service object.
@@ -36,15 +47,15 @@ class AuthenticationService: NSObject {
// MARK: Private
/// The rest client used to make authentication requests.
private var client: AuthenticationRestClient
/// The object used to create a new `MXSession` when authentication has completed.
private var sessionCreator = SessionCreator()
private var sessionCreator: SessionCreatorProtocol
// MARK: Public
/// The current state of the authentication flow.
private(set) var state: AuthenticationState
/// The rest client used to make authentication requests.
private(set) var client: AuthenticationRestClient
/// The current login wizard or `nil` if `startFlow` hasn't been called.
private(set) var loginWizard: LoginWizard?
/// The current registration wizard or `nil` if `startFlow` hasn't been called for `.registration`.
@@ -53,22 +64,60 @@ class AuthenticationService: NSObject {
/// The authentication service's delegate.
weak var delegate: AuthenticationServiceDelegate?
/// The type of client to use during the flow.
var clientType: AuthenticationRestClient.Type = MXRestClient.self
// MARK: - Setup
override init() {
init(sessionCreator: SessionCreatorProtocol = SessionCreator()) {
guard let homeserverURL = URL(string: AppConfigService.shared.serverUrl()) else {
MXLog.failure("[AuthenticationService]: Failed to create URL from default homeserver URL string.")
fatalError("Invalid defeiault homeserver URL string.")
}
state = AuthenticationState(flow: .login, homeserverAddress: BuildSettings.serverConfigDefaultHomeserverUrlString)
client = MXRestClient(homeServer: homeserverURL, unrecognizedCertificateHandler: nil)
client = clientType.init(homeServer: homeserverURL, unrecognizedCertificateHandler: nil)
self.sessionCreator = sessionCreator
super.init()
}
// MARK: - Public
/// Parse and handle a server provisioning link.
/// - Parameter universalLink: A link such as https://mobile.element.io/?hs_url=matrix.example.com&is_url=identity.example.com
/// - Returns: `true` if a provisioning link was detected and handled.
@discardableResult
func handleServerProvisioningLink(_ universalLink: UniversalLink) -> Bool {
MXLog.debug("[AuthenticationService] handleServerProvisioningLink: \(universalLink)")
let hsUrl = universalLink.homeserverUrl
let isUrl = universalLink.identityServerUrl
if hsUrl == nil && isUrl == nil {
MXLog.debug("[AuthenticationService] handleServerProvisioningLink: no hsUrl or isUrl")
return false
}
let isRegister = universalLink.pathParams.first == "register"
let flow: AuthenticationFlow = isRegister ? .register : .login
if needsAuthentication {
reset()
// not logged in
// update the state with given HS and IS addresses
state = AuthenticationState(flow: flow,
homeserverAddress: hsUrl ?? BuildSettings.serverConfigDefaultHomeserverUrlString,
identityServer: isUrl ?? BuildSettings.serverConfigDefaultIdentityServerUrlString)
delegate?.authenticationService(self, didUpdateStateWithLink: universalLink)
} else {
// logged in
AppDelegate.theDelegate().displayLogoutConfirmation(for: universalLink, completion: nil)
}
return true
}
/// Whether authentication is needed by checking for any accounts.
/// - Returns: `true` there are no accounts or if there is an inactive account that has had a soft logout.
var needsAuthentication: Bool {
@@ -76,16 +125,7 @@ class AuthenticationService: NSObject {
}
/// Credentials to be used when authenticating after soft logout, otherwise `nil`.
var softLogoutCredentials: MXCredentials? {
guard MXKAccountManager.shared().activeAccounts.isEmpty else { return nil }
for account in MXKAccountManager.shared().accounts {
if account.isSoftLogout {
return account.mxCredentials
}
}
return nil
}
var softLogoutCredentials: MXCredentials?
/// Get the last authenticated [Session], if there is an active session.
/// - Returns: The last active session if any, or `nil`
@@ -96,12 +136,12 @@ class AuthenticationService: NSObject {
func startFlow(_ flow: AuthenticationFlow, for homeserverAddress: String) async throws {
var (client, homeserver) = try await loginFlow(for: homeserverAddress)
let loginWizard = LoginWizard(client: client)
let loginWizard = LoginWizard(client: client, sessionCreator: sessionCreator)
self.loginWizard = loginWizard
if flow == .register {
do {
let registrationWizard = RegistrationWizard(client: client)
let registrationWizard = RegistrationWizard(client: client, sessionCreator: sessionCreator)
homeserver.registrationFlow = try await registrationWizard.registrationFlow()
self.registrationWizard = registrationWizard
} catch {
@@ -134,13 +174,18 @@ class AuthenticationService: NSObject {
}
/// Reset the service to a fresh state.
func reset() {
/// - Parameter useDefaultServer: Pass `true` to revert back to the one in `BuildSettings`, otherwise the current homeserver will be kept.
func reset(useDefaultServer: Bool = false) {
loginWizard = nil
registrationWizard = nil
softLogoutCredentials = nil
// The previously used homeserver is re-used as `startFlow` will be called again a replace it anyway.
let address = state.homeserver.addressFromUser ?? state.homeserver.address
self.state = AuthenticationState(flow: .login, homeserverAddress: address)
let address = useDefaultServer ? BuildSettings.serverConfigDefaultHomeserverUrlString : state.homeserver.addressFromUser ?? state.homeserver.address
let identityServer = state.identityServer
self.state = AuthenticationState(flow: .login,
homeserverAddress: address,
identityServer: identityServer)
}
/// Continues an SSO flow when completion comes via a deep link.
@@ -152,27 +197,6 @@ class AuthenticationService: NSObject {
delegate?.authenticationService(self, didReceive: token, with: transactionID) ?? false
}
// /// Perform a well-known request, using the domain from the matrixId
// func getWellKnownData(matrixId: String,
// homeServerConnectionConfig: HomeServerConnectionConfig?) async -> WellknownResult {
//
// }
//
// /// Authenticate with a matrixId and a password
// /// Usually call this after a successful call to getWellKnownData()
// /// - Parameter homeServerConnectionConfig the information about the homeserver and other configuration
// /// - Parameter matrixId the matrixId of the user
// /// - Parameter password the password of the account
// /// - Parameter initialDeviceName the initial device name
// /// - Parameter deviceId the device id, optional. If not provided or null, the server will generate one.
// func directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
// matrixId: String,
// password: String,
// initialDeviceName: String,
// deviceId: String? = nil) async -> MXSession {
//
// }
// MARK: - Private
/// Query the supported login flows for the supplied homeserver.
@@ -186,14 +210,37 @@ class AuthenticationService: NSObject {
MXLog.error("[AuthenticationService] Unable to create a URL from the supplied homeserver address when calling loginFlow.")
throw AuthenticationError.invalidHomeserver
}
var identityServerURL: URL?
if let wellKnown = try? await wellKnown(for: homeserverURL),
let baseURL = URL(string: wellKnown.homeServer.baseUrl) {
homeserverURL = baseURL
if let wellKnown = try? await wellKnown(for: homeserverURL) {
if let baseURL = URL(string: wellKnown.homeServer.baseUrl) {
homeserverURL = baseURL
}
if let identityServer = wellKnown.identityServer,
let baseURL = URL(string: identityServer.baseUrl) {
identityServerURL = baseURL
}
}
#warning("Add an unrecognized certificate handler.")
let client = MXRestClient(homeServer: homeserverURL, unrecognizedCertificateHandler: nil)
let client = clientType.init(homeServer: homeserverURL, unrecognizedCertificateHandler: { [weak self] certificate in
guard let self = self else { return false }
var isTrusted = false
let semaphore = DispatchSemaphore(value: 0)
self.delegate?.authenticationService(self, needsPromptFor: certificate) { didTrust in
isTrusted = didTrust
semaphore.signal()
}
semaphore.wait()
return isTrusted
})
if let identityServerURL = identityServerURL {
client.identityServer = identityServerURL.absoluteString
}
let loginFlow = try await getLoginFlowResult(client: client)
@@ -219,7 +266,7 @@ class AuthenticationService: NSObject {
return (client, homeserver)
}
private func getLoginFlowResult(client: MXRestClient) async throws -> LoginFlowResult {
private func getLoginFlowResult(client: AuthenticationRestClient) async throws -> LoginFlowResult {
// Get the login flow
let loginFlowResponse = try await client.getLoginSession()
@@ -231,7 +278,7 @@ class AuthenticationService: NSObject {
/// Perform a well-known request on the specified homeserver URL.
private func wellKnown(for homeserverURL: URL) async throws -> MXWellKnown {
let wellKnownClient = MXRestClient(homeServer: homeserverURL, unrecognizedCertificateHandler: nil)
let wellKnownClient = clientType.init(homeServer: homeserverURL, unrecognizedCertificateHandler: nil)
// The .well-known/matrix/client API is often just a static file returned with no content type.
// Make our HTTP client compatible with this behaviour
@@ -23,16 +23,20 @@ struct AuthenticationState {
/// Information about the currently selected homeserver.
var homeserver: Homeserver
/// Currently selected identity server
var identityServer: String?
var isForceLoginFallbackEnabled = false
init(flow: AuthenticationFlow, homeserverAddress: String) {
init(flow: AuthenticationFlow, homeserverAddress: String, identityServer: String? = nil) {
self.flow = flow
self.homeserver = Homeserver(address: homeserverAddress)
self.identityServer = identityServer
}
init(flow: AuthenticationFlow, homeserver: Homeserver) {
init(flow: AuthenticationFlow, homeserver: Homeserver, identityServer: String? = nil) {
self.flow = flow
self.homeserver = homeserver
self.identityServer = identityServer
}
struct Homeserver {
@@ -61,7 +65,6 @@ struct AuthenticationState {
/// The homeserver mapped into view data that is ready for display.
var viewData: AuthenticationHomeserverViewData {
AuthenticationHomeserverViewData(address: displayableAddress,
isMatrixDotOrg: isMatrixDotOrg,
showLoginForm: preferredLoginMode.supportsPasswordFlow,
showRegistrationForm: registrationFlow != nil && !needsRegistrationFallback,
ssoIdentityProviders: preferredLoginMode.ssoIdentityProviders ?? [])
@@ -89,7 +89,6 @@ enum LoginMode {
/// Data obtained when calling `LoginWizard.resetPassword` that will be used
/// when calling `LoginWizard.checkResetPasswordMailConfirmed`.
struct ResetPasswordData {
let newPassword: String
let addThreePIDSessionID: String
}
@@ -100,14 +100,18 @@ struct CheckResetPasswordParameters: DictionaryEncodable {
let auth: AuthenticationParameters
/// The new password
let newPassword: String
/// The sign out of all devices flag
let signoutAllDevices: Bool
enum CodingKeys: String, CodingKey {
case auth
case newPassword = "new_password"
case signoutAllDevices = "logout_devices"
}
init(clientSecret: String, sessionID: String, newPassword: String) {
init(clientSecret: String, sessionID: String, newPassword: String, signoutAllDevices: Bool) {
self.auth = AuthenticationParameters.resetPasswordParameters(clientSecret: clientSecret, sessionID: sessionID)
self.newPassword = newPassword
self.signoutAllDevices = signoutAllDevices
}
}
@@ -15,6 +15,7 @@
//
import Foundation
import libPhoneNumber_iOS
/// Set of methods to be able to login to an existing account on a homeserver.
///
@@ -31,30 +32,30 @@ class LoginWizard {
}
let client: AuthenticationRestClient
let sessionCreator: SessionCreator
let sessionCreator: SessionCreatorProtocol
private(set) var state: State
init(client: AuthenticationRestClient, sessionCreator: SessionCreator = SessionCreator()) {
init(client: AuthenticationRestClient, sessionCreator: SessionCreatorProtocol) {
self.client = client
self.sessionCreator = sessionCreator
self.state = State()
}
// /// Get some information about a matrixId: displayName and avatar url
// func profileInfo(for matrixID: String) async -> LoginProfileInfo {
//
// }
/// Login to the homeserver.
/// - Parameters:
/// - login: The login field. Can be a user name, or a msisdn (email or phone number) associated to the account.
/// - password: The password of the account.
/// - initialDeviceName: The initial device name.
/// - deviceID: The device ID, optional. If not provided or nil, the server will generate one.
/// - removeOtherAccounts: If set to true, existing accounts with different user identifiers will be removed.
/// - Returns: An `MXSession` if the login is successful.
func login(login: String, password: String, initialDeviceName: String, deviceID: String? = nil) async throws -> MXSession {
func login(login: String,
password: String,
initialDeviceName: String,
deviceID: String? = nil,
removeOtherAccounts: Bool = false) async throws -> MXSession {
let parameters: LoginPasswordParameters
if MXTools.isEmailAddress(login) {
@@ -62,6 +63,13 @@ class LoginWizard {
password: password,
deviceDisplayName: initialDeviceName,
deviceID: deviceID)
} else if let number = try? NBPhoneNumberUtil.sharedInstance().parse(login, defaultRegion: nil),
NBPhoneNumberUtil.sharedInstance().isValidNumber(number) {
let msisdn = login.replacingOccurrences(of: "+", with: "")
parameters = LoginPasswordParameters(id: .thirdParty(medium: .msisdn, address: msisdn),
password: password,
deviceDisplayName: initialDeviceName,
deviceID: deviceID)
} else {
parameters = LoginPasswordParameters(id: .user(login),
password: password,
@@ -70,41 +78,43 @@ class LoginWizard {
}
let credentials = try await client.login(parameters: parameters)
return sessionCreator.createSession(credentials: credentials, client: client)
return sessionCreator.createSession(credentials: credentials,
client: client,
removeOtherAccounts: removeOtherAccounts)
}
/// Exchange a login token to an access token.
/// - Parameter loginToken: A login token, obtained when login has happened in a WebView, using SSO.
/// - Parameters:
/// - token: A login token, obtained when login has happened in a WebView, using SSO.
/// - removeOtherAccounts: If set to true, existing accounts with different user identifiers will be removed.
/// - Returns: An `MXSession` if the login is successful.
func login(with token: String) async throws -> MXSession {
func login(with token: String, removeOtherAccounts: Bool = false) async throws -> MXSession {
let parameters = LoginTokenParameters(token: token)
let credentials = try await client.login(parameters: parameters)
return sessionCreator.createSession(credentials: credentials, client: client)
return sessionCreator.createSession(credentials: credentials,
client: client,
removeOtherAccounts: removeOtherAccounts)
}
// /// Login to the homeserver by sending a custom JsonDict.
// /// The data should contain at least one entry `type` with a String value.
// func loginCustom(data: Codable) async -> MXSession {
//
// }
/// Ask the homeserver to reset the user password. The password will not be
/// reset until `checkResetPasswordMailConfirmed` is successfully called.
/// reset until `resetPasswordMailConfirmed` is successfully called.
/// - Parameters:
/// - email: An email previously associated to the account the user wants the password to be reset.
/// - newPassword: The desired new password
func resetPassword(email: String, newPassword: String) async throws {
func resetPassword(email: String) async throws {
let result = try await client.forgetPassword(for: email,
clientSecret: state.clientSecret,
sendAttempt: state.sendAttempt)
state.sendAttempt += 1
state.resetPasswordData = ResetPasswordData(newPassword: newPassword, addThreePIDSessionID: result)
state.resetPasswordData = ResetPasswordData(addThreePIDSessionID: result)
}
/// Confirm the new password, once the user has checked their email.
/// When this method succeeds, the account password will be effectively modified.
func checkResetPasswordMailConfirmed() async throws {
/// - Parameters:
/// - newPassword: The desired new password
/// - signoutAllDevices: The flag to sign out of all devices
func resetPasswordMailConfirmed(newPassword: String, signoutAllDevices: Bool) async throws {
guard let resetPasswordData = state.resetPasswordData else {
MXLog.error("[LoginWizard] resetPasswordMailConfirmed: Reset password data missing. Call resetPassword first.")
throw LoginError.resetPasswordNotStarted
@@ -112,7 +122,8 @@ class LoginWizard {
let parameters = CheckResetPasswordParameters(clientSecret: state.clientSecret,
sessionID: resetPasswordData.addThreePIDSessionID,
newPassword: resetPasswordData.newPassword)
newPassword: newPassword,
signoutAllDevices: signoutAllDevices)
try await client.resetPassword(parameters: parameters)
@@ -17,7 +17,7 @@
import Foundation
/// The parameters used for registration requests.
struct RegistrationParameters: DictionaryEncodable {
struct RegistrationParameters: DictionaryEncodable, Equatable {
/// Authentication parameters
var auth: AuthenticationParameters?
@@ -44,7 +44,7 @@ struct RegistrationParameters: DictionaryEncodable {
}
/// The data passed to the `auth` parameter in authentication requests.
struct AuthenticationParameters: Encodable {
struct AuthenticationParameters: Encodable, Equatable {
/// The type of authentication taking place. The identifier from `MXLoginFlowType`.
let type: String
@@ -36,7 +36,7 @@ class RegistrationWizard {
}
let client: AuthenticationRestClient
let sessionCreator: SessionCreator
let sessionCreator: SessionCreatorProtocol
private(set) var state: State
@@ -59,7 +59,7 @@ class RegistrationWizard {
state.isRegistrationStarted
}
init(client: AuthenticationRestClient, sessionCreator: SessionCreator = SessionCreator()) {
init(client: AuthenticationRestClient, sessionCreator: SessionCreatorProtocol) {
self.client = client
self.sessionCreator = sessionCreator
@@ -255,7 +255,7 @@ class RegistrationWizard {
do {
let response = try await client.register(parameters: parameters)
let credentials = MXCredentials(loginResponse: response, andDefaultCredentials: client.credentials)
return .success(sessionCreator.createSession(credentials: credentials, client: client))
return .success(sessionCreator.createSession(credentials: credentials, client: client, removeOtherAccounts: false))
} catch {
let nsError = error as NSError
@@ -268,17 +268,17 @@ class RegistrationWizard {
let flowResult = authenticationSession.flowResult
if isCreatingAccount || isRegistrationStarted {
return try await handleMandatoryDummyStage(flowResult: flowResult)
return try await handleDummyStage(flowResult: flowResult)
}
return .flowResponse(flowResult)
}
}
/// Checks for a mandatory dummy stage and handles it automatically when possible.
private func handleMandatoryDummyStage(flowResult: FlowResult) async throws -> RegistrationResult {
/// Checks for a dummy stage and handles it automatically when possible.
private func handleDummyStage(flowResult: FlowResult) async throws -> RegistrationResult {
// If the dummy stage is mandatory, do the dummy stage now
guard flowResult.missingStages.contains(where: { $0.isDummy && $0.isMandatory }) else { return .flowResponse(flowResult) }
guard flowResult.missingStages.contains(where: { $0.isDummy }) else { return .flowResponse(flowResult) }
return try await dummy()
}
@@ -16,23 +16,51 @@
import Foundation
/// A WIP class that has common functionality to create a new session.
class SessionCreator {
protocol SessionCreatorProtocol {
/// Creates an `MXSession` using the supplied credentials and REST client.
func createSession(credentials: MXCredentials, client: AuthenticationRestClient) -> MXSession {
// Report the new account in account manager
/// - Parameters:
/// - credentials: The `MXCredentials` for the account.
/// - client: The client that completed the authentication.
/// - removeOtherAccounts: Flag to remove other accounts than the account specified with the `credentials.userId`.
/// - Returns: A new `MXSession` for the account.
func createSession(credentials: MXCredentials, client: AuthenticationRestClient, removeOtherAccounts: Bool) -> MXSession
}
/// A struct that provides common functionality to create a new session.
struct SessionCreator: SessionCreatorProtocol {
private let accountManager: MXKAccountManager
init(withAccountManager accountManager: MXKAccountManager = .shared()) {
self.accountManager = accountManager
}
func createSession(credentials: MXCredentials, client: AuthenticationRestClient, removeOtherAccounts: Bool) -> MXSession {
// Use identity server provided in the client
if credentials.identityServer == nil {
#warning("Check that the client is actually updated with this info?")
credentials.identityServer = client.identityServer
}
let account = MXKAccount(credentials: credentials)
if let identityServer = credentials.identityServer {
account.identityServerURL = identityServer
if removeOtherAccounts {
let otherAccounts = accountManager.accounts.filter({ $0.mxCredentials.userId != credentials.userId })
for account in otherAccounts {
accountManager.removeAccount(account, completion: nil)
}
}
if let account = accountManager.account(forUserId: credentials.userId) {
accountManager.hydrateAccount(account, with: credentials)
return account.mxSession
} else {
let account = MXKAccount(credentials: credentials)
// set identity server of the new account
if let identityServer = credentials.identityServer {
account.identityServerURL = identityServer
}
accountManager.addAccount(account, andOpenSession: true)
return account.mxSession
}
MXKAccountManager.shared().addAccount(account, andOpenSession: true)
return account.mxSession
}
}
@@ -21,7 +21,7 @@ enum RegisterThreePID {
case msisdn(msisdn: String, countryCode: String)
}
struct ThreePIDCredentials: Codable {
struct ThreePIDCredentials: Codable, Equatable {
var clientSecret: String?
var identityServer: String?