From 39551563d293a52223e4c17ef3ba768ad1b0237f Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 19 Jul 2019 14:25:45 +0200 Subject: [PATCH 1/8] Soft logout: Support soft logout #2540 --- CHANGES.rst | 7 ++++ Riot/AppDelegate.m | 10 +++++ .../AuthenticationViewController.m | 10 +++++ .../Authentication/Views/AuthInputsView.m | 23 ++++++++++- Riot/Modules/TabBar/MasterTabBarController.h | 7 ++++ Riot/Modules/TabBar/MasterTabBarController.m | 41 ++++++++++++++++++- 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 0b1fb0bed..a09fb1333 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,10 @@ +Changes in 0.9.2 (2019-07-) +=============================================== + +Improvements: + * Upgrade MatrixKit version ([v0.10.2](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.10.2)). + * Soft logout: Support soft logout (#2540). + Changes in 0.9.1 (2019-07-17) =============================================== diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index db380b2ec..10297a090 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -2781,6 +2781,16 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [self logoutWithConfirmation:NO completion:nil]; } }]; + + // Add observer to handle soft logout + [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidSoftlogoutAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + + MXKAccount *account = notif.object; + [self removeMatrixSession:account.mxSession]; + + // Return to authentication screen + [self.masterTabBarController showAuthenticationScreenAfterSoftLogout:account.mxCredentials]; + }]; [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionIgnoredUsersDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull notif) { diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index fb73984d6..af8240796 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -395,6 +395,16 @@ } } +- (void)setSoftLogoutCredentials:(MXCredentials *)softLogoutCredentials +{ + [super setSoftLogoutCredentials:softLogoutCredentials]; + + // Customise the screen for soft logout + // TODO + self.customServersTickButton.hidden = YES; +} + + - (void)handleAuthenticationSession:(MXAuthenticationSession *)authSession { [super handleAuthenticationSession:authSession]; diff --git a/Riot/Modules/Authentication/Views/AuthInputsView.m b/Riot/Modules/Authentication/Views/AuthInputsView.m index 5685a9f43..81795f22d 100644 --- a/Riot/Modules/Authentication/Views/AuthInputsView.m +++ b/Riot/Modules/Authentication/Views/AuthInputsView.m @@ -54,6 +54,7 @@ @end @implementation AuthInputsView +@synthesize softLogoutCredentials; + (UINib *)nib { @@ -487,6 +488,15 @@ } } } + + // For soft logout, pass the device_id currently used + if (parameters && self.softLogoutCredentials) + { + NSMutableDictionary *parametersWithDeviceId = [parameters mutableCopy]; + parametersWithDeviceId[@"device_id"] = self.softLogoutCredentials.deviceId; + parameters = parametersWithDeviceId; + } + } else if (type == MXKAuthenticationTypeRegister) { @@ -725,7 +735,12 @@ { // Note: this use case was not tested yet. parameters = @{ - @"auth": @{@"session":currentSession.session, @"username": self.userLoginTextField.text, @"password": self.passWordTextField.text, @"type": kMXLoginFlowTypePassword} + @"auth": @{ + @"session":currentSession.session, + @"username": self.userLoginTextField.text, + @"password": self.passWordTextField.text, + @"type": kMXLoginFlowTypePassword + } }; } else if ([self isFlowSupported:kMXLoginFlowTypeTerms] && ![self isFlowCompleted:kMXLoginFlowTypeTerms]) @@ -936,6 +951,12 @@ return YES; } +- (void)setSoftLogoutCredentials:(MXCredentials *)credentials +{ + softLogoutCredentials = credentials; + self.userLoginTextField.text = softLogoutCredentials.userId; +} + - (BOOL)areAllRequiredFieldsSet { // Keep enable the submit button. diff --git a/Riot/Modules/TabBar/MasterTabBarController.h b/Riot/Modules/TabBar/MasterTabBarController.h index 2a5f59710..8f17d2d0e 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.h +++ b/Riot/Modules/TabBar/MasterTabBarController.h @@ -63,6 +63,13 @@ */ - (void)showAuthenticationScreenWithRegistrationParameters:(NSDictionary*)parameters; +/** + Display the authentication screen in order to login back a soft logout session. + + @param softLogoutCredentials the credentials of the soft logout session. + */ +- (void)showAuthenticationScreenAfterSoftLogout:(MXCredentials*)softLogoutCredentials; + /** Open the room with the provided identifier in a specific matrix session. diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index c85c8b969..634df71bc 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -42,6 +42,7 @@ // The parameters to pass to the Authentification view controller. NSDictionary *authViewControllerRegistrationParameters; + MXCredentials *softLogoutCredentials; // The recents data source shared between all the view controllers of the tab bar. RecentsDataSource *recentsDataSource; @@ -142,11 +143,25 @@ [super viewDidAppear:animated]; // Check whether we're not logged in + BOOL authIsShown = NO; if (![MXKAccountManager sharedManager].accounts.count) { [self showAuthenticationScreen]; + authIsShown = YES; } - else + else if (![MXKAccountManager sharedManager].activeAccounts.count) + { + // Display a login screen if the account is soft logout + // Note: We support only one account + MXKAccount *account = [MXKAccountManager sharedManager].accounts.firstObject; + if (account.isSoftLogout) + { + [self showAuthenticationScreenAfterSoftLogout:account.mxCredentials]; + authIsShown = YES; + } + } + + if (!authIsShown) { // Check whether the user has been already prompted to send crash reports. // (Check whether 'enableCrashReport' flag has been set once) @@ -401,6 +416,25 @@ } } +- (void)showAuthenticationScreenAfterSoftLogout:(MXCredentials*)credentials; +{ + NSLog(@"[MasterTabBarController] showAuthenticationScreenAfterSoftLogout"); + + softLogoutCredentials = credentials; + + // Check whether an authentication screen is not already shown or preparing + if (!self.authViewController && !isAuthViewControllerPreparing) + { + isAuthViewControllerPreparing = YES; + + [[AppDelegate theDelegate] restoreInitialDisplay:^{ + + [self performSegueWithIdentifier:@"showAuth" sender:self]; + + }]; + } +} + - (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession { [self selectRoomWithId:roomId andEventId:eventId inMatrixSession:matrixSession completion:nil]; @@ -637,6 +671,11 @@ _authViewController.externalRegistrationParameters = authViewControllerRegistrationParameters; authViewControllerRegistrationParameters = nil; } + if (softLogoutCredentials) + { + _authViewController.softLogoutCredentials = softLogoutCredentials; + softLogoutCredentials = nil; + } } else if ([[segue identifier] isEqualToString:@"showUnifiedSearch"]) { From 7230af2b34ca8d55a222355e212421698368a642 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 23 Jul 2019 11:51:46 +0200 Subject: [PATCH 2/8] Soft logout: Implement design This is an adapted version of the zeplin design. It uses the current app login look and feel with the copy of the zeplin design #2540 --- Riot/Assets/en.lproj/Vector.strings | 4 ++ Riot/Generated/Strings.swift | 16 ++++++ .../AuthenticationViewController.m | 10 ++-- .../Authentication/Views/AuthInputsView.m | 53 +++++++++++++++++++ 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index f13c54309..6d0fd62f1 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -115,6 +115,10 @@ "auth_add_email_and_phone_warning" = "Registration with email and phone number at once is not supported yet until the api exists. Only the phone number will be taken into account. You may add your email to your profile in settings."; "auth_accept_policies" = "Please review and accept the policies of this homeserver:"; "auth_autodiscover_invalid_response" = "Invalid homeserver discovery response"; +"auth_softlogout_signed_out" = "You’re signed out"; +"auth_softlogout_sign_in" = "Sign In"; +"auth_softlogout_reason" = "Your homeserver (%1$@) admin has signed you out of your account %2$@ (%3$@)."; +"auth_softlogout_recover_encryption_keys" = "Sign in to recover encryption keys stored exclusively on this device. You need them to read all of your secure messages on any device."; // Chat creation "room_creation_title" = "New Chat"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 0738f3685..5c1a54486 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -226,6 +226,22 @@ internal enum VectorL10n { internal static var authSkip: String { return VectorL10n.tr("Vector", "auth_skip") } + /// Your homeserver (%1$@) admin has signed you out of your account %2$@ (%3$@). + internal static func authSoftlogoutReason(_ p1: String, _ p2: String, _ p3: String) -> String { + return VectorL10n.tr("Vector", "auth_softlogout_reason", p1, p2, p3) + } + /// Sign in to recover encryption keys stored exclusively on this device. You need them to read all of your secure messages on any device. + internal static var authSoftlogoutRecoverEncryptionKeys: String { + return VectorL10n.tr("Vector", "auth_softlogout_recover_encryption_keys") + } + /// Sign In + internal static var authSoftlogoutSignIn: String { + return VectorL10n.tr("Vector", "auth_softlogout_sign_in") + } + /// You’re signed out + internal static var authSoftlogoutSignedOut: String { + return VectorL10n.tr("Vector", "auth_softlogout_signed_out") + } /// Submit internal static var authSubmit: String { return VectorL10n.tr("Vector", "auth_submit") diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index af8240796..590bd20f9 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -1,7 +1,8 @@ /* Copyright 2015 OpenMarket Ltd Copyright 2017 Vector Creations Ltd - + Copyright 2019 New Vector Ltd + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -366,7 +367,7 @@ // The right bar button is used to switch the authentication type. if (self.authType == MXKAuthenticationTypeLogin) { - if (!authInputsview.isSingleSignOnRequired) + if (!authInputsview.isSingleSignOnRequired && !self.softLogoutCredentials) { self.rightBarButtonItem.title = NSLocalizedStringFromTable(@"auth_register", @"Vector", nil); } @@ -400,8 +401,11 @@ [super setSoftLogoutCredentials:softLogoutCredentials]; // Customise the screen for soft logout - // TODO self.customServersTickButton.hidden = YES; + self.rightBarButtonItem.title = nil; + self.mainNavigationItem.title = NSLocalizedStringFromTable(@"auth_softlogout_signed_out", @"Vector", nil); + + // TODO: Clear all data button } diff --git a/Riot/Modules/Authentication/Views/AuthInputsView.m b/Riot/Modules/Authentication/Views/AuthInputsView.m index 81795f22d..60b584f69 100644 --- a/Riot/Modules/Authentication/Views/AuthInputsView.m +++ b/Riot/Modules/Authentication/Views/AuthInputsView.m @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd + Copyright 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -955,6 +956,58 @@ { softLogoutCredentials = credentials; self.userLoginTextField.text = softLogoutCredentials.userId; + self.userLoginContainer.hidden = YES; + self.phoneContainer.hidden = YES; + + [self displaySoftLogoutMessage]; +} + +- (void)displaySoftLogoutMessage +{ + // Take some shortcuts and make some assumptions (Riot uses MXFileStore) to + // retrieve my user display name as quick as possible + MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:softLogoutCredentials]; + [fileStore asyncUsersWithUserIds:@[softLogoutCredentials.userId] success:^(NSArray * _Nonnull users) { + + MXUser *myUser = users.firstObject; + [self displaySoftLogoutMessageWithUserDisplayname:myUser.displayname]; + + } failure:^(NSError * _Nonnull error) { + NSLog(@"[AuthInputsView] displaySoftLogoutMessage: Cannot load displayname. Error: %@", error); + [self displaySoftLogoutMessageWithUserDisplayname:nil]; + }]; +} + +- (void)displaySoftLogoutMessageWithUserDisplayname:(NSString*)userDisplayname +{ + // Use messageLabel for this message + self.messageLabelTopConstraint.constant = 8; + self.messageLabel.textColor = ThemeService.shared.theme.textPrimaryColor; + self.messageLabel.hidden = NO; + + NSMutableAttributedString *message = [[NSMutableAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"auth_softlogout_sign_in", @"Vector", nil) + attributes:@{ + NSFontAttributeName: [UIFont boldSystemFontOfSize:14] + }]; + + [message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]]; + + NSString *string = [NSString stringWithFormat:NSLocalizedStringFromTable(@"auth_softlogout_reason", @"Vector", nil), + softLogoutCredentials.homeServerName, userDisplayname, softLogoutCredentials.userId]; + [message appendAttributedString:[[NSAttributedString alloc] initWithString:string + attributes:@{ + NSFontAttributeName: [UIFont systemFontOfSize:14] + }]]; + + // TODO: Do not display this message if no e2e keys + [message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]]; + string = NSLocalizedStringFromTable(@"auth_softlogout_recover_encryption_keys", @"Vector", nil); + [message appendAttributedString:[[NSAttributedString alloc] initWithString:string + attributes:@{ + NSFontAttributeName: [UIFont systemFontOfSize:14] + }]]; + + self.messageLabel.attributedText = message; } - (BOOL)areAllRequiredFieldsSet From bcdf55f1fcaada80a29926f7defa8bb631339c82 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 23 Jul 2019 14:45:51 +0200 Subject: [PATCH 3/8] Soft logout: Implement design for the clear data section #2540 --- Riot/Assets/en.lproj/Vector.strings | 4 ++ Riot/Generated/Strings.swift | 16 ++++++ .../AuthenticationViewController.h | 4 ++ .../AuthenticationViewController.m | 46 ++++++++++++++-- .../AuthenticationViewController.xib | 53 ++++++++++++++++++- 5 files changed, 118 insertions(+), 5 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6d0fd62f1..b28e4807f 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -119,6 +119,10 @@ "auth_softlogout_sign_in" = "Sign In"; "auth_softlogout_reason" = "Your homeserver (%1$@) admin has signed you out of your account %2$@ (%3$@)."; "auth_softlogout_recover_encryption_keys" = "Sign in to recover encryption keys stored exclusively on this device. You need them to read all of your secure messages on any device."; +"auth_softlogout_clear_data" = "Clear personal data"; +"auth_softlogout_clear_data_message_1" = "Warning: Your personal data (including encryption keys) is still stored on this device."; +"auth_softlogout_clear_data_message_2" = "Clear it if you're finished using this device, or want to sign in to another account."; +"auth_softlogout_clear_data_button" = "Clear all data"; // Chat creation "room_creation_title" = "New Chat"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 5c1a54486..3b2f545ea 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -226,6 +226,22 @@ internal enum VectorL10n { internal static var authSkip: String { return VectorL10n.tr("Vector", "auth_skip") } + /// Clear personal data + internal static var authSoftlogoutClearData: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data") + } + /// Clear all data + internal static var authSoftlogoutClearDataButton: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data_button") + } + /// Warning: Your personal data (including encryption keys) is still stored on this device. + internal static var authSoftlogoutClearDataMessage1: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data_message_1") + } + /// Clear it if you're finished using this device, or want to sign in to another account. + internal static var authSoftlogoutClearDataMessage2: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data_message_2") + } /// Your homeserver (%1$@) admin has signed you out of your account %2$@ (%3$@). internal static func authSoftlogoutReason(_ p1: String, _ p2: String, _ p3: String) -> String { return VectorL10n.tr("Vector", "auth_softlogout_reason", p1, p2, p3) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.h b/Riot/Modules/Authentication/AuthenticationViewController.h index 5358f20f6..9c24ea4f1 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.h +++ b/Riot/Modules/Authentication/AuthenticationViewController.h @@ -41,5 +41,9 @@ @property (weak, nonatomic) IBOutlet UIView *homeServerSeparator; @property (weak, nonatomic) IBOutlet UIView *identityServerSeparator; +@property (weak, nonatomic) IBOutlet UIView *softLogoutClearDataContainer; +@property (weak, nonatomic) IBOutlet UILabel *softLogoutClearDataLabel; +@property (weak, nonatomic) IBOutlet UIButton *softLogoutClearDataButton; + @end diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 590bd20f9..22e855528 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -108,6 +108,14 @@ [self.customServersTickButton setImage:[UIImage imageNamed:@"selection_untick"] forState:UIControlStateHighlighted]; [self hideCustomServers:YES]; + + // Soft logout section + self.softLogoutClearDataButton.layer.cornerRadius = 5; + self.softLogoutClearDataButton.clipsToBounds = YES; + [self.softLogoutClearDataButton setTitle:NSLocalizedStringFromTable(@"auth_softlogout_clear_data_button", @"Vector", nil) forState:UIControlStateNormal]; + [self.softLogoutClearDataButton setTitle:NSLocalizedStringFromTable(@"auth_softlogout_clear_data_button", @"Vector", nil) forState:UIControlStateHighlighted]; + self.softLogoutClearDataButton.enabled = YES; + self.softLogoutClearDataContainer.hidden = YES; // The view controller dismiss itself on successful login. self.delegate = self; @@ -195,7 +203,10 @@ self.identityServerLabel.textColor = ThemeService.shared.theme.textSecondaryColor; self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor; - + + self.softLogoutClearDataLabel.textColor = ThemeService.shared.theme.textPrimaryColor; + self.softLogoutClearDataButton.backgroundColor = ThemeService.shared.theme.warningColor; + [self.authInputsView customizeViewRendering]; [self setNeedsStatusBarAppearanceUpdate]; @@ -405,7 +416,30 @@ self.rightBarButtonItem.title = nil; self.mainNavigationItem.title = NSLocalizedStringFromTable(@"auth_softlogout_signed_out", @"Vector", nil); - // TODO: Clear all data button + [self showLogoutClearDataContainer]; +} + +- (void)showLogoutClearDataContainer +{ + NSMutableAttributedString *message = [[NSMutableAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"auth_softlogout_clear_data", @"Vector", nil) + attributes:@{ + NSFontAttributeName: [UIFont boldSystemFontOfSize:14] + }]; + + [message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]]; + + NSString *string = [NSString stringWithFormat:@"%@\n\n%@", + NSLocalizedStringFromTable(@"auth_softlogout_clear_data_message_1", @"Vector", nil), + NSLocalizedStringFromTable(@"auth_softlogout_clear_data_message_2", @"Vector", nil)]; + + [message appendAttributedString:[[NSAttributedString alloc] initWithString:string + attributes:@{ + NSFontAttributeName: [UIFont systemFontOfSize:14] + }]]; + self.softLogoutClearDataLabel.attributedText = message; + + self.softLogoutClearDataContainer.hidden = NO; + [self refreshContentViewHeightConstraint]; } @@ -724,7 +758,13 @@ } } } - + + if (!self.softLogoutClearDataContainer.isHidden) + { + // The soft logout clear data section adds more height + constant += self.softLogoutClearDataContainer.frame.size.height; + } + self.contentViewHeightConstraint.constant = constant; } diff --git a/Riot/Modules/Authentication/AuthenticationViewController.xib b/Riot/Modules/Authentication/AuthenticationViewController.xib index 71887099d..a875b9470 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.xib +++ b/Riot/Modules/Authentication/AuthenticationViewController.xib @@ -1,11 +1,11 @@ - + - + @@ -42,6 +42,9 @@ + + + @@ -345,17 +348,63 @@ + + + + + + + + + + + + + + + + + + + + From ef5a2704a17d5373c172af4faccdb9c554e6428a Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 23 Jul 2019 16:20:07 +0200 Subject: [PATCH 4/8] Soft logout: Implement the clear data button #2540 --- Riot/AppDelegate.m | 5 ++- Riot/Assets/en.lproj/Vector.strings | 4 ++ Riot/Generated/Strings.swift | 12 +++++ .../AuthenticationViewController.m | 45 +++++++++++++++++++ .../AuthenticationViewController.xib | 3 ++ Riot/Modules/TabBar/MasterTabBarController.m | 15 +++++++ 6 files changed, 83 insertions(+), 1 deletion(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 10297a090..9e6cf8f5b 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -2770,7 +2770,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Remove inApp notifications toggle change MXKAccount *account = notif.object; - [account removeObserver:self forKeyPath:@"enableInAppNotifications"]; + if (!account.isSoftLogout) + { + [account removeObserver:self forKeyPath:@"enableInAppNotifications"]; + } // Clear Modular data [[WidgetManager sharedManager] deleteDataForUser:account.mxCredentials.userId]; diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index b28e4807f..6dc4d294c 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -123,6 +123,10 @@ "auth_softlogout_clear_data_message_1" = "Warning: Your personal data (including encryption keys) is still stored on this device."; "auth_softlogout_clear_data_message_2" = "Clear it if you're finished using this device, or want to sign in to another account."; "auth_softlogout_clear_data_button" = "Clear all data"; +"auth_softlogout_clear_data_sign_out_title" = "Are you sure?"; +"auth_softlogout_clear_data_sign_out_msg" = "Are you sure you want to clear all data currently stored on this device? Sign in again to access your account data and messages."; +"auth_softlogout_clear_data_sign_out" = "Sign out"; + // Chat creation "room_creation_title" = "New Chat"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 3b2f545ea..b1f9b8633 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -242,6 +242,18 @@ internal enum VectorL10n { internal static var authSoftlogoutClearDataMessage2: String { return VectorL10n.tr("Vector", "auth_softlogout_clear_data_message_2") } + /// Sign out + internal static var authSoftlogoutClearDataSignOut: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data_sign_out") + } + /// Are you sure you want to clear all data currently stored on this device? Sign in again to access your account data and messages. + internal static var authSoftlogoutClearDataSignOutMsg: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data_sign_out_msg") + } + /// Are you sure? + internal static var authSoftlogoutClearDataSignOutTitle: String { + return VectorL10n.tr("Vector", "auth_softlogout_clear_data_sign_out_title") + } /// Your homeserver (%1$@) admin has signed you out of your account %2$@ (%3$@). internal static func authSoftlogoutReason(_ p1: String, _ p2: String, _ p3: String) -> String { return VectorL10n.tr("Vector", "auth_softlogout_reason", p1, p2, p3) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 22e855528..0f757cfd5 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -442,6 +442,47 @@ [self refreshContentViewHeightConstraint]; } +- (void)showClearDataAfterSoftLogoutConfirmation +{ + // Request confirmation + if (alert) + { + [alert dismissViewControllerAnimated:NO completion:nil]; + } + + alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"auth_softlogout_clear_data_sign_out_title", @"Vector", nil) + message:NSLocalizedStringFromTable(@"auth_softlogout_clear_data_sign_out_msg", @"Vector", nil) + preferredStyle:UIAlertControllerStyleAlert]; + + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"auth_softlogout_clear_data_sign_out", @"Vector", nil) style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * action) + { + [self clearDataAfterSoftLogout]; + }]]; + + MXWeakify(self); + [alert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + MXStrongifyAndReturnIfNil(self); + self->alert = nil; + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +- (void)clearDataAfterSoftLogout +{ + NSLog(@"[AuthenticationVC] clearDataAfterSoftLogout %@", self.softLogoutCredentials.userId); + + // Use AppDelegate so that we reset app settings and this auth screen + [[AppDelegate theDelegate] logoutSendingRequestServer:YES completion:^(BOOL isLoggedOut) { + NSLog(@"[AuthenticationVC] Complete. isLoggedOut: %@", @(isLoggedOut)); + }]; +} + - (void)handleAuthenticationSession:(MXAuthenticationSession *)authSession { @@ -577,6 +618,10 @@ [ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar]; } + else if (sender == self.softLogoutClearDataButton) + { + [self showClearDataAfterSoftLogoutConfirmation]; + } else { [super onButtonPressed:sender]; diff --git a/Riot/Modules/Authentication/AuthenticationViewController.xib b/Riot/Modules/Authentication/AuthenticationViewController.xib index a875b9470..aa204d4d7 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.xib +++ b/Riot/Modules/Authentication/AuthenticationViewController.xib @@ -378,6 +378,9 @@ Clear it if you're finished using this device, or want to sign in to another acc + + + diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index 634df71bc..218101ca5 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -39,6 +39,7 @@ // Observer that checks when the Authentification view controller has gone. id authViewControllerObserver; + id authViewRemovedAccountObserver; // The parameters to pass to the Authentification view controller. NSDictionary *authViewControllerRegistrationParameters; @@ -231,6 +232,11 @@ [[NSNotificationCenter defaultCenter] removeObserver:authViewControllerObserver]; authViewControllerObserver = nil; } + if (authViewRemovedAccountObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:authViewRemovedAccountObserver]; + authViewRemovedAccountObserver = nil; + } if (kThemeServiceDidChangeThemeNotificationObserver) { @@ -664,6 +670,15 @@ [[NSNotificationCenter defaultCenter] removeObserver:authViewControllerObserver]; authViewControllerObserver = nil; }]; + + authViewRemovedAccountObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidRemoveAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + + // The user has cleared data for their soft logged out account + _authViewController = nil; + + [[NSNotificationCenter defaultCenter] removeObserver:authViewRemovedAccountObserver]; + authViewRemovedAccountObserver = nil; + }]; // Forward parameters if any if (authViewControllerRegistrationParameters) From e2c757dedd521e3141a4f4d37efd943c97db0ad2 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 23 Jul 2019 17:03:24 +0200 Subject: [PATCH 5/8] Soft logout: Do not try to log against matrix.org if the password was wrong --- Riot/Modules/Authentication/AuthenticationViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 0f757cfd5..2d3b1dcef 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -633,7 +633,7 @@ // Homeserver migration: When the default homeserver url is different from matrix.org, // the login (or forgot pwd) process with an existing matrix.org accounts will then fail. // Patch: Falling back to matrix.org HS so we don't break everyone's logins - if ([self.homeServerTextField.text isEqualToString:self.defaultHomeServerUrl] && ![self.defaultHomeServerUrl isEqualToString:@"https://matrix.org"]) + if ([self.homeServerTextField.text isEqualToString:self.defaultHomeServerUrl] && ![self.defaultHomeServerUrl isEqualToString:@"https://matrix.org"] && !self.softLogoutCredentials) { MXError *mxError = [[MXError alloc] initWithNSError:error]; From 82880737786a7debe1022d9a0f9a2553c9f956ec Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 23 Jul 2019 17:15:16 +0200 Subject: [PATCH 6/8] Soft logout: Do not show the clear data section on the forgot password flow --- .../AuthenticationViewController.m | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 2d3b1dcef..03d34371e 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -300,6 +300,7 @@ } [self updateForgotPwdButtonVisibility]; + [self updateSoftLogoutClearDataContainerVisibility]; } - (void)setAuthInputsView:(MXKAuthInputsView *)authInputsView @@ -416,10 +417,10 @@ self.rightBarButtonItem.title = nil; self.mainNavigationItem.title = NSLocalizedStringFromTable(@"auth_softlogout_signed_out", @"Vector", nil); - [self showLogoutClearDataContainer]; + [self showSoftLogoutClearDataContainer]; } -- (void)showLogoutClearDataContainer +- (void)showSoftLogoutClearDataContainer { NSMutableAttributedString *message = [[NSMutableAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"auth_softlogout_clear_data", @"Vector", nil) attributes:@{ @@ -442,6 +443,19 @@ [self refreshContentViewHeightConstraint]; } +- (void)updateSoftLogoutClearDataContainerVisibility +{ + // Do not display it in case of forget password flow + if (self.softLogoutCredentials && self.authType == MXKAuthenticationTypeLogin) + { + self.softLogoutClearDataContainer.hidden = NO; + } + else + { + self.softLogoutClearDataContainer.hidden = YES; + } +} + - (void)showClearDataAfterSoftLogoutConfirmation { // Request confirmation @@ -490,6 +504,7 @@ // Hide "Forgot password" and "Log in" buttons in case of SSO [self updateForgotPwdButtonVisibility]; + [self updateSoftLogoutClearDataContainerVisibility]; AuthInputsView *authInputsview; if ([self.authInputsView isKindOfClass:AuthInputsView.class]) @@ -626,6 +641,8 @@ { [super onButtonPressed:sender]; } + + [self updateSoftLogoutClearDataContainerVisibility]; } - (void)onFailureDuringAuthRequest:(NSError *)error From 98ad5721cbb81b51999c297379442264a333fd29 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 23 Jul 2019 17:36:10 +0200 Subject: [PATCH 7/8] Soft logout: Display the message about keys only if there are keys not yet backed ip --- .../Authentication/Views/AuthInputsView.m | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Riot/Modules/Authentication/Views/AuthInputsView.m b/Riot/Modules/Authentication/Views/AuthInputsView.m index 60b584f69..e7ec0c0e0 100644 --- a/Riot/Modules/Authentication/Views/AuthInputsView.m +++ b/Riot/Modules/Authentication/Views/AuthInputsView.m @@ -964,21 +964,25 @@ - (void)displaySoftLogoutMessage { - // Take some shortcuts and make some assumptions (Riot uses MXFileStore) to - // retrieve my user display name as quick as possible + // Take some shortcuts and make some assumptions (Riot uses MXFileStore and MXRealmCryptoStore) to + // retrieve data to display as quick as possible + MXRealmCryptoStore *cryptoStore = [[MXRealmCryptoStore alloc] initWithCredentials:self.softLogoutCredentials]; + BOOL keyBackupNeeded = [cryptoStore inboundGroupSessionsToBackup:1].count > 0; + MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:softLogoutCredentials]; [fileStore asyncUsersWithUserIds:@[softLogoutCredentials.userId] success:^(NSArray * _Nonnull users) { MXUser *myUser = users.firstObject; - [self displaySoftLogoutMessageWithUserDisplayname:myUser.displayname]; + + [self displaySoftLogoutMessageWithUserDisplayname:myUser.displayname andKeyBackupNeeded:keyBackupNeeded]; } failure:^(NSError * _Nonnull error) { NSLog(@"[AuthInputsView] displaySoftLogoutMessage: Cannot load displayname. Error: %@", error); - [self displaySoftLogoutMessageWithUserDisplayname:nil]; + [self displaySoftLogoutMessageWithUserDisplayname:nil andKeyBackupNeeded:keyBackupNeeded]; }]; } -- (void)displaySoftLogoutMessageWithUserDisplayname:(NSString*)userDisplayname +- (void)displaySoftLogoutMessageWithUserDisplayname:(NSString*)userDisplayname andKeyBackupNeeded:(BOOL)keyBackupNeeded { // Use messageLabel for this message self.messageLabelTopConstraint.constant = 8; @@ -999,13 +1003,15 @@ NSFontAttributeName: [UIFont systemFontOfSize:14] }]]; - // TODO: Do not display this message if no e2e keys - [message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]]; - string = NSLocalizedStringFromTable(@"auth_softlogout_recover_encryption_keys", @"Vector", nil); - [message appendAttributedString:[[NSAttributedString alloc] initWithString:string - attributes:@{ - NSFontAttributeName: [UIFont systemFontOfSize:14] - }]]; + if (keyBackupNeeded) + { + [message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]]; + string = NSLocalizedStringFromTable(@"auth_softlogout_recover_encryption_keys", @"Vector", nil); + [message appendAttributedString:[[NSAttributedString alloc] initWithString:string + attributes:@{ + NSFontAttributeName: [UIFont systemFontOfSize:14] + }]]; + } self.messageLabel.attributedText = message; } From 1a26e9ee4cf2f8ac4592c49e6fb01eed6719f11d Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 24 Jul 2019 12:14:31 +0200 Subject: [PATCH 8/8] Soft logout: Retain MXFileStore instance while getting user display name --- Riot/Modules/Authentication/Views/AuthInputsView.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Modules/Authentication/Views/AuthInputsView.m b/Riot/Modules/Authentication/Views/AuthInputsView.m index e7ec0c0e0..64341f17d 100644 --- a/Riot/Modules/Authentication/Views/AuthInputsView.m +++ b/Riot/Modules/Authentication/Views/AuthInputsView.m @@ -973,6 +973,7 @@ [fileStore asyncUsersWithUserIds:@[softLogoutCredentials.userId] success:^(NSArray * _Nonnull users) { MXUser *myUser = users.firstObject; + [fileStore close]; [self displaySoftLogoutMessageWithUserDisplayname:myUser.displayname andKeyBackupNeeded:keyBackupNeeded];