diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 9a1d5faba..a40c64f3c 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1074,6 +1074,12 @@ "key_verification_self_verify_current_session_alert_message" = "Other users may not trust it."; "key_verification_self_verify_current_session_alert_validate_action" = "Verify"; +// Unverified sessions + +"key_verification_self_verify_unverified_sessions_alert_title" = "Review where you're logged in"; +"key_verification_self_verify_unverified_sessions_alert_message" = "Verify your other sessions."; +"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Review"; + // MARK: Self verification wait "device_verification_self_verify_wait_title" = "Complete security"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 6380c029e..950d6f903 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1570,6 +1570,18 @@ internal enum VectorL10n { internal static var keyVerificationSelfVerifyCurrentSessionAlertValidateAction: String { return VectorL10n.tr("Vector", "key_verification_self_verify_current_session_alert_validate_action") } + /// Verify your other sessions. + internal static var keyVerificationSelfVerifyUnverifiedSessionsAlertMessage: String { + return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_message") + } + /// Review where you're logged in + internal static var keyVerificationSelfVerifyUnverifiedSessionsAlertTitle: String { + return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_title") + } + /// Review + internal static var keyVerificationSelfVerifyUnverifiedSessionsAlertValidateAction: String { + return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_validate_action") + } /// Verify this session internal static var keyVerificationThisSessionTitle: String { return VectorL10n.tr("Vector", "key_verification_this_session_title") diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 8c1be1aea..b1ab98997 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -33,6 +33,7 @@ final class RiotSettings: NSObject { static let allowStunServerFallback = "allowStunServerFallback" static let stunServerFallback = "stunServerFallback" static let hideVerifyThisSessionAlert = "hideVerifyThisSessionAlert" + static let hideReviewSessionsAlert = "hideReviewSessionsAlert" } static let shared = RiotSettings() @@ -144,4 +145,12 @@ final class RiotSettings: NSObject { UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.hideVerifyThisSessionAlert) } } + + var hideReviewSessionsAlert: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.hideReviewSessionsAlert) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.hideReviewSessionsAlert) + } + } } diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index 1a1b5503a..a42479e18 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -27,6 +27,9 @@ #import "MXRoom+Riot.h" #import "MXSession+Riot.h" +#import "SettingsViewController.h" +#import "SecurityViewController.h" + #import "Riot-Swift.h" @interface MasterTabBarController () @@ -66,7 +69,7 @@ @property(nonatomic,getter=isHidden) BOOL hidden; -@property(nonatomic) BOOL verifyCurrentSessionAlertHasBeenDisplayed; +@property(nonatomic) BOOL reviewSessionAlertHasBeenDisplayed; @end @@ -209,7 +212,7 @@ [childViewControllers removeAllObjects]; } - [self presentVerifyCurrentSessionAlertIfNeeded]; + [self presentReviewSessionsAlertIfNeeded]; } if (unifiedSearchViewController) @@ -219,55 +222,6 @@ } } -- (void)presentVerifyCurrentSessionAlertIfNeeded -{ - if (RiotSettings.shared.hideVerifyThisSessionAlert || self.verifyCurrentSessionAlertHasBeenDisplayed) - { - return; - } - - MXSession *mainSession = self.mxSessions.firstObject; - - if (self.viewLoaded - && mainSession.state >= MXSessionStateStoreDataReady - && mainSession.crypto.crossSigning - && mainSession.crypto.crossSigning.state == MXCrossSigningStateCrossSigningExists) - { - self.verifyCurrentSessionAlertHasBeenDisplayed = YES; - [self presentVerifyCurrentSessionAlertWithSession:mainSession]; - } -} - -- (void)presentVerifyCurrentSessionAlertWithSession:(MXSession*)session -{ - [currentAlert dismissViewControllerAnimated:NO completion:nil]; - - UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_title", @"Vector", nil) - message:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_message", @"Vector", nil) - preferredStyle:UIAlertControllerStyleAlert]; - - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_validate_action", @"Vector", nil) - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - [[AppDelegate theDelegate] presentCompleteSecurityForSession:session]; - }]]; - - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil) - style:UIAlertActionStyleCancel - handler:nil]]; - - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"do_not_ask_again", @"Vector", nil) - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction * action) { - RiotSettings.shared.hideVerifyThisSessionAlert = YES; - }]]; - - - [self presentViewController:alert animated:YES completion:nil]; - - currentAlert = alert; -} - - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; @@ -444,7 +398,7 @@ { [self refreshTabBarBadges]; - [self presentVerifyCurrentSessionAlertIfNeeded]; + [self presentReviewSessionsAlertIfNeeded]; } - (void)showAuthenticationScreen @@ -456,6 +410,8 @@ { isAuthViewControllerPreparing = YES; + [self resetReviewSessionsFlags]; + [[AppDelegate theDelegate] restoreInitialDisplay:^{ [self performSegueWithIdentifier:@"showAuth" sender:self]; @@ -1034,6 +990,147 @@ [self presentViewController:currentAlert animated:YES completion:nil]; } +#pragma mark - Review session + +- (void)presentReviewSessionsAlertIfNeeded +{ + MXSession *mainSession = self.mxSessions.firstObject; + + if (!(self.viewLoaded + && mainSession.state >= MXSessionStateStoreDataReady + && mainSession.crypto.crossSigning)) + { + return; + } + + switch (mainSession.crypto.crossSigning.state) { + case MXCrossSigningStateCrossSigningExists: + [self presentVerifyCurrentSessionAlertIfNeededWithSession:mainSession]; + break; + case MXCrossSigningStateCanCrossSign: + [self presentReviewUnverifiedSessionsAlertIfNeededWithSession:mainSession]; + break; + default: + break; + } +} + +- (void)presentVerifyCurrentSessionAlertIfNeededWithSession:(MXSession*)session +{ + if (RiotSettings.shared.hideVerifyThisSessionAlert || self.reviewSessionAlertHasBeenDisplayed) + { + return; + } + + self.reviewSessionAlertHasBeenDisplayed = YES; + [self presentVerifyCurrentSessionAlertWithSession:session]; +} + +- (void)presentVerifyCurrentSessionAlertWithSession:(MXSession*)session +{ + [currentAlert dismissViewControllerAnimated:NO completion:nil]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_title", @"Vector", nil) + message:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_message", @"Vector", nil) + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_validate_action", @"Vector", nil) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + [[AppDelegate theDelegate] presentCompleteSecurityForSession:session]; + }]]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil) + style:UIAlertActionStyleCancel + handler:nil]]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"do_not_ask_again", @"Vector", nil) + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * action) { + RiotSettings.shared.hideVerifyThisSessionAlert = YES; + }]]; + + + [self presentViewController:alert animated:YES completion:nil]; + + currentAlert = alert; +} + +- (void)presentReviewUnverifiedSessionsAlertIfNeededWithSession:(MXSession*)session +{ + if (RiotSettings.shared.hideReviewSessionsAlert || self.reviewSessionAlertHasBeenDisplayed) + { + return; + } + + NSArray *devices = [session.crypto.store devicesForUser:session.myUserId].allValues; + + BOOL isUserHasOneUnverifiedDevice = NO; + + for (MXDeviceInfo *device in devices) + { + if (device.trustLevel.localVerificationStatus == MXDeviceUnknown) + { + isUserHasOneUnverifiedDevice = YES; + break; + } + } + + if (isUserHasOneUnverifiedDevice) + { + self.reviewSessionAlertHasBeenDisplayed = YES; + [self presentReviewUnverifiedSessionsAlertWithSession:session]; + } +} + +- (void)presentReviewUnverifiedSessionsAlertWithSession:(MXSession*)session +{ + [currentAlert dismissViewControllerAnimated:NO completion:nil]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_unverified_sessions_alert_title", @"Vector", nil) + message:NSLocalizedStringFromTable(@"key_verification_self_verify_unverified_sessions_alert_message", @"Vector", nil) + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_unverified_sessions_alert_validate_action", @"Vector", nil) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + [self showSettingsSecurityScreenForSession:session]; + }]]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil) + style:UIAlertActionStyleCancel + handler:nil]]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"do_not_ask_again", @"Vector", nil) + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * action) { + RiotSettings.shared.hideReviewSessionsAlert = YES; + }]]; + + + [self presentViewController:alert animated:YES completion:nil]; + + currentAlert = alert; +} + +- (void)showSettingsSecurityScreenForSession:(MXSession*)session +{ + SettingsViewController *settingsViewController = [SettingsViewController instantiate]; + [settingsViewController loadViewIfNeeded]; + SecurityViewController *securityViewController = [SecurityViewController instantiateWithMatrixSession:session]; + + [[AppDelegate theDelegate] restoreInitialDisplay:^{ + self.navigationController.viewControllers = @[settingsViewController, securityViewController]; + }]; +} + +- (void)resetReviewSessionsFlags +{ + self.reviewSessionAlertHasBeenDisplayed = NO; + RiotSettings.shared.hideVerifyThisSessionAlert = NO; + RiotSettings.shared.hideReviewSessionsAlert = NO; +} + #pragma mark - UITabBarDelegate - (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item