From 2fbd129456c875a8ff9c5c25e4b9fc20ea62319d Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 9 Dec 2021 17:28:56 +0000 Subject: [PATCH 01/16] Add first refresh token implementation pass. Account credential persistence and NotificationService handling. --- Config/BuildSettings.swift | 3 +++ Config/CommonConfiguration.swift | 2 ++ .../UserSessions/UserSessionsService.swift | 2 +- .../MatrixKit/Models/Account/MXKAccount.m | 27 ++++++++++++++++++- RiotNSE/NotificationService.swift | 17 +++++++++++- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 0919c08fd4..9515debb95 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -344,6 +344,9 @@ final class BuildSettings: NSObject { static let authScreenShowForgotPassword = true static let authScreenShowCustomServerOptions = true + // MARK: - Authentication Options + static let authEnableRefreshTokens = true + // MARK: - Unified Search static let unifiedSearchScreenShowPublicDirectory = true diff --git a/Config/CommonConfiguration.swift b/Config/CommonConfiguration.swift index 5edcacc37c..2d628d3bce 100644 --- a/Config/CommonConfiguration.swift +++ b/Config/CommonConfiguration.swift @@ -76,6 +76,8 @@ class CommonConfiguration: NSObject, Configurable { sdkOptions.enableKeyBackupWhenStartingMXCrypto = false sdkOptions.clientPermalinkBaseUrl = BuildSettings.clientPermalinkBaseUrl + + sdkOptions.authEnableRefreshTokens = BuildSettings.authEnableRefreshTokens // Configure key provider delegate MXKeyProvider.sharedInstance().delegate = EncryptionKeyManager.shared } diff --git a/Riot/Managers/UserSessions/UserSessionsService.swift b/Riot/Managers/UserSessions/UserSessionsService.swift index b8618abb0d..576e0d22f8 100644 --- a/Riot/Managers/UserSessions/UserSessionsService.swift +++ b/Riot/Managers/UserSessions/UserSessionsService.swift @@ -155,7 +155,7 @@ class UserSessionsService: NSObject { let isSessionStateValid: Bool switch mxSession.state { - case .closed, .unknownToken: + case .closed, .unauthenticated: isSessionStateValid = false default: isSessionStateValid = true diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index c308672513..b277fc4439 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -1771,7 +1771,7 @@ - (void)onMatrixSessionStateChange { isPauseRequested = NO; } - else if (mxSession.state == MXSessionStateUnknownToken) + else if (mxSession.state == MXSessionStateUnauthenticated) { // Logout this account [[MXKAccountManager sharedManager] removeAccount:self completion:nil]; @@ -2225,4 +2225,29 @@ - (void)handleIdentityServiceDidChangeAccessTokenNotification:(NSNotification*)n } } +#pragma mark - Homeserver Access/Refresh Token updates + +- (void)registerRestClientDidRefreshTokensNotification +{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRestClientDidRefreshTokensNotification:) name:MXRestClientDidRefreshTokensNotification object:nil]; +} + +- (void)handleRestClientDidRefreshTokensNotification:(NSNotification*)notification +{ + NSDictionary *userInfo = notification.userInfo; + + NSString *userId = userInfo[MXIdentityServiceNotificationUserIdKey]; + NSString *identityServer = userInfo[MXIdentityServiceNotificationIdentityServerKey]; + NSString *accessToken = userInfo[MXIdentityServiceNotificationAccessTokenKey]; + + if (userId && identityServer && accessToken && [mxCredentials.identityServer isEqualToString:identityServer]) + { + mxCredentials.identityServerAccessToken = accessToken; + + // Archive updated field + [[MXKAccountManager sharedManager] saveAccounts]; + } +} + + @end diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index 9464453cad..f669b95934 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -56,8 +56,23 @@ class NotificationService: UNNotificationServiceExtension { guard let userAccount = userAccount else { return nil } - return MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil) + let restClient = MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil) + restClient.refreshTokensFailedHandler = { mxError in + MXLog.debug("[NotificationService] mxRestClient: The rest client is no longer authenticated.") + if let mxError = mxError, + mxError.httpResponse.statusCode == 401, + let softLogout = mxError.userInfo[kMXErrorSoftLogoutKey] as? Bool, + softLogout { + MXLog.debug("[NotificationService] mxRestClient: soft logout"); + userAccount.softLogout() + } else { + MXLog.debug("[NotificationService] mxRestClient: full logout"); + MXKAccountManager.shared().removeAccount(userAccount, completion: nil) + } + } + return restClient }() + private static var isLoggerInitialized: Bool = false private lazy var pushGatewayRestClient: MXPushGatewayRestClient = { let url = URL(string: BuildSettings.serverConfigSygnalAPIUrlString)! From b09cf742245471197f08052daed54383f3971dd0 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 13 Dec 2021 16:29:02 +0000 Subject: [PATCH 02/16] Fix refresh token coding and persistence. --- .../MatrixKit/Models/Account/MXKAccount.m | 33 +++++-------------- .../Models/Account/MXKAccountManager.m | 15 +++++++++ 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index b277fc4439..359cf9ff44 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -187,6 +187,8 @@ - (id)initWithCoder:(NSCoder *)coder userId:userId accessToken:accessToken]; + mxCredentials.accessTokenExpiresAt = [coder decodeInt64ForKey:@"accessTokenExpiresAt"]; + mxCredentials.refreshToken = [coder decodeObjectForKey:@"refreshToken"]; mxCredentials.identityServer = _identityServerURL; mxCredentials.identityServerAccessToken = identityServerAccessToken; mxCredentials.deviceId = [coder decodeObjectForKey:@"deviceId"]; @@ -242,6 +244,12 @@ - (void)encodeWithCoder:(NSCoder *)coder [coder encodeObject:mxCredentials.homeServer forKey:@"homeserverurl"]; [coder encodeObject:mxCredentials.userId forKey:@"userid"]; [coder encodeObject:mxCredentials.accessToken forKey:@"accesstoken"]; + if (mxCredentials.accessTokenExpiresAt) { + [coder encodeInt64:mxCredentials.accessTokenExpiresAt forKey:@"accessTokenExpiresAt"]; + } + if (mxCredentials.refreshToken) { + [coder encodeObject:mxCredentials.refreshToken forKey:@"refreshToken"]; + } [coder encodeObject:mxCredentials.identityServerAccessToken forKey:@"identityserveraccesstoken"]; if (mxCredentials.deviceId) @@ -2225,29 +2233,4 @@ - (void)handleIdentityServiceDidChangeAccessTokenNotification:(NSNotification*)n } } -#pragma mark - Homeserver Access/Refresh Token updates - -- (void)registerRestClientDidRefreshTokensNotification -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRestClientDidRefreshTokensNotification:) name:MXRestClientDidRefreshTokensNotification object:nil]; -} - -- (void)handleRestClientDidRefreshTokensNotification:(NSNotification*)notification -{ - NSDictionary *userInfo = notification.userInfo; - - NSString *userId = userInfo[MXIdentityServiceNotificationUserIdKey]; - NSString *identityServer = userInfo[MXIdentityServiceNotificationIdentityServerKey]; - NSString *accessToken = userInfo[MXIdentityServiceNotificationAccessTokenKey]; - - if (userId && identityServer && accessToken && [mxCredentials.identityServer isEqualToString:identityServer]) - { - mxCredentials.identityServerAccessToken = accessToken; - - // Archive updated field - [[MXKAccountManager sharedManager] saveAccounts]; - } -} - - @end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m index 0763dab531..080a7ace41 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m @@ -66,6 +66,8 @@ - (instancetype)init // Load existing accounts from local storage [self loadAccounts]; + + [self registerRestClientDidRefreshTokensNotification]; } return self; } @@ -723,4 +725,17 @@ - (void)migrateAccounts } } +#pragma mark - Homeserver Access/Refresh Token updates + +- (void)registerRestClientDidRefreshTokensNotification +{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRestClientDidRefreshTokensNotification:) name:MXRestClientDidRefreshTokensNotification object:nil]; +} + +- (void)handleRestClientDidRefreshTokensNotification:(NSNotification*)notification +{ + [self saveAccounts]; +} + + @end From 362635a98d21b23270cb48529b52fde45e51e0d4 Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 6 Jan 2022 20:35:37 +0000 Subject: [PATCH 03/16] Split MXKAccount from Data so just data can be loaded from disk without side effects. Also change force reload of accounts to stop double load on init. --- .../AuthenticationViewController.m | 2 +- .../MXKAuthenticationViewController.m | 2 + .../MatrixKit/Models/Account/MXKAccount.h | 77 +----- .../MatrixKit/Models/Account/MXKAccount.m | 229 +++++------------- .../MatrixKit/Models/Account/MXKAccountData.h | 141 +++++++++++ .../MatrixKit/Models/Account/MXKAccountData.m | 150 ++++++++++++ .../Models/Account/MXKAccountManager.h | 9 +- .../Models/Account/MXKAccountManager.m | 87 +++++-- RiotNSE/NotificationService.swift | 10 +- RiotShareExtension/Shared/ShareDataSource.m | 4 +- RiotShareExtension/Shared/ShareManager.m | 6 +- 11 files changed, 445 insertions(+), 272 deletions(-) create mode 100644 Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h create mode 100644 Riot/Modules/MatrixKit/Models/Account/MXKAccountData.m diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 188e33268b..6bc35a5b00 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -340,7 +340,7 @@ - (void)viewDidAppear:(BOOL)animated didCheckFalseAuthScreenDisplay = YES; MXLogDebug(@"[AuthenticationVC] viewDidAppear: Checking false logout"); - [[MXKAccountManager sharedManager] forceReloadAccounts]; + [MXKAccountManager sharedManagerWithReload: YES]; if ([MXKAccountManager sharedManager].activeAccounts.count) { // For now, we do not have better solution than forcing the user to restart the app diff --git a/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m index 91a1eda043..acccd6a293 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m @@ -1451,6 +1451,8 @@ - (void)attemptDeviceRehydrationWithKeyData:(NSData *)keyData MXRestClient *mxRestClient = [[MXRestClient alloc] initWithCredentials:credentials andOnUnrecognizedCertificateBlock:^BOOL(NSData *certificate) { return NO; + } andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { + [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; }]; MXWeakify(self); diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h index 8d21f6e72b..5e928299c4 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h @@ -17,6 +17,7 @@ */ #import +#import "MXKAccountData.h" @class MXKAccount; @@ -56,29 +57,7 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer `MXKAccount` object contains the credentials of a logged matrix user. It is used to handle matrix session and presence for this user. */ -@interface MXKAccount : NSObject - -/** - The account's credentials: homeserver, access token, user id. - */ -@property (nonatomic, readonly) MXCredentials *mxCredentials; - -/** - The identity server URL. - */ -@property (nonatomic) NSString *identityServerURL; - -/** - The antivirus server URL, if any (nil by default). - Set a non-null url to configure the antivirus scanner use. - */ -@property (nonatomic) NSString *antivirusServerURL; - -/** - The Push Gateway URL used to send event notifications to (nil by default). - This URL should be over HTTPS and never over HTTP. - */ -@property (nonatomic) NSString *pushGatewayURL; +@interface MXKAccount : MXKAccountData /** The matrix REST client used to make matrix API requests. @@ -107,12 +86,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer */ @property (nonatomic, readonly) NSString *fullDisplayName; -/** - The 3PIDs linked to this account. - [self load3PIDs] must be called to update the property. - */ -@property (nonatomic, readonly) NSArray *threePIDs; - /** The email addresses linked to this account. This is a subset of self.threePIDs. @@ -125,12 +98,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer */ @property (nonatomic, readonly) NSArray *linkedPhoneNumbers; -/** - The account user's device. - [self loadDeviceInformation] must be called to update the property. - */ -@property (nonatomic, readonly) MXDevice *device; - /** The account user's presence (`MXPresenceUnknown` by default, available if matrix session `mxSession` is opened). The notification `kMXKAccountUserInfoDidChangeNotification` is posted in case of change of this property. @@ -148,11 +115,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer */ @property (nonatomic, readonly) BOOL pushNotificationServiceIsActive; -/** - Transient information storage. - */ -@property (nonatomic, strong, readonly) NSMutableDictionary> *others; - /** Enable Push notification based on Apple Push Notification Service (APNS). @@ -166,11 +128,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer success:(void (^)(void))success failure:(void (^)(NSError *))failure; -/** - Flag to indicate that an APNS pusher has been set on the homeserver for this device. - */ -@property (nonatomic, readonly) BOOL hasPusherForPushNotifications; - /** The Push notification activity (based on PushKit) for this account. YES when Push is turned on (locally available and enabled homeserver side). @@ -190,26 +147,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer success:(void (^)(void))success failure:(void (^)(NSError *))failure; -/** - Flag to indicate that a PushKit pusher has been set on the homeserver for this device. - */ -@property (nonatomic, readonly) BOOL hasPusherForPushKitNotifications; - - -/** - Enable In-App notifications based on Remote notifications rules. - NO by default. - */ -@property (nonatomic) BOOL enableInAppNotifications; - -/** - Disable the account without logging out (NO by default). - - A matrix session is automatically opened for the account when this property is toggled from YES to NO. - The session is closed when this property is set to YES. - */ -@property (nonatomic,getter=isDisabled) BOOL disabled; - /** Manage the online presence event. @@ -217,11 +154,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer */ @property (nonatomic) BOOL hideUserPresence; -/** - Flag indicating if the end user has been warned about encryption and its limitations. - */ -@property (nonatomic,getter=isWarnedAboutEncryption) BOOL warnedAboutEncryption; - /** Register the MXKAccountOnCertificateChange block that will be used to handle certificate change during account use. This block is nil by default, any new certificate is ignored/untrusted (this will abort the connection to the server). @@ -284,11 +216,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer #pragma mark - Soft logout -/** - Flag to indicate if the account has been logged out by the homeserver admin. - */ -@property (nonatomic, readonly) BOOL isSoftLogout; - /** Soft logout the account. diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index 359cf9ff44..25482b6b53 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -92,13 +92,10 @@ @interface MXKAccount () @property (nonatomic, strong) id backgroundTask; @property (nonatomic, strong) id backgroundSyncBgTask; -@property (nonatomic, strong) NSMutableDictionary> *others; - @end @implementation MXKAccount -@synthesize mxCredentials, mxSession, mxRestClient; -@synthesize threePIDs; +@synthesize mxSession, mxRestClient; @synthesize userPresence; @synthesize userTintColor; @synthesize hideUserPresence; @@ -144,7 +141,7 @@ - (instancetype)initWithCredentials:(MXCredentials*)credentials notifyOpenSessionFailure = YES; // Report credentials and alloc REST client. - mxCredentials = credentials; + _mxCredentials = credentials; [self prepareRESTClient]; userPresence = MXPresenceUnknown; @@ -171,67 +168,19 @@ - (void)dealloc - (id)initWithCoder:(NSCoder *)coder { - self = [super init]; + self = [super initWithCoder:coder]; if (self) { notifyOpenSessionFailure = YES; - NSString *homeServerURL = [coder decodeObjectForKey:@"homeserverurl"]; - NSString *userId = [coder decodeObjectForKey:@"userid"]; - NSString *accessToken = [coder decodeObjectForKey:@"accesstoken"]; - _identityServerURL = [coder decodeObjectForKey:@"identityserverurl"]; - NSString *identityServerAccessToken = [coder decodeObjectForKey:@"identityserveraccesstoken"]; - - mxCredentials = [[MXCredentials alloc] initWithHomeServer:homeServerURL - userId:userId - accessToken:accessToken]; - - mxCredentials.accessTokenExpiresAt = [coder decodeInt64ForKey:@"accessTokenExpiresAt"]; - mxCredentials.refreshToken = [coder decodeObjectForKey:@"refreshToken"]; - mxCredentials.identityServer = _identityServerURL; - mxCredentials.identityServerAccessToken = identityServerAccessToken; - mxCredentials.deviceId = [coder decodeObjectForKey:@"deviceId"]; - mxCredentials.allowedCertificate = [coder decodeObjectForKey:@"allowedCertificate"]; - [self prepareRESTClient]; [self registerAccountDataDidChangeIdentityServerNotification]; [self registerIdentityServiceDidChangeAccessTokenNotification]; - if ([coder decodeObjectForKey:@"threePIDs"]) - { - threePIDs = [coder decodeObjectForKey:@"threePIDs"]; - } - - if ([coder decodeObjectForKey:@"device"]) - { - _device = [coder decodeObjectForKey:@"device"]; - } - userPresence = MXPresenceUnknown; - if ([coder decodeObjectForKey:@"antivirusserverurl"]) - { - _antivirusServerURL = [coder decodeObjectForKey:@"antivirusserverurl"]; - } - - if ([coder decodeObjectForKey:@"pushgatewayurl"]) - { - _pushGatewayURL = [coder decodeObjectForKey:@"pushgatewayurl"]; - } - - _hasPusherForPushNotifications = [coder decodeBoolForKey:@"_enablePushNotifications"]; - _hasPusherForPushKitNotifications = [coder decodeBoolForKey:@"enablePushKitNotifications"]; - _enableInAppNotifications = [coder decodeBoolForKey:@"enableInAppNotifications"]; - - _disabled = [coder decodeBoolForKey:@"disabled"]; - _isSoftLogout = [coder decodeBoolForKey:@"isSoftLogout"]; - - _warnedAboutEncryption = [coder decodeBoolForKey:@"warnedAboutEncryption"]; - - _others = [coder decodeObjectForKey:@"others"]; - // Refresh device information [self loadDeviceInformation:nil failure:nil]; } @@ -239,66 +188,6 @@ - (id)initWithCoder:(NSCoder *)coder return self; } -- (void)encodeWithCoder:(NSCoder *)coder -{ - [coder encodeObject:mxCredentials.homeServer forKey:@"homeserverurl"]; - [coder encodeObject:mxCredentials.userId forKey:@"userid"]; - [coder encodeObject:mxCredentials.accessToken forKey:@"accesstoken"]; - if (mxCredentials.accessTokenExpiresAt) { - [coder encodeInt64:mxCredentials.accessTokenExpiresAt forKey:@"accessTokenExpiresAt"]; - } - if (mxCredentials.refreshToken) { - [coder encodeObject:mxCredentials.refreshToken forKey:@"refreshToken"]; - } - [coder encodeObject:mxCredentials.identityServerAccessToken forKey:@"identityserveraccesstoken"]; - - if (mxCredentials.deviceId) - { - [coder encodeObject:mxCredentials.deviceId forKey:@"deviceId"]; - } - - if (mxCredentials.allowedCertificate) - { - [coder encodeObject:mxCredentials.allowedCertificate forKey:@"allowedCertificate"]; - } - - if (self.threePIDs) - { - [coder encodeObject:threePIDs forKey:@"threePIDs"]; - } - - if (self.device) - { - [coder encodeObject:_device forKey:@"device"]; - } - - if (self.identityServerURL) - { - [coder encodeObject:_identityServerURL forKey:@"identityserverurl"]; - } - - if (self.antivirusServerURL) - { - [coder encodeObject:_antivirusServerURL forKey:@"antivirusserverurl"]; - } - - if (self.pushGatewayURL) - { - [coder encodeObject:_pushGatewayURL forKey:@"pushgatewayurl"]; - } - - [coder encodeBool:_hasPusherForPushNotifications forKey:@"_enablePushNotifications"]; - [coder encodeBool:_hasPusherForPushKitNotifications forKey:@"enablePushKitNotifications"]; - [coder encodeBool:_enableInAppNotifications forKey:@"enableInAppNotifications"]; - - [coder encodeBool:_disabled forKey:@"disabled"]; - [coder encodeBool:_isSoftLogout forKey:@"isSoftLogout"]; - - [coder encodeBool:_warnedAboutEncryption forKey:@"warnedAboutEncryption"]; - - [coder encodeObject:_others forKey:@"others"]; -} - #pragma mark - Properties - (void)setIdentityServerURL:(NSString *)identityServerURL @@ -306,10 +195,10 @@ - (void)setIdentityServerURL:(NSString *)identityServerURL if (identityServerURL.length) { _identityServerURL = identityServerURL; - mxCredentials.identityServer = identityServerURL; + self.mxCredentials.identityServer = identityServerURL; // Update services used in MXSession - [mxSession setIdentityServer:mxCredentials.identityServer andAccessToken:mxCredentials.identityServerAccessToken]; + [mxSession setIdentityServer:self.mxCredentials.identityServer andAccessToken:self.mxCredentials.identityServerAccessToken]; } else { @@ -363,24 +252,24 @@ - (NSString*)fullDisplayName { if (self.userDisplayName.length) { - return [NSString stringWithFormat:@"%@ (%@)", self.userDisplayName, mxCredentials.userId]; + return [NSString stringWithFormat:@"%@ (%@)", self.userDisplayName, self.mxCredentials.userId]; } else { - return mxCredentials.userId; + return self.mxCredentials.userId; } } -- (NSArray *)threePIDs -{ - return threePIDs; -} +//- (NSArray *)threePIDs +//{ +// return _threePIDs; +//} - (NSArray *)linkedEmails { NSMutableArray *linkedEmails = [NSMutableArray array]; - for (MXThirdPartyIdentifier *threePID in threePIDs) + for (MXThirdPartyIdentifier *threePID in self.threePIDs) { if ([threePID.medium isEqualToString:kMX3PIDMediumEmail]) { @@ -395,7 +284,7 @@ - (NSString*)fullDisplayName { NSMutableArray *linkedPhoneNumbers = [NSMutableArray array]; - for (MXThirdPartyIdentifier *threePID in threePIDs) + for (MXThirdPartyIdentifier *threePID in self.threePIDs) { if ([threePID.medium isEqualToString:kMX3PIDMediumMSISDN]) { @@ -410,7 +299,7 @@ - (UIColor*)userTintColor { if (!userTintColor) { - userTintColor = [MXKTools colorWithRGBValue:[mxCredentials.userId hash]]; + userTintColor = [MXKTools colorWithRGBValue:[self.mxCredentials.userId hash]]; } return userTintColor; @@ -418,7 +307,7 @@ - (UIColor*)userTintColor - (BOOL)pushNotificationServiceIsActive { - BOOL pushNotificationServiceIsActive = ([[MXKAccountManager sharedManager] isAPNSAvailable] && _hasPusherForPushNotifications && mxSession); + BOOL pushNotificationServiceIsActive = ([[MXKAccountManager sharedManager] isAPNSAvailable] && self.hasPusherForPushNotifications && mxSession); MXLogDebug(@"[MXKAccount][Push] pushNotificationServiceIsActive: %@", @(pushNotificationServiceIsActive)); return pushNotificationServiceIsActive; @@ -469,7 +358,7 @@ - (void)enablePushNotifications:(BOOL)enable } } } - else if (_hasPusherForPushNotifications) + else if (self.hasPusherForPushNotifications) { MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Disable APNS for %@ account", self.mxCredentials.userId); @@ -495,7 +384,7 @@ - (void)enablePushNotifications:(BOOL)enable - (BOOL)isPushKitNotificationActive { - BOOL isPushKitNotificationActive = ([[MXKAccountManager sharedManager] isPushAvailable] && _hasPusherForPushKitNotifications && mxSession); + BOOL isPushKitNotificationActive = ([[MXKAccountManager sharedManager] isPushAvailable] && self.hasPusherForPushKitNotifications && mxSession); MXLogDebug(@"[MXKAccount][Push] isPushKitNotificationActive: %@", @(isPushKitNotificationActive)); return isPushKitNotificationActive; @@ -543,7 +432,7 @@ - (void)enablePushKitNotifications:(BOOL)enable failure (error); } } - else if (_hasPusherForPushKitNotifications) + else if (self.hasPusherForPushKitNotifications) { MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Disable Push for %@ account", self.mxCredentials.userId); @@ -641,7 +530,7 @@ - (void)setUserDisplayName:(NSString*)displayname success:(void (^)(void))succes success(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId]; } failure:failure]; } @@ -661,7 +550,7 @@ - (void)setUserAvatarUrl:(NSString*)avatarUrl success:(void (^)(void))success fa success(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId]; } failure:failure]; } @@ -694,9 +583,9 @@ - (void)changePassword:(NSString*)oldPassword with:(NSString*)newPassword succes - (void)load3PIDs:(void (^)(void))success failure:(void (^)(NSError *))failure { + [mxRestClient threePIDs:^(NSArray *threePIDs2) { - - self->threePIDs = threePIDs2; + self->_threePIDs = threePIDs2; // Archive updated field [[MXKAccountManager sharedManager] saveAccounts]; @@ -716,9 +605,9 @@ - (void)load3PIDs:(void (^)(void))success failure:(void (^)(NSError *))failure - (void)loadDeviceInformation:(void (^)(void))success failure:(void (^)(NSError *error))failure { - if (mxCredentials.deviceId) + if (self.mxCredentials.deviceId) { - [mxRestClient deviceByDeviceId:mxCredentials.deviceId success:^(MXDevice *device) { + [mxRestClient deviceByDeviceId:self.mxCredentials.deviceId success:^(MXDevice *device) { self->_device = device; @@ -759,21 +648,21 @@ - (void)setUserPresence:(MXPresence)presence andStatusMessage:(NSString *)status [mxSession.myUser setPresence:userPresence andStatusMessage:statusMessage success:^{ - MXLogDebug(@"[MXKAccount] %@: set user presence (%lu) succeeded", self->mxCredentials.userId, (unsigned long)self->userPresence); + MXLogDebug(@"[MXKAccount] %@: set user presence (%lu) succeeded", self.mxCredentials.userId, (unsigned long)self->userPresence); if (completion) { completion(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId]; } failure:^(NSError *error) { - MXLogDebug(@"[MXKAccount] %@: set user presence (%lu) failed", self->mxCredentials.userId, (unsigned long)self->userPresence); + MXLogDebug(@"[MXKAccount] %@: set user presence (%lu) failed", self.mxCredentials.userId, (unsigned long)self->userPresence); }]; } else if (hideUserPresence) { - MXLogDebug(@"[MXKAccount] %@: set user presence is disabled.", mxCredentials.userId); + MXLogDebug(@"[MXKAccount] %@: set user presence is disabled.", self.mxCredentials.userId); } } @@ -791,7 +680,7 @@ - (void)setUserPresence:(MXPresence)presence andStatusMessage:(NSString *)status -(void)openSessionWithStore:(id)store { // Sanity check - if (!mxCredentials || !mxRestClient) + if (!self.mxCredentials || !mxRestClient) { MXLogDebug(@"[MXKAccount] Matrix session cannot be created without credentials"); return; @@ -1056,9 +945,9 @@ - (void)softLogout - (void)hydrateWithCredentials:(MXCredentials*)credentials { // Sanity check - if ([mxCredentials.userId isEqualToString:credentials.userId]) + if ([self.mxCredentials.userId isEqualToString:credentials.userId]) { - mxCredentials = credentials; + _mxCredentials = credentials; _isSoftLogout = NO; [[MXKAccountManager sharedManager] saveAccounts]; @@ -1066,11 +955,13 @@ - (void)hydrateWithCredentials:(MXCredentials*)credentials } else { - MXLogDebug(@"[MXKAccount] hydrateWithCredentials: Error: users ids mismatch: %@ vs %@", credentials.userId, mxCredentials.userId); + MXLogDebug(@"[MXKAccount] hydrateWithCredentials: Error: users ids mismatch: %@ vs %@", credentials.userId, self.mxCredentials.userId); } } + + - (void)deletePusher { if (self.pushNotificationServiceIsActive) @@ -1267,7 +1158,7 @@ - (void)enableAPNSPusher:(BOOL)enabled success:(void (^)(void))success failure:( success(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId]; } failure:^(NSError *error) { @@ -1286,7 +1177,7 @@ - (void)enableAPNSPusher:(BOOL)enabled success:(void (^)(void))success failure:( success(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId]; return; } @@ -1303,7 +1194,7 @@ - (void)enableAPNSPusher:(BOOL)enabled success:(void (^)(void))success failure:( failure(error); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId]; }]; } @@ -1330,7 +1221,7 @@ - (void)refreshPushKitPusher MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: Error: %@", error); }]; } - else if (_hasPusherForPushKitNotifications) + else if (self.hasPusherForPushKitNotifications) { if ([MXKAccountManager sharedManager].pushDeviceToken) { @@ -1344,7 +1235,7 @@ - (void)refreshPushKitPusher else { MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: PushKit pusher for %@ account is already disabled. Reset _hasPusherForPushKitNotifications", self.mxCredentials.userId); - _hasPusherForPushKitNotifications = NO; + self->_hasPusherForPushKitNotifications = NO; [[MXKAccountManager sharedManager] saveAccounts]; } } @@ -1406,7 +1297,7 @@ - (void)enablePushKitPusher:(BOOL)enabled success:(void (^)(void))success failur success(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self.mxCredentials.userId]; } failure:^(NSError *error) { @@ -1425,7 +1316,7 @@ - (void)enablePushKitPusher:(BOOL)enabled success:(void (^)(void))success failur success(); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self.mxCredentials.userId]; return; } @@ -1442,7 +1333,7 @@ - (void)enablePushKitPusher:(BOOL)enabled success:(void (^)(void))success failur failure(error); } - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self.mxCredentials.userId]; }]; } @@ -1451,7 +1342,7 @@ - (void)enablePusher:(BOOL)enabled appId:(NSString*)appId token:(NSData*)token p MXLogDebug(@"[MXKAccount][Push] enablePusher: %@", @(enabled)); // Refuse to try & turn push on if we're not logged in, it's nonsensical. - if (!mxCredentials) + if (!self.mxCredentials) { MXLogDebug(@"[MXKAccount][Push] enablePusher: Not setting push token because we're not logged in"); return; @@ -1618,7 +1509,7 @@ - (void)launchInitialServerSync [self.mxSession startWithSyncFilter:syncFilter onServerSyncDone:^{ MXStrongifyAndReturnIfNil(self); - MXLogDebug(@"[MXKAccount] %@: The session is ready. Matrix SDK session has been started in %0.fms.", self->mxCredentials.userId, [[NSDate date] timeIntervalSinceDate:self->openSessionStartDate] * 1000); + MXLogDebug(@"[MXKAccount] %@: The session is ready. Matrix SDK session has been started in %0.fms.", self.mxCredentials.userId, [[NSDate date] timeIntervalSinceDate:self->openSessionStartDate] * 1000); [self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil]; @@ -1753,11 +1644,11 @@ - (void)onMatrixSessionStateChange } // Here displayname or other information have been updated, post update notification. - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self->mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId]; }]; // User information are just up-to-date (`mxSession` is running), post update notification. - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId]; } } else if (mxSession.state == MXSessionStateStoreDataReady || mxSession.state == MXSessionStateSyncInProgress) @@ -1772,7 +1663,7 @@ - (void)onMatrixSessionStateChange { // Here the initial server sync is in progress. The session is not running yet, but some user's information are available (from local storage). // We post update notification to let observer take into account this user's information even if they may not be up-to-date. - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:mxCredentials.userId]; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId]; } } else if (mxSession.state == MXSessionStatePaused) @@ -1782,7 +1673,7 @@ - (void)onMatrixSessionStateChange else if (mxSession.state == MXSessionStateUnauthenticated) { // Logout this account - [[MXKAccountManager sharedManager] removeAccount:self completion:nil]; + [[MXKAccountManager sharedManager] removeAccount:self sendLogoutRequest:NO completion:nil]; } else if (mxSession.state == MXSessionStateSoftLogout) { @@ -1793,19 +1684,19 @@ - (void)onMatrixSessionStateChange - (void)prepareRESTClient { - if (!mxCredentials) + if (!self.mxCredentials) { return; } - mxRestClient = [[MXRestClient alloc] initWithCredentials:mxCredentials andOnUnrecognizedCertificateBlock:^BOOL(NSData *certificate) { + mxRestClient = [[MXRestClient alloc] initWithCredentials:self.mxCredentials andOnUnrecognizedCertificateBlock:^BOOL(NSData *certificate) { if (_onCertificateChangeBlock) { if (_onCertificateChangeBlock (self, certificate)) { // Update the certificate in credentials - self->mxCredentials.allowedCertificate = certificate; + self.mxCredentials.allowedCertificate = certificate; // Archive updated field [[MXKAccountManager sharedManager] saveAccounts]; @@ -1813,13 +1704,15 @@ - (void)prepareRESTClient return YES; } - self->mxCredentials.ignoredCertificate = certificate; + self.mxCredentials.ignoredCertificate = certificate; // Archive updated field [[MXKAccountManager sharedManager] saveAccounts]; } return NO; + } andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { + [MXKAccountManager.sharedManager readAndWriteCredentials:handler]; }]; } @@ -1875,7 +1768,7 @@ - (void)onDateTimeFormatUpdate #pragma mark - Crypto - (void)resetDeviceId { - mxCredentials.deviceId = nil; + self.mxCredentials.deviceId = nil; // Archive updated field [[MXKAccountManager sharedManager] saveAccounts]; @@ -2191,11 +2084,11 @@ - (void)handleAccountDataDidChangeIdentityServerNotification:(NSNotification*)no MXSession *mxSession = notification.object; if (mxSession == self.mxSession) { - if (![mxCredentials.identityServer isEqualToString:self.mxSession.accountDataIdentityServer]) + if (![self.mxCredentials.identityServer isEqualToString:self.mxSession.accountDataIdentityServer]) { _identityServerURL = self.mxSession.accountDataIdentityServer; - mxCredentials.identityServer = _identityServerURL; - mxCredentials.identityServerAccessToken = nil; + self.mxCredentials.identityServer = _identityServerURL; + self.mxCredentials.identityServerAccessToken = nil; // Archive updated field [[MXKAccountManager sharedManager] saveAccounts]; @@ -2208,7 +2101,7 @@ - (void)handleAccountDataDidChangeIdentityServerNotification:(NSNotification*)no - (void)identityService:(MXIdentityService *)identityService didUpdateAccessToken:(NSString *)accessToken { - mxCredentials.identityServerAccessToken = accessToken; + self.mxCredentials.identityServerAccessToken = accessToken; } - (void)registerIdentityServiceDidChangeAccessTokenNotification @@ -2224,9 +2117,9 @@ - (void)handleIdentityServiceDidChangeAccessTokenNotification:(NSNotification*)n NSString *identityServer = userInfo[MXIdentityServiceNotificationIdentityServerKey]; NSString *accessToken = userInfo[MXIdentityServiceNotificationAccessTokenKey]; - if (userId && identityServer && accessToken && [mxCredentials.identityServer isEqualToString:identityServer]) + if (userId && identityServer && accessToken && [self.mxCredentials.identityServer isEqualToString:identityServer]) { - mxCredentials.identityServerAccessToken = accessToken; + self.mxCredentials.identityServerAccessToken = accessToken; // Archive updated field [[MXKAccountManager sharedManager] saveAccounts]; diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h new file mode 100644 index 0000000000..b5cc5512b1 --- /dev/null +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h @@ -0,0 +1,141 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#import + +@class MXKAccountData; + +@interface MXKAccountData : NSObject { + +@protected MXCredentials *_mxCredentials; +@protected NSString *_identityServerURL; +@protected NSString *_antivirusServerURL; +@protected NSString *_pushGatewayURL; +@protected MXDevice *_device; +@protected BOOL _disabled; +@protected BOOL _enableInAppNotifications; +@protected BOOL _warnedAboutEncryption; +@protected NSMutableDictionary> *_others; +@protected NSArray *_threePIDs; +@protected BOOL _isSoftLogout; +@protected BOOL _hasPusherForPushNotifications; +@protected BOOL _hasPusherForPushKitNotifications; +} + +/** + The account's credentials: homeserver, access token, user id. + */ +@property (nonatomic, readonly) MXCredentials *mxCredentials; + +/** + The identity server URL. + */ +@property (nonatomic) NSString *identityServerURL; + +/** + The antivirus server URL, if any (nil by default). + Set a non-null url to configure the antivirus scanner use. + */ +@property (nonatomic) NSString *antivirusServerURL; + +/** + The Push Gateway URL used to send event notifications to (nil by default). + This URL should be over HTTPS and never over HTTP. + */ +@property (nonatomic) NSString *pushGatewayURL; + +/** + The 3PIDs linked to this account. + [self load3PIDs] must be called to update the property. + */ +@property (nonatomic, readonly) NSArray *threePIDs; + +/** + The email addresses linked to this account. + This is a subset of self.threePIDs. + */ +@property (nonatomic, readonly) NSArray *linkedEmails; + +/** + The phone numbers linked to this account. + This is a subset of self.threePIDs. + */ +@property (nonatomic, readonly) NSArray *linkedPhoneNumbers; + +/** + The account user's device. + [self loadDeviceInformation] must be called to update the property. + */ +@property (nonatomic, readonly) MXDevice *device; + +/** + The account user's tint color: a unique color fixed by the user id. This tint color may be used to highlight + rooms which belong to this account's user. + */ +@property (nonatomic, readonly) UIColor *userTintColor; + +/** + The Apple Push Notification Service activity for this account. YES when APNS is turned on (locally available and synced with server). + */ +@property (nonatomic, readonly) BOOL pushNotificationServiceIsActive; + +/** + Transient information storage. + */ +@property (nonatomic, strong, readonly) NSMutableDictionary> *others; + +/** + Flag to indicate that an APNS pusher has been set on the homeserver for this device. + */ +@property (nonatomic, readonly) BOOL hasPusherForPushNotifications; + +/** + The Push notification activity (based on PushKit) for this account. + YES when Push is turned on (locally available and enabled homeserver side). + */ +@property (nonatomic, readonly) BOOL isPushKitNotificationActive; + +/** + Flag to indicate that a PushKit pusher has been set on the homeserver for this device. + */ +@property (nonatomic, readonly) BOOL hasPusherForPushKitNotifications; + + +/** + Enable In-App notifications based on Remote notifications rules. + NO by default. + */ +@property (nonatomic) BOOL enableInAppNotifications; + +/** + Disable the account without logging out (NO by default). + + A matrix session is automatically opened for the account when this property is toggled from YES to NO. + The session is closed when this property is set to YES. + */ +@property (nonatomic,getter=isDisabled) BOOL disabled; + +/** + Flag indicating if the end user has been warned about encryption and its limitations. + */ +@property (nonatomic,getter=isWarnedAboutEncryption) BOOL warnedAboutEncryption; + +#pragma mark - Soft logout + +/** + Flag to indicate if the account has been logged out by the homeserver admin. + */ +@property (nonatomic, readonly) BOOL isSoftLogout; +@end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.m new file mode 100644 index 0000000000..4d59e2a4b7 --- /dev/null +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.m @@ -0,0 +1,150 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "MXKAccountData.h" + +@interface MXKAccountData () + +@end + +@implementation MXKAccountData + +@synthesize mxCredentials = _mxCredentials; + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)coder +{ + self = [super init]; + + if (self) + { + + NSString *homeServerURL = [coder decodeObjectForKey:@"homeserverurl"]; + NSString *userId = [coder decodeObjectForKey:@"userid"]; + NSString *accessToken = [coder decodeObjectForKey:@"accesstoken"]; + _identityServerURL = [coder decodeObjectForKey:@"identityserverurl"]; + NSString *identityServerAccessToken = [coder decodeObjectForKey:@"identityserveraccesstoken"]; + + _mxCredentials = [[MXCredentials alloc] initWithHomeServer:homeServerURL + userId:userId + accessToken:accessToken]; + + _mxCredentials.accessTokenExpiresAt = [coder decodeInt64ForKey:@"accessTokenExpiresAt"]; + _mxCredentials.refreshToken = [coder decodeObjectForKey:@"refreshToken"]; + _mxCredentials.identityServer = _identityServerURL; + _mxCredentials.identityServerAccessToken = identityServerAccessToken; + _mxCredentials.deviceId = [coder decodeObjectForKey:@"deviceId"]; + _mxCredentials.allowedCertificate = [coder decodeObjectForKey:@"allowedCertificate"]; + + if ([coder decodeObjectForKey:@"threePIDs"]) + { + _threePIDs = [coder decodeObjectForKey:@"threePIDs"]; + } + + if ([coder decodeObjectForKey:@"device"]) + { + _device = [coder decodeObjectForKey:@"device"]; + } + + if ([coder decodeObjectForKey:@"antivirusserverurl"]) + { + _antivirusServerURL = [coder decodeObjectForKey:@"antivirusserverurl"]; + } + + if ([coder decodeObjectForKey:@"pushgatewayurl"]) + { + _pushGatewayURL = [coder decodeObjectForKey:@"pushgatewayurl"]; + } + + _hasPusherForPushNotifications = [coder decodeBoolForKey:@"_enablePushNotifications"]; + _hasPusherForPushKitNotifications = [coder decodeBoolForKey:@"enablePushKitNotifications"]; + _enableInAppNotifications = [coder decodeBoolForKey:@"enableInAppNotifications"]; + + _disabled = [coder decodeBoolForKey:@"disabled"]; + _isSoftLogout = [coder decodeBoolForKey:@"isSoftLogout"]; + + _warnedAboutEncryption = [coder decodeBoolForKey:@"warnedAboutEncryption"]; + + _others = [coder decodeObjectForKey:@"others"]; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:_mxCredentials.homeServer forKey:@"homeserverurl"]; + [coder encodeObject:_mxCredentials.userId forKey:@"userid"]; + [coder encodeObject:_mxCredentials.accessToken forKey:@"accesstoken"]; + if (self.mxCredentials.accessTokenExpiresAt) { + [coder encodeInt64:_mxCredentials.accessTokenExpiresAt forKey:@"accessTokenExpiresAt"]; + } + if (self.mxCredentials.refreshToken) { + [coder encodeObject:_mxCredentials.refreshToken forKey:@"refreshToken"]; + } + [coder encodeObject:_mxCredentials.identityServerAccessToken forKey:@"identityserveraccesstoken"]; + + if (self.mxCredentials.deviceId) + { + [coder encodeObject:_mxCredentials.deviceId forKey:@"deviceId"]; + } + + if (self.mxCredentials.allowedCertificate) + { + [coder encodeObject:_mxCredentials.allowedCertificate forKey:@"allowedCertificate"]; + } + + if (self.threePIDs) + { + [coder encodeObject:_threePIDs forKey:@"threePIDs"]; + } + + if (self.device) + { + [coder encodeObject:_device forKey:@"device"]; + } + + if (self.identityServerURL) + { + [coder encodeObject:_identityServerURL forKey:@"identityserverurl"]; + } + + if (self.antivirusServerURL) + { + [coder encodeObject:_antivirusServerURL forKey:@"antivirusserverurl"]; + } + + if (self.pushGatewayURL) + { + [coder encodeObject:_pushGatewayURL forKey:@"pushgatewayurl"]; + } + + [coder encodeBool:_hasPusherForPushNotifications forKey:@"_enablePushNotifications"]; + [coder encodeBool:_hasPusherForPushKitNotifications forKey:@"enablePushKitNotifications"]; + [coder encodeBool:_enableInAppNotifications forKey:@"enableInAppNotifications"]; + + [coder encodeBool:_disabled forKey:@"disabled"]; + [coder encodeBool:_isSoftLogout forKey:@"isSoftLogout"]; + + [coder encodeBool:_warnedAboutEncryption forKey:@"warnedAboutEncryption"]; + + [coder encodeObject:_others forKey:@"others"]; +} + + +@end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.h index 70c4857c9f..cfbec2a9ab 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.h +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.h @@ -110,6 +110,8 @@ extern NSString *const MXKAccountManagerDataType; */ + (MXKAccountManager *)sharedManager; ++ (MXKAccountManager *)sharedManagerWithReload:(BOOL)reload; + /** Check for each enabled account if a matrix session is already opened. Open a matrix session for each enabled account which doesn't have a session. @@ -208,11 +210,6 @@ extern NSString *const MXKAccountManagerDataType; */ - (MXKAccount *)accountKnowingUserWithUserId:(NSString *)userId; -/** - Force the account manager to reload existing accounts from the local storage. - The account manager is supposed to handle itself the list of the accounts. - Call this method only when an account has been changed from an other application from the same group. - */ -- (void)forceReloadAccounts; +- (void)readAndWriteCredentials:(void (^)(NSArray * _Nullable readData, void (^completion)(BOOL didUpdateCredentials)))readAnWriteHandler; @end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m index 080a7ace41..a8947f4efc 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m @@ -21,6 +21,8 @@ #import "MXKAppSettings.h" #import "MXKTools.h" +#import "MXKAccountData.h" +#import "MXRefreshTokenData.h" static NSString *const kMXKAccountsKeyOld = @"accounts"; static NSString *const kMXKAccountsKey = @"accountsV2"; @@ -43,13 +45,23 @@ The list of all accounts (enabled and disabled). Each value is a `MXKAccount` in @implementation MXKAccountManager + (MXKAccountManager *)sharedManager +{ + return [MXKAccountManager sharedManagerWithReload:NO]; +} + ++ (MXKAccountManager *)sharedManagerWithReload:(BOOL)reload { static MXKAccountManager *sharedAccountManager = nil; static dispatch_once_t onceToken; + __block BOOL didLoad = false; dispatch_once(&onceToken, ^{ + didLoad = true; sharedAccountManager = [[super allocWithZone:NULL] init]; }); + if (reload && !didLoad) { + [sharedAccountManager loadAccounts]; + } return sharedAccountManager; } @@ -66,8 +78,6 @@ - (instancetype)init // Load existing accounts from local storage [self loadAccounts]; - - [self registerRestClientDidRefreshTokensNotification]; } return self; } @@ -601,7 +611,6 @@ - (NSString*)accountFile - (void)loadAccounts { MXLogDebug(@"[MXKAccountManager] loadAccounts"); - NSString *accountFile = [self accountFile]; if ([[NSFileManager defaultManager] fileExistsAtPath:accountFile]) { @@ -667,12 +676,6 @@ - (void)loadAccounts } } -- (void)forceReloadAccounts -{ - MXLogDebug(@"[MXKAccountManager] Force reload existing accounts from local storage"); - [self loadAccounts]; -} - - (NSData*)encryptData:(NSData*)data { // Exceptions are not caught as the key is always needed if the KeyProviderDelegate @@ -725,17 +728,69 @@ - (void)migrateAccounts } } -#pragma mark - Homeserver Access/Refresh Token updates - -- (void)registerRestClientDidRefreshTokensNotification +- (void)readAndWriteCredentials:(void (^)(NSArray * _Nullable readData, void (^completion)(BOOL didUpdateCredentials)))readAnWriteHandler { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRestClientDidRefreshTokensNotification:) name:MXRestClientDidRefreshTokensNotification object:nil]; + NSError *error; + NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init]; + __block BOOL coordinatorSuccess = NO; + NSLog(@"[MXKAccountManager] readAndWriteCredentials: purposeIdentifier = %@", fileCoordinator.purposeIdentifier); + NSDate *coordinateStartTime = [NSDate date]; + [fileCoordinator coordinateReadingItemAtURL:[self accountFileUrl] + options:0 + writingItemAtURL:[self accountFileUrl] + options:NSFileCoordinatorWritingForMerging + error:&error + byAccessor:^(NSURL * _Nonnull newReadingURL, NSURL * _Nonnull newWritingURL) { + + NSDate *accessorStartTime = [NSDate date]; + NSTimeInterval acquireInterval = [accessorStartTime timeIntervalSinceDate:coordinateStartTime]; + NSLog(@"[MXKAccountManager] readAndWriteCredentials: acquireInterval = %f", acquireInterval); + NSError *error = nil; + NSData* data = [NSData dataWithContentsOfURL:newReadingURL options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:&error]; + + // Decrypt data if encryption method is provided + NSData *unciphered = [self decryptData:data]; + NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingFromData:unciphered error:&error]; + decoder.requiresSecureCoding = false; + [decoder setClass:[MXKAccountData class] forClassName:@"MXKAccount"]; + NSMutableArray* mxAccountsData = [decoder decodeObjectForKey:@"mxAccounts"]; + NSMutableArray* mxAccountCredentials = [NSMutableArray arrayWithCapacity:mxAccounts.count]; + for(MXKAccountData *account in mxAccountsData){ + [mxAccountCredentials addObject:account.mxCredentials]; + } + + dispatch_group_t dispatchGroup = dispatch_group_create(); + dispatch_group_enter(dispatchGroup); + + __block BOOL didUpdate = NO; + readAnWriteHandler(mxAccountCredentials, ^(BOOL didUpdateCredentials) { + didUpdate = didUpdateCredentials; + dispatch_group_leave(dispatchGroup); + }); + + dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER); + + if (didUpdate) { + NSLog(@"[MXKAccountManager] readAndWriteCredentials: did update saving credential data"); + NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initRequiringSecureCoding: NO]; + [encoder setClassName:@"MXKAccount" forClass:[MXKAccountData class]]; + [encoder encodeObject:mxAccountsData forKey:@"mxAccounts"]; + NSData *writeData = [self encryptData:[encoder encodedData]]; + coordinatorSuccess = [writeData writeToURL:newWritingURL atomically:YES]; + } else { + NSLog(@"[MXKAccountManager] readAndWriteCredentials: did not update not saving credential data"); + coordinatorSuccess = YES; + } + NSDate *accessorEndTime = [NSDate date]; + NSTimeInterval lockedTime = [accessorEndTime timeIntervalSinceDate:accessorStartTime]; + NSLog(@"[MXKAccountManager] readAndWriteCredentials: lockedTime = %f", lockedTime); + }]; + NSLog(@"[MXKAccountManager] readAndWriteCredentials:exit"); } -- (void)handleRestClientDidRefreshTokensNotification:(NSNotification*)notification +- (NSURL *)accountFileUrl { - [self saveAccounts]; + return [NSURL fileURLWithPath: [self accountFile]]; } - @end diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index f669b95934..cd8494f24f 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -56,7 +56,9 @@ class NotificationService: UNNotificationServiceExtension { guard let userAccount = userAccount else { return nil } - let restClient = MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil) + let restClient = MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil) { persistTokenDataHandler in + MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler) + } restClient.refreshTokensFailedHandler = { mxError in MXLog.debug("[NotificationService] mxRestClient: The rest client is no longer authenticated.") if let mxError = mxError, @@ -180,14 +182,16 @@ class NotificationService: UNNotificationServiceExtension { } private func setup(withRoomId roomId: String, eventId: String, completion: @escaping () -> Void) { - MXKAccountManager.shared()?.forceReloadAccounts() + MXKAccountManager.sharedManager(withReload: true) self.userAccount = MXKAccountManager.shared()?.activeAccounts.first if let userAccount = userAccount { Self.backgroundServiceInitQueue.sync { if NotificationService.backgroundSyncService?.credentials != userAccount.mxCredentials { MXLog.debug("[NotificationService] setup: MXBackgroundSyncService init: BEFORE") self.logMemory() - NotificationService.backgroundSyncService = MXBackgroundSyncService(withCredentials: userAccount.mxCredentials) + NotificationService.backgroundSyncService = MXBackgroundSyncService(withCredentials: userAccount.mxCredentials, persistTokenDataHandler: { persistTokenDataHandler in + MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler) + }) MXLog.debug("[NotificationService] setup: MXBackgroundSyncService init: AFTER") self.logMemory() } diff --git a/RiotShareExtension/Shared/ShareDataSource.m b/RiotShareExtension/Shared/ShareDataSource.m index aa064c5a5a..7bfcfab731 100644 --- a/RiotShareExtension/Shared/ShareDataSource.m +++ b/RiotShareExtension/Shared/ShareDataSource.m @@ -82,7 +82,9 @@ - (void)loadCellData NSMutableArray *cellData = [NSMutableArray array]; // Add a fake matrix session to each room summary to provide it a REST client (used to handle correctly the room avatar). - MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.credentials andOnUnrecognizedCertificateBlock:nil]]; + MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.credentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { + [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; + }]]; for (MXRoomSummary *roomSummary in roomsSummaries) { diff --git a/RiotShareExtension/Shared/ShareManager.m b/RiotShareExtension/Shared/ShareManager.m index d955f9da10..ee306286d6 100644 --- a/RiotShareExtension/Shared/ShareManager.m +++ b/RiotShareExtension/Shared/ShareManager.m @@ -78,7 +78,9 @@ - (UIViewController *)mainViewController - (void)shareViewController:(ShareViewController *)shareViewController didRequestShareForRoomIdentifiers:(NSSet *)roomIdentifiers { - MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil]]; + MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { + [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; + }]]; [MXFileStore setPreloadOptions:0]; MXWeakify(session); @@ -147,7 +149,7 @@ - (void)showFailureAlert:(NSString *)title - (void)checkUserAccount { // Force account manager to reload account from the local storage. - [[MXKAccountManager sharedManager] forceReloadAccounts]; + [MXKAccountManager sharedManagerWithReload:YES]; if (self.userAccount) { From 56475bbec1b9b4ad8ed90e6453983c23ca050ebf Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 10 Jan 2022 21:38:24 +0000 Subject: [PATCH 04/16] Remove duplicated logout code and fix spinner. - Remove some duplication of logout behaviour - Fix additional spinner on homeViewController --- .../UserSessions/UserSessionsService.swift | 2 +- Riot/Modules/Application/LegacyAppDelegate.m | 16 ++++---- ...ollerWithBannerWrapperViewController.swift | 22 ++++++++++- .../MXKAuthenticationViewController.m | 2 +- .../MatrixKit/Models/Account/MXKAccount.h | 4 ++ .../MatrixKit/Models/Account/MXKAccount.m | 37 +++++++++++-------- RiotNSE/NotificationService.swift | 21 +++-------- RiotShareExtension/Shared/ShareDataSource.m | 7 ++-- RiotShareExtension/Shared/ShareManager.m | 9 ++++- 9 files changed, 74 insertions(+), 46 deletions(-) diff --git a/Riot/Managers/UserSessions/UserSessionsService.swift b/Riot/Managers/UserSessions/UserSessionsService.swift index 576e0d22f8..7a68d9752a 100644 --- a/Riot/Managers/UserSessions/UserSessionsService.swift +++ b/Riot/Managers/UserSessions/UserSessionsService.swift @@ -155,7 +155,7 @@ class UserSessionsService: NSObject { let isSessionStateValid: Bool switch mxSession.state { - case .closed, .unauthenticated: + case .closed: isSessionStateValid = false default: isSessionStateValid = true diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index fd6354ad39..37ca135d3d 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1372,9 +1372,9 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin else { void(^findRoom)(void) = ^{ - if ([_masterTabBarController.selectedViewController isKindOfClass:MXKActivityHandlingViewController.class]) + if ([_masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) { - MXKActivityHandlingViewController *homeViewController = (MXKActivityHandlingViewController*)_masterTabBarController.selectedViewController; + UIViewController *homeViewController = (UIViewController*)_masterTabBarController.selectedViewController; [homeViewController startActivityIndicator]; @@ -1651,11 +1651,13 @@ - (void)peekInRoomWithNavigationParameters:(RoomPreviewNavigationParameters*)pre // Try to get more information about the room before opening its preview [roomPreviewData peekInRoom:^(BOOL succeeded) { MXStrongifyAndReturnIfNil(self); - - MXKViewController *homeViewController = (MXKViewController*)self.masterTabBarController.selectedViewController; - - // Note: the activity indicator will not disappear if the session is not ready - [homeViewController stopActivityIndicator]; + if ([self.masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) + { + UIViewController *homeViewController = (UIViewController*)self.masterTabBarController.selectedViewController; + + // Note: the activity indicator will not disappear if the session is not ready + [homeViewController stopActivityIndicator]; + } // If no data is available for this room, we name it with the known room alias (if any). if (!succeeded && self->universalLinkFragmentPendingRoomAlias[roomIdOrAlias]) diff --git a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift index 85abec4d1a..bae7d1eadf 100644 --- a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift +++ b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift @@ -16,8 +16,8 @@ import Foundation -class HomeViewControllerWithBannerWrapperViewController: MXKActivityHandlingViewController, BannerPresentationProtocol { - +class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKViewControllerActivityHandling, BannerPresentationProtocol { + @objc let homeViewController: HomeViewController private var bannerContainerView: UIView! private var stackView: UIStackView! @@ -85,4 +85,22 @@ class HomeViewControllerWithBannerWrapperViewController: MXKActivityHandlingView bannerView.removeFromSuperview() } } + + // MARK: - MXKViewControllerActivityHandling + var activityIndicator: UIActivityIndicatorView! { + get { + return homeViewController.activityIndicator + } + set { + homeViewController.activityIndicator = newValue + } + } + + func startActivityIndicator() { + homeViewController.startActivityIndicator() + } + + func stopActivityIndicator() { + homeViewController.stopActivityIndicator() + } } diff --git a/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m index acccd6a293..18d65c9272 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m @@ -1453,7 +1453,7 @@ - (void)attemptDeviceRehydrationWithKeyData:(NSData *)keyData return NO; } andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; - }]; + } andUnauthenticatedHandler: nil]; MXWeakify(self); [[MXKAccountManager sharedManager].dehydrationService rehydrateDeviceWithMatrixRestClient:mxRestClient dehydrationKey:keyData success:^(NSString * deviceId) { diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h index 5e928299c4..b9eea90a4a 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h @@ -359,4 +359,8 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer success:(void (^)(void))success failure:(void (^)(NSError *error))failure; +/** + Handle unauthenticated errors from the server triggering hard/soft logouts as appropriate. + */ +- (void)handleUnauthenticated:(MXError *)error andCompletion:(void (^)(void))completion; @end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index 25482b6b53..69db123221 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -959,9 +959,6 @@ - (void)hydrateWithCredentials:(MXCredentials*)credentials } } - - - - (void)deletePusher { if (self.pushNotificationServiceIsActive) @@ -1670,16 +1667,6 @@ - (void)onMatrixSessionStateChange { isPauseRequested = NO; } - else if (mxSession.state == MXSessionStateUnauthenticated) - { - // Logout this account - [[MXKAccountManager sharedManager] removeAccount:self sendLogoutRequest:NO completion:nil]; - } - else if (mxSession.state == MXSessionStateSoftLogout) - { - // Soft logout this account - [[MXKAccountManager sharedManager] softLogout:self]; - } } - (void)prepareRESTClient @@ -1688,9 +1675,9 @@ - (void)prepareRESTClient { return; } - + MXWeakify(self); mxRestClient = [[MXRestClient alloc] initWithCredentials:self.mxCredentials andOnUnrecognizedCertificateBlock:^BOOL(NSData *certificate) { - + MXStrongifyAndReturnValueIfNil(self, NO); if (_onCertificateChangeBlock) { if (_onCertificateChangeBlock (self, certificate)) @@ -1713,9 +1700,29 @@ - (void)prepareRESTClient } andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { [MXKAccountManager.sharedManager readAndWriteCredentials:handler]; + } andUnauthenticatedHandler:^(MXError *error, void (^completion)(void)) { + MXStrongifyAndReturnIfNil(self); + [self handleUnauthenticated:error andCompletion:completion]; }]; } + +- (void)handleUnauthenticated:(MXError *)error andCompletion:(void (^)(void))completion +{ + if (error.httpResponse.statusCode == 401 + && [error.userInfo[kMXErrorSoftLogoutKey] isEqual:@(YES)]) + { + MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: soft logout."); + [[MXKAccountManager sharedManager] softLogout:self]; + completion(); + } + else + { + MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: hard logout."); + [[MXKAccountManager sharedManager] removeAccount:self sendLogoutRequest:NO completion:completion]; + } +} + - (void)onDateTimeFormatUpdate { if ([mxSession.roomSummaryUpdateDelegate isKindOfClass:MXKEventFormatter.class]) diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index e28b861a82..b6a921b77d 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -56,22 +56,11 @@ class NotificationService: UNNotificationServiceExtension { guard let userAccount = userAccount else { return nil } - let restClient = MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil) { persistTokenDataHandler in + let restClient = MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil, persistentTokenDataHandler: { persistTokenDataHandler in MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler) - } - restClient.refreshTokensFailedHandler = { mxError in - MXLog.debug("[NotificationService] mxRestClient: The rest client is no longer authenticated.") - if let mxError = mxError, - mxError.httpResponse.statusCode == 401, - let softLogout = mxError.userInfo[kMXErrorSoftLogoutKey] as? Bool, - softLogout { - MXLog.debug("[NotificationService] mxRestClient: soft logout"); - userAccount.softLogout() - } else { - MXLog.debug("[NotificationService] mxRestClient: full logout"); - MXKAccountManager.shared().removeAccount(userAccount, completion: nil) - } - } + }, unauthenticatedHandler: { error, completion in + userAccount.handleUnauthenticated(error, andCompletion: completion) + }) return restClient }() @@ -191,6 +180,8 @@ class NotificationService: UNNotificationServiceExtension { self.logMemory() NotificationService.backgroundSyncService = MXBackgroundSyncService(withCredentials: userAccount.mxCredentials, persistTokenDataHandler: { persistTokenDataHandler in MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler) + }, unauthenticatedHandler: { error, completion in + userAccount.handleUnauthenticated(error, andCompletion: completion) }) MXLog.debug("[NotificationService] setup: MXBackgroundSyncService init: AFTER") self.logMemory() diff --git a/RiotShareExtension/Shared/ShareDataSource.m b/RiotShareExtension/Shared/ShareDataSource.m index 7bfcfab731..9f213a8400 100644 --- a/RiotShareExtension/Shared/ShareDataSource.m +++ b/RiotShareExtension/Shared/ShareDataSource.m @@ -81,10 +81,11 @@ - (void)loadCellData NSMutableArray *cellData = [NSMutableArray array]; - // Add a fake matrix session to each room summary to provide it a REST client (used to handle correctly the room avatar). - MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.credentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { + MXRestClient *mxRestClient = [[MXRestClient alloc] initWithCredentials:self.credentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; - }]]; + } andUnauthenticatedHandler:nil]; + // Add a fake matrix session to each room summary to provide it a REST client (used to handle correctly the room avatar). + MXSession *session = [[MXSession alloc] initWithMatrixRestClient:mxRestClient]; for (MXRoomSummary *roomSummary in roomsSummaries) { diff --git a/RiotShareExtension/Shared/ShareManager.m b/RiotShareExtension/Shared/ShareManager.m index ee306286d6..bfb58e8bc7 100644 --- a/RiotShareExtension/Shared/ShareManager.m +++ b/RiotShareExtension/Shared/ShareManager.m @@ -78,9 +78,14 @@ - (UIViewController *)mainViewController - (void)shareViewController:(ShareViewController *)shareViewController didRequestShareForRoomIdentifiers:(NSSet *)roomIdentifiers { - MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { + MXWeakify(self); + MXRestClient *restClient = [[MXRestClient alloc] initWithCredentials:self.userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; - }]]; + } andUnauthenticatedHandler:^(MXError *error, void (^completion)(void)) { + MXStrongifyAndReturnIfNil(self); + [self.userAccount handleUnauthenticated:error andCompletion:completion]; + }]; + MXSession *session = [[MXSession alloc] initWithMatrixRestClient:restClient]; [MXFileStore setPreloadOptions:0]; MXWeakify(session); From 38fae3c7cf3bf3066fd3a02562570a3037e2d294 Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 11 Jan 2022 08:07:59 +0000 Subject: [PATCH 05/16] Temporarily point to refresh sdk branch to build alpha --- Podfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Podfile b/Podfile index e465a8f52d..8e948962e0 100644 --- a/Podfile +++ b/Podfile @@ -13,9 +13,10 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixSDKVersion = '0.20.15' +# $matrixSDKVersion = '0.20.15' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} +$matrixSDKVersion = { :branch => 'langleyd/5292_refresh_tokens'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } ######################################## From 06a8d0c0c9476f87ab1a7bf3132e8b462b1bea73 Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 13 Jan 2022 17:33:51 +0000 Subject: [PATCH 06/16] Add analytics for Unauthenticated errors --- Riot/Modules/Analytics/Analytics.swift | 12 +++++++++++- .../MatrixKit/Models/Account/MXKAccount.h | 2 +- .../MatrixKit/Models/Account/MXKAccount.m | 15 +++++++++------ RiotNSE/NotificationService.swift | 17 +++++++++++++---- .../SupportingFiles/RiotNSE-Bridging-Header.h | 2 ++ RiotNSE/target.yml | 2 ++ RiotShareExtension/Shared/ShareManager.m | 4 ++-- .../Sources/ShareExtensionRootViewController.m | 4 ++++ RiotShareExtension/target.yml | 1 + SiriIntents/IntentHandler.m | 5 +++++ .../SiriIntents-Bridging-Header.h | 1 + SiriIntents/target.yml | 4 ++++ 12 files changed, 55 insertions(+), 14 deletions(-) diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index 535ca7b2a4..c1e162417b 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -83,7 +83,7 @@ import AnalyticsEvents // Catch and log crashes MXLogger.logCrashes(true) - MXLogger.setBuildVersion(AppDelegate.theDelegate().build) + MXLogger.setBuildVersion(AppInfo.current.buildInfo.readableBuildVersion) } /// Use the analytics settings from the supplied session to configure analytics. @@ -200,6 +200,16 @@ extension Analytics { } } + /// Track when a user becomes unauthenticated without pressing the `sign out` button. + /// - Parameters: + /// - reason: The error that occurred. + /// - count: The number of times that error occurred. + func trackAuthUnauthenticatedError(softLogout: Bool, refreshTokenAuth: Bool, errorCode: String, errorReason: String) { + let errorCode = AnalyticsEvent.UnauthenticatedError.ErrorCode(rawValue: errorCode) ?? .M_UNKNOWN + let event = AnalyticsEvent.UnauthenticatedError(errorCode: errorCode, errorReason: errorReason, refreshTokenAuth: refreshTokenAuth, softLogout: softLogout) + client.capture(event) + } + /// Track whether the user accepted or declined the terms to an identity server. /// **Note** This method isn't currently implemented. /// - Parameter accepted: Whether the terms were accepted. diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h index b9eea90a4a..e2c56d63d0 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h @@ -362,5 +362,5 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer /** Handle unauthenticated errors from the server triggering hard/soft logouts as appropriate. */ -- (void)handleUnauthenticated:(MXError *)error andCompletion:(void (^)(void))completion; +- (void)handleUnauthenticatedWithError:(MXError *)error isSoftLogout:(BOOL)isSoftLogout isRefreshTokenAuth:(BOOL)isRefreshTokenAuth andCompletion:(void (^)(void))completion; @end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index 69db123221..0cb776bb2d 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -36,6 +36,8 @@ #import "MXKSwiftHeader.h" +#import "GeneratedInterface-Swift.h" + NSString *const kMXKAccountUserInfoDidChangeNotification = @"kMXKAccountUserInfoDidChangeNotification"; NSString *const kMXKAccountAPNSActivityDidChangeNotification = @"kMXKAccountAPNSActivityDidChangeNotification"; NSString *const kMXKAccountPushKitActivityDidChangeNotification = @"kMXKAccountPushKitActivityDidChangeNotification"; @@ -1700,17 +1702,18 @@ - (void)prepareRESTClient } andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { [MXKAccountManager.sharedManager readAndWriteCredentials:handler]; - } andUnauthenticatedHandler:^(MXError *error, void (^completion)(void)) { + } andUnauthenticatedHandler:^(MXError *error, BOOL isSoftLogout, BOOL isRefreshTokenAuth, void (^completion)(void)) { MXStrongifyAndReturnIfNil(self); - [self handleUnauthenticated:error andCompletion:completion]; + [self handleUnauthenticatedWithError:error isSoftLogout:isSoftLogout isRefreshTokenAuth:isRefreshTokenAuth andCompletion:completion]; }]; } - -- (void)handleUnauthenticated:(MXError *)error andCompletion:(void (^)(void))completion +- (void)handleUnauthenticatedWithError:(MXError *)error isSoftLogout:(BOOL)isSoftLogout isRefreshTokenAuth:(BOOL)isRefreshTokenAuth andCompletion:(void (^)(void))completion { - if (error.httpResponse.statusCode == 401 - && [error.userInfo[kMXErrorSoftLogoutKey] isEqual:@(YES)]) + + [Analytics.shared trackAuthUnauthenticatedErrorWithSoftLogout:isSoftLogout refreshTokenAuth:isRefreshTokenAuth errorCode:error.errcode errorReason:error.error]; + MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: trackAuthUnauthenticatedErrorWithSoftLogout sent"); + if (isSoftLogout) { MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: soft logout."); [[MXKAccountManager sharedManager] softLogout:self]; diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index b6a921b77d..5435362067 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -58,8 +58,8 @@ class NotificationService: UNNotificationServiceExtension { } let restClient = MXRestClient(credentials: userAccount.mxCredentials, unrecognizedCertificateHandler: nil, persistentTokenDataHandler: { persistTokenDataHandler in MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler) - }, unauthenticatedHandler: { error, completion in - userAccount.handleUnauthenticated(error, andCompletion: completion) + }, unauthenticatedHandler: { error, softLogout, refreshTokenAuth, completion in + userAccount.handleUnauthenticatedWithError(error, isSoftLogout: softLogout, isRefreshTokenAuth: refreshTokenAuth, andCompletion: completion) }) return restClient }() @@ -97,6 +97,8 @@ class NotificationService: UNNotificationServiceExtension { // log memory at the beginning of the process logMemory() + setupAnalytics() + UNUserNotificationCenter.current().removeUnwantedNotifications() // check if this is a Matrix notification @@ -170,6 +172,13 @@ class NotificationService: UNNotificationServiceExtension { } } + private func setupAnalytics(){ + // Configure our analytics. It will start if the option is enabled + let analytics = Analytics.shared + MXSDKOptions.sharedInstance().analyticsDelegate = analytics + analytics.startIfEnabled() + } + private func setup(withRoomId roomId: String, eventId: String, completion: @escaping () -> Void) { MXKAccountManager.sharedManager(withReload: true) self.userAccount = MXKAccountManager.shared()?.activeAccounts.first @@ -180,8 +189,8 @@ class NotificationService: UNNotificationServiceExtension { self.logMemory() NotificationService.backgroundSyncService = MXBackgroundSyncService(withCredentials: userAccount.mxCredentials, persistTokenDataHandler: { persistTokenDataHandler in MXKAccountManager.shared().readAndWriteCredentials(persistTokenDataHandler) - }, unauthenticatedHandler: { error, completion in - userAccount.handleUnauthenticated(error, andCompletion: completion) + }, unauthenticatedHandler: { error, softLogout, refreshTokenAuth, completion in + userAccount.handleUnauthenticatedWithError(error, isSoftLogout: softLogout, isRefreshTokenAuth: refreshTokenAuth, andCompletion: completion) }) MXLog.debug("[NotificationService] setup: MXBackgroundSyncService init: AFTER") self.logMemory() diff --git a/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h b/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h index 41b0ba485e..6409af92f6 100644 --- a/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h +++ b/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h @@ -21,4 +21,6 @@ #import "MatrixKit-Bridging-Header.h" +#import "BuildInfo.h" + #endif /* RiotNSE_Bridging_Header_h */ diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index f01b619a35..669fceeb68 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -62,6 +62,8 @@ targets: - path: ../Riot/Managers/Widgets/WidgetConstants.m - path: ../Riot/PropertyWrappers/UserDefaultsBackedPropertyWrapper.swift - path: ../Riot/Modules/MatrixKit + - path: ../Riot/Modules/Analytics + - path: ../Riot/Managers/AppInfo/ excludes: - "**/*.md" # excludes all files with the .md extension - path: ../Riot/Generated/MatrixKitStrings.swift diff --git a/RiotShareExtension/Shared/ShareManager.m b/RiotShareExtension/Shared/ShareManager.m index bfb58e8bc7..d242891888 100644 --- a/RiotShareExtension/Shared/ShareManager.m +++ b/RiotShareExtension/Shared/ShareManager.m @@ -81,9 +81,9 @@ - (void)shareViewController:(ShareViewController *)shareViewController didReques MXWeakify(self); MXRestClient *restClient = [[MXRestClient alloc] initWithCredentials:self.userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:^(void (^handler)(NSArray *credentials, void (^completion)(BOOL didUpdateCredentials))) { [[MXKAccountManager sharedManager] readAndWriteCredentials:handler]; - } andUnauthenticatedHandler:^(MXError *error, void (^completion)(void)) { + } andUnauthenticatedHandler:^(MXError *error, BOOL isSoftLogout, BOOL isRefreshTokenAuth, void (^completion)(void)) { MXStrongifyAndReturnIfNil(self); - [self.userAccount handleUnauthenticated:error andCompletion:completion]; + [self.userAccount handleUnauthenticatedWithError:error isSoftLogout:isSoftLogout isRefreshTokenAuth:isRefreshTokenAuth andCompletion:completion]; }]; MXSession *session = [[MXSession alloc] initWithMatrixRestClient:restClient]; [MXFileStore setPreloadOptions:0]; diff --git a/RiotShareExtension/Sources/ShareExtensionRootViewController.m b/RiotShareExtension/Sources/ShareExtensionRootViewController.m index 90b5006e8f..c43eef81ec 100644 --- a/RiotShareExtension/Sources/ShareExtensionRootViewController.m +++ b/RiotShareExtension/Sources/ShareExtensionRootViewController.m @@ -52,6 +52,10 @@ - (void)viewDidLoad [MXLog configure:configuration]; + // Configure our analytics. It will start if the option is enabled + Analytics *analytics = Analytics.shared; + [MXSDKOptions sharedInstance].analyticsDelegate = analytics; + [analytics startIfEnabled]; [ThemeService.shared setThemeId:RiotSettings.shared.userInterfaceTheme]; diff --git a/RiotShareExtension/target.yml b/RiotShareExtension/target.yml index 7f32196f4e..1144c2e377 100644 --- a/RiotShareExtension/target.yml +++ b/RiotShareExtension/target.yml @@ -69,6 +69,7 @@ targets: - path: ../Riot/Assets/SharedImages.xcassets buildPhase: resources - path: ../Riot/Modules/MatrixKit + - path: ../Riot/Modules/Analytics excludes: - "**/*.md" # excludes all files with the .md extension - path: ../Riot/Generated/MatrixKitStrings.swift diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index e73af83128..737db0839f 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -53,6 +53,11 @@ - (instancetype)init } [MXLog configure:configuration]; + + // Configure our analytics. It will start if the option is enabled + Analytics *analytics = Analytics.shared; + [MXSDKOptions sharedInstance].analyticsDelegate = analytics; + [analytics startIfEnabled]; } return self; } diff --git a/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h b/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h index 306e2e582a..ca6d81962e 100644 --- a/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h +++ b/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h @@ -15,3 +15,4 @@ // #import "MatrixKit-Bridging-Header.h" +#import "BuildInfo.h" diff --git a/SiriIntents/target.yml b/SiriIntents/target.yml index 05aea0ea90..e41030c710 100644 --- a/SiriIntents/target.yml +++ b/SiriIntents/target.yml @@ -51,6 +51,10 @@ targets: - path: ../Riot/Managers/Locale/LocaleProviderType.swift - path: ../Riot/Managers/Locale/LocaleProvider.swift - path: ../Riot/Modules/MatrixKit + - path: ../Riot/Modules/Analytics + - path: ../Riot/Managers/AppInfo/ + - path: ../Riot/Managers/Locale/LocaleProviderType.swift + - path: ../Riot/Generated/Strings.swift excludes: - "**/*.md" # excludes all files with the .md extension - path: ../Riot/Generated/MatrixKitStrings.swift From dbe3c6f2256617e15d17ab9184d5f4527093cac3 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 14 Jan 2022 11:44:07 +0000 Subject: [PATCH 07/16] Update Podfile.lock --- Podfile.lock | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 749fe065fd..fc927d2457 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -118,8 +118,8 @@ DEPENDENCIES: - Keys (from `Pods/CocoaPodsKeys`) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.20.16) - - MatrixSDK/JingleCallStack (= 0.20.16) + - MatrixSDK (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `langleyd/5292_refresh_tokens`) + - MatrixSDK/JingleCallStack (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `langleyd/5292_refresh_tokens`) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -159,7 +159,6 @@ SPEC REPOS: - libPhoneNumber-iOS - LoggerAPI - Logging - - MatrixSDK - OLMKit - PostHog - ReadMoreTextView @@ -181,11 +180,17 @@ EXTERNAL SOURCES: :git: https://github.com/matrix-org/matrix-analytics-events.git Keys: :path: Pods/CocoaPodsKeys + MatrixSDK: + :branch: langleyd/5292_refresh_tokens + :git: https://github.com/matrix-org/matrix-ios-sdk.git CHECKOUT OPTIONS: AnalyticsEvents: - :commit: f1805ad7c3fafa7fd9c6e2eaa9e0165f8142ecd2 + :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c :git: https://github.com/matrix-org/matrix-analytics-events.git + MatrixSDK: + :commit: 7da1e08534dc6784dff80923ef475c2b86f6e289 + :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce @@ -214,7 +219,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: af6a70532bb43af59f43a1f4dae512a26afeab0b + MatrixSDK: fbef8eb1793f8c2b5233bee493b6b1bbe93ae3f7 OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -230,6 +235,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 2493587902f8f28bb2638303dd583c47e9f24d8b +PODFILE CHECKSUM: 8ad5a5ab16f6cb768b9fad274722fe6e0593c3d7 COCOAPODS: 1.11.2 From 5850d55b1f5a1fabbec6e2b744b3ec8f802cfe32 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 14 Jan 2022 15:28:08 +0000 Subject: [PATCH 08/16] Update lockfile to get latest SDK. --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index fc927d2457..020d05861b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -189,7 +189,7 @@ CHECKOUT OPTIONS: :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c :git: https://github.com/matrix-org/matrix-analytics-events.git MatrixSDK: - :commit: 7da1e08534dc6784dff80923ef475c2b86f6e289 + :commit: 634b47c943a786db44d8beb04a4365a00b126901 :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: From 07b9b087fbb6c82237f95c8c8a5dcb3bf9f0c9f8 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 24 Jan 2022 12:44:26 +0000 Subject: [PATCH 09/16] Remove NSLog and fix Analytics documentation. --- Podfile.lock | 6 ++---- Riot/Modules/Analytics/Analytics.swift | 6 ++++-- .../MatrixKit/Models/Account/MXKAccountManager.m | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 72b9892441..50c9647bb2 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -176,8 +176,6 @@ EXTERNAL SOURCES: AnalyticsEvents: :branch: release/swift :git: https://github.com/matrix-org/matrix-analytics-events.git - Keys: - :path: Pods/CocoaPodsKeys MatrixSDK: :branch: langleyd/5292_refresh_tokens :git: https://github.com/matrix-org/matrix-ios-sdk.git @@ -187,7 +185,7 @@ CHECKOUT OPTIONS: :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c :git: https://github.com/matrix-org/matrix-analytics-events.git MatrixSDK: - :commit: 634b47c943a786db44d8beb04a4365a00b126901 + :commit: 35fa763f2c6ccd71ad0340c47cc44e6c40083746 :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: @@ -232,6 +230,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 8ad5a5ab16f6cb768b9fad274722fe6e0593c3d7 +PODFILE CHECKSUM: c5f0584d20a092fba207f356f7487bdbea129ab8 COCOAPODS: 1.11.2 diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index 2fe4296636..4bef46af29 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -212,8 +212,10 @@ extension Analytics { /// Track when a user becomes unauthenticated without pressing the `sign out` button. /// - Parameters: - /// - reason: The error that occurred. - /// - count: The number of times that error occurred. + /// - softLogout: Wether it was a soft/hard logout that was triggered. + /// - refreshTokenAuth: Wether it was either an access-token-based or refresh-token-based auth mechanism enabled. + /// - errorCode: The error code as returned by the homeserver that triggered the logout. + /// - errorReason: The reason for the error as returned by the homeserver that triggered the logout. func trackAuthUnauthenticatedError(softLogout: Bool, refreshTokenAuth: Bool, errorCode: String, errorReason: String) { let errorCode = AnalyticsEvent.UnauthenticatedError.ErrorCode(rawValue: errorCode) ?? .M_UNKNOWN let event = AnalyticsEvent.UnauthenticatedError(errorCode: errorCode, errorReason: errorReason, refreshTokenAuth: refreshTokenAuth, softLogout: softLogout) diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m index a8947f4efc..9c37c1696c 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m @@ -733,7 +733,7 @@ - (void)readAndWriteCredentials:(void (^)(NSArray * _Nullable re NSError *error; NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init]; __block BOOL coordinatorSuccess = NO; - NSLog(@"[MXKAccountManager] readAndWriteCredentials: purposeIdentifier = %@", fileCoordinator.purposeIdentifier); + MXLogDebug(@"[MXKAccountManager] readAndWriteCredentials: purposeIdentifier = %@", fileCoordinator.purposeIdentifier); NSDate *coordinateStartTime = [NSDate date]; [fileCoordinator coordinateReadingItemAtURL:[self accountFileUrl] options:0 @@ -744,7 +744,7 @@ - (void)readAndWriteCredentials:(void (^)(NSArray * _Nullable re NSDate *accessorStartTime = [NSDate date]; NSTimeInterval acquireInterval = [accessorStartTime timeIntervalSinceDate:coordinateStartTime]; - NSLog(@"[MXKAccountManager] readAndWriteCredentials: acquireInterval = %f", acquireInterval); + MXLogDebug(@"[MXKAccountManager] readAndWriteCredentials: acquireInterval = %f", acquireInterval); NSError *error = nil; NSData* data = [NSData dataWithContentsOfURL:newReadingURL options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:&error]; @@ -771,21 +771,21 @@ - (void)readAndWriteCredentials:(void (^)(NSArray * _Nullable re dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER); if (didUpdate) { - NSLog(@"[MXKAccountManager] readAndWriteCredentials: did update saving credential data"); + MXLogDebug(@"[MXKAccountManager] readAndWriteCredentials: did update saving credential data"); NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initRequiringSecureCoding: NO]; [encoder setClassName:@"MXKAccount" forClass:[MXKAccountData class]]; [encoder encodeObject:mxAccountsData forKey:@"mxAccounts"]; NSData *writeData = [self encryptData:[encoder encodedData]]; coordinatorSuccess = [writeData writeToURL:newWritingURL atomically:YES]; } else { - NSLog(@"[MXKAccountManager] readAndWriteCredentials: did not update not saving credential data"); + MXLogDebug(@"[MXKAccountManager] readAndWriteCredentials: did not update not saving credential data"); coordinatorSuccess = YES; } NSDate *accessorEndTime = [NSDate date]; NSTimeInterval lockedTime = [accessorEndTime timeIntervalSinceDate:accessorStartTime]; - NSLog(@"[MXKAccountManager] readAndWriteCredentials: lockedTime = %f", lockedTime); + MXLogDebug(@"[MXKAccountManager] readAndWriteCredentials: lockedTime = %f", lockedTime); }]; - NSLog(@"[MXKAccountManager] readAndWriteCredentials:exit"); + MXLogDebug(@"[MXKAccountManager] readAndWriteCredentials:exit %d", coordinatorSuccess); } - (NSURL *)accountFileUrl From cb70d6d6a2c12bbbd227e12dfea88b66abc12d41 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 24 Jan 2022 13:24:16 +0000 Subject: [PATCH 10/16] Update pod lockfile to include fix in SDK. --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index 50c9647bb2..cea581dea0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -185,7 +185,7 @@ CHECKOUT OPTIONS: :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c :git: https://github.com/matrix-org/matrix-analytics-events.git MatrixSDK: - :commit: 35fa763f2c6ccd71ad0340c47cc44e6c40083746 + :commit: 98c2efd759e48ce21cd5f5f864d2b401197e2253 :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: From e7851793c4b0578b6dd9344fab7935bc80502b67 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 24 Jan 2022 13:39:37 +0000 Subject: [PATCH 11/16] Update Podfile.lock --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index cea581dea0..65885ca0ee 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -185,7 +185,7 @@ CHECKOUT OPTIONS: :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c :git: https://github.com/matrix-org/matrix-analytics-events.git MatrixSDK: - :commit: 98c2efd759e48ce21cd5f5f864d2b401197e2253 + :commit: b9cbc3bd378c55c5317725e3dbebf18a1cd5d0fc :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: From c2928ba1a427eccef9bb1e49a1a1af6d489730c0 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 24 Jan 2022 18:17:27 +0000 Subject: [PATCH 12/16] Fix missing bubbles cell types (from #5419) --- .../BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m index 58a460dfec..6e77a6dbdb 100644 --- a/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m +++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m @@ -270,7 +270,7 @@ - (void)registerLocationCellsForTableView:(UITableView*)tableView NSDictionary *incomingTextMessageCellsMapping = [self incomingTextMessageCellsMapping]; [cellClasses addEntriesFromDictionary:incomingTextMessageCellsMapping]; - NSDictionary *outgoingTextMessageCellsMapping = [self incomingTextMessageCellsMapping]; + NSDictionary *outgoingTextMessageCellsMapping = [self outgoingTextMessageCellsMapping]; [cellClasses addEntriesFromDictionary:outgoingTextMessageCellsMapping]; // Attachment From be445ac32b4b334f03aa4453896b857abcc24343 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 24 Jan 2022 18:35:00 +0000 Subject: [PATCH 13/16] Revert bad merge formatting from "Merge branch 'develop' of https://github.com/vector-im/element-ios into langleyd/5292_refresh_tokens" This reverts commit 2f006727eb5af482fcc4e8a5a84cf0f6f41db0f6, reversing changes made to e7851793c4b0578b6dd9344fab7935bc80502b67. --- Riot/Modules/Application/LegacyAppDelegate.m | 1130 ++++++++--------- ...ollerWithBannerWrapperViewController.swift | 36 +- 2 files changed, 583 insertions(+), 583 deletions(-) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index e407869342..37ca135d3d 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -2,13 +2,13 @@ Copyright 2014 OpenMarket Ltd Copyright 2017 Vector Creations Ltd Copyright 2018 New Vector Ltd - + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -91,23 +91,23 @@ @interface LegacyAppDelegate () " withString: @""] stringByReplacingOccurrencesOfString: @" " withString: @""]; - + MXLogDebug(@"The generated device token string is : %@",deviceTokenString); } @@ -325,7 +325,7 @@ - (void)setIsOffline:(BOOL)isOffline { // Define reachability observer when isOffline property is set for the first time reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - + NSNumber *statusItem = note.userInfo[AFNetworkingReachabilityNotificationStatusItem]; if (statusItem) { @@ -339,14 +339,14 @@ - (void)setIsOffline:(BOOL)isOffline [AppDelegate theDelegate].isOffline = NO; } } - + }]; } - + if (_isOffline != isOffline) { _isOffline = isOffline; - + [[NSNotificationCenter defaultCenter] postNotificationName:kAppDelegateNetworkStatusDidChangeNotification object:nil]; } } @@ -358,10 +358,10 @@ - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions: // Create message sound NSURL *messageSoundURL = [[NSBundle mainBundle] URLForResource:@"message" withExtension:@"caf"]; AudioServicesCreateSystemSoundID((__bridge CFURLRef)messageSoundURL, &_messageSound); - + // Set app info now as Mac (Designed for iPad) accesses it before didFinishLaunching is called self.appInfo = AppInfo.current; - + MXLogDebug(@"[AppDelegate] willFinishLaunchingWithOptions: Done"); return YES; @@ -370,7 +370,7 @@ - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSDate *startDate = [NSDate date]; - + #ifdef DEBUG // log the full launchOptions only in DEBUG MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: %@", launchOptions); @@ -382,19 +382,19 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( _configuration = [AppConfiguration new]; self.clearingCache = NO; - + // Log app information NSString *appDisplayName = self.appInfo.displayName; NSString* appVersion = self.appVersion; NSString* build = self.build; - + MXLogDebug(@"------------------------------"); MXLogDebug(@"Application info:"); MXLogDebug(@"%@ version: %@", appDisplayName, appVersion); MXLogDebug(@"MatrixSDK version: %@", MatrixSDKVersion); MXLogDebug(@"Build: %@\n", build); MXLogDebug(@"------------------------------\n"); - + [self setupUserDefaults]; // Set up theme @@ -423,48 +423,48 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // To simplify navigation into the app, we retrieve here the main navigation controller and the tab bar controller. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; - + _masterNavigationController = splitViewController.viewControllers[0]; _masterTabBarController = _masterNavigationController.viewControllers.firstObject; - + // Sanity check NSAssert(_masterTabBarController, @"Something wrong in Main.storyboard"); - + _isAppForeground = NO; _handleSelfVerificationRequest = YES; - + // Configure our analytics. It will start if the option is enabled Analytics *analytics = Analytics.shared; [MXSDKOptions sharedInstance].analyticsDelegate = analytics; [DecryptionFailureTracker sharedInstance].delegate = analytics; - + MXBaseProfiler *profiler = [MXBaseProfiler new]; profiler.analytics = analytics; [MXSDKOptions sharedInstance].profiler = profiler; - + [analytics startIfEnabled]; self.localAuthenticationService = [[LocalAuthenticationService alloc] initWithPinCodePreferences:[PinCodePreferences shared]]; - + self.callPresenter = [[CallPresenter alloc] init]; self.callPresenter.delegate = self; self.pushNotificationStore = [PushNotificationStore new]; self.pushNotificationService = [[PushNotificationService alloc] initWithPushNotificationStore:self.pushNotificationStore]; self.pushNotificationService.delegate = self; - + self.spaceFeatureUnavailablePresenter = [SpaceFeatureUnavailablePresenter new]; - + // Add matrix observers, and initialize matrix sessions if the app is not launched in background. [self initMatrixSessions]; - + #ifdef CALL_STACK_JINGLE // Setup Jitsi [JitsiService.shared configureDefaultConferenceOptionsWith:BuildSettings.jitsiServerUrl]; [JitsiService.shared application:application didFinishLaunchingWithOptions:launchOptions]; #endif - + self.majorUpdateManager = [MajorUpdateManager new]; MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: Done in %.0fms", [[NSDate date] timeIntervalSinceDate:startDate] * 1000); @@ -472,44 +472,44 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( dispatch_async(dispatch_get_main_queue(), ^{ [self configurePinCodeScreenFor:application createIfRequired:YES]; }); - + return YES; } - (void)applicationWillResignActive:(UIApplication *)application { MXLogDebug(@"[AppDelegate] applicationWillResignActive"); - + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - + [self.pushNotificationService applicationWillResignActive]; - + // Release MatrixKit error observer if (matrixKitErrorObserver) { [[NSNotificationCenter defaultCenter] removeObserver:matrixKitErrorObserver]; matrixKitErrorObserver = nil; } - + if (self.errorNotification) { [self.errorNotification dismissViewControllerAnimated:NO completion:nil]; self.errorNotification = nil; } - + if (accountPicker) { [accountPicker dismissViewControllerAnimated:NO completion:nil]; accountPicker = nil; } - + if (noCallSupportAlert) { [noCallSupportAlert dismissViewControllerAnimated:NO completion:nil]; noCallSupportAlert = nil; } - + if (cryptoDataCorruptedAlert) { [cryptoDataCorruptedAlert dismissViewControllerAnimated:NO completion:nil]; @@ -521,7 +521,7 @@ - (void)applicationWillResignActive:(UIApplication *)application [wrongBackupVersionAlert dismissViewControllerAnimated:NO completion:nil]; wrongBackupVersionAlert = nil; } - + if ([self.localAuthenticationService isProtectionSet] && ![BiometricsAuthenticationPresenter isPresenting]) { if (self.setPinCoordinatorBridgePresenter) @@ -539,10 +539,10 @@ - (void)applicationWillResignActive:(UIApplication *)application - (void)applicationDidEnterBackground:(UIApplication *)application { MXLogDebug(@"[AppDelegate] applicationDidEnterBackground"); - + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - + // Stop reachability monitoring if (reachabilityObserver) { @@ -551,40 +551,40 @@ - (void)applicationDidEnterBackground:(UIApplication *)application } [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:nil]; [[AFNetworkReachabilityManager sharedManager] stopMonitoring]; - + // check if some media must be released to reduce the cache size [MXMediaManager reduceCacheSizeToInsert:0]; - + // Remove expired URL previews from the cache [URLPreviewService.shared removeExpiredCacheData]; - + // Hide potential notification if (self.mxInAppNotification) { [self.mxInAppNotification dismissViewControllerAnimated:NO completion:nil]; self.mxInAppNotification = nil; } - + // Discard any process on pending universal link [self resetPendingUniversalLink]; - + // Suspend all running matrix sessions NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; for (MXKAccount *account in mxAccounts) { [account pauseInBackgroundTask]; } - + // Refresh the notifications counter [self refreshApplicationIconBadgeNumber]; - + _isAppForeground = NO; - + [self.pushNotificationService applicationDidEnterBackground]; - + // Pause profiling [MXSDKOptions.sharedInstance.profiler pause]; - + // Analytics: Force to send the pending actions [[DecryptionFailureTracker sharedInstance] dispatch]; [Analytics.shared forceUpload]; @@ -593,27 +593,27 @@ - (void)applicationDidEnterBackground:(UIApplication *)application - (void)applicationWillEnterForeground:(UIApplication *)application { MXLogDebug(@"[AppDelegate] applicationWillEnterForeground"); - + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. [MXSDKOptions.sharedInstance.profiler resume]; - + // Force each session to refresh here their publicised groups by user dictionary. // When these publicised groups are retrieved for a user, they are cached and reused until the app is backgrounded and enters in the foreground again for (MXSession *session in mxSessionArray) { [session markOutdatedPublicisedGroupsByUserData]; } - + _isAppForeground = YES; } - (void)applicationDidBecomeActive:(UIApplication *)application { MXLogDebug(@"[AppDelegate] applicationDidBecomeActive"); - + [self.pushNotificationService applicationDidBecomeActive]; - + [self configurePinCodeScreenFor:application createIfRequired:NO]; } @@ -646,7 +646,7 @@ - (void)configurePinCodeScreenFor:(UIApplication *)application - (void)afterAppUnlockedByPin:(UIApplication *)application { MXLogDebug(@"[AppDelegate] afterAppUnlockedByPin"); - + // Check if there is crash log to send if (RiotSettings.shared.enableAnalytics) { @@ -656,7 +656,7 @@ - (void)afterAppUnlockedByPin:(UIApplication *)application [self checkExceptionToReport]; #endif } - + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. // Check if an initial sync failure occured while the app was in background @@ -670,13 +670,13 @@ - (void)afterAppUnlockedByPin:(UIApplication *)application [self showErrorAsAlert:error]; } - + // Register to GDPR consent not given notification [self registerUserConsentNotGivenNotification]; - + // Start monitoring reachability [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { - + // Check whether monitoring is ready if (status != AFNetworkReachabilityStatusUnknown) { @@ -689,23 +689,23 @@ - (void)afterAppUnlockedByPin:(UIApplication *)application { self.isOffline = NO; } - + // Use a dispatch to avoid to kill ourselves dispatch_async(dispatch_get_main_queue(), ^{ [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:nil]; }); } - + }]; [[AFNetworkReachabilityManager sharedManager] startMonitoring]; - + // Observe matrixKit error to alert user on error matrixKitErrorObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKErrorNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - + [self showErrorAsAlert:note.object]; - + }]; - + // Observe crypto data storage corruption [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSessionCryptoDidCorruptData:) name:kMXSessionCryptoDidCorruptDataNotification object:nil]; @@ -718,12 +718,12 @@ - (void)afterAppUnlockedByPin:(UIApplication *)application { [account resume]; } - + _isAppForeground = YES; - + // Riot has its own dark theme. Prevent iOS from applying its one [application keyWindow].accessibilityIgnoresInvertColors = YES; - + [self handleAppState]; } @@ -741,7 +741,7 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray> * _Nullable))restorationHandler { BOOL continueUserActivity = NO; - + if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { continueUserActivity = [self handleUniversalLink:userActivity]; @@ -750,15 +750,15 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct [userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier]) { INInteraction *interaction = userActivity.interaction; - + // roomID provided by Siri intent NSString *roomID = userActivity.userInfo[@"roomID"]; - + // We've launched from calls history list if (!roomID) { INPerson *person; - + if ([interaction.intent isKindOfClass:INStartAudioCallIntent.class]) { person = [[(INStartAudioCallIntent *)(interaction.intent) contacts] firstObject]; @@ -767,17 +767,17 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct { person = [[(INStartVideoCallIntent *)(interaction.intent) contacts] firstObject]; } - + roomID = person.personHandle.value; } - + BOOL isVideoCall = [userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier]; - + UIApplication *application = UIApplication.sharedApplication; - + id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; id backgroundTask; - + // Start background task since we need time for MXSession preparasion because our app can be launched in the background if (application.applicationState == UIApplicationStateBackground) { @@ -810,10 +810,10 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct [backgroundTask stop]; } }]; - + continueUserActivity = YES; } - + return continueUserActivity; } @@ -823,23 +823,23 @@ - (void)restoreInitialDisplay:(void (^)(void))completion { // Suspend error notifications during navigation stack change. isErrorNotificationSuspended = YES; - + // Dismiss potential view controllers that were presented modally (like the media picker). if (self.window.rootViewController.presentedViewController) { // Do it asynchronously to avoid hasardous dispatch_async after calling restoreInitialDisplay [self.window.rootViewController dismissViewControllerAnimated:NO completion:^{ - + [self popToHomeViewControllerAnimated:NO completion:^{ - + if (completion) { completion(); } - + // Enable error notifications isErrorNotificationSuspended = NO; - + if (noCallSupportAlert) { MXLogDebug(@"[AppDelegate] restoreInitialDisplay: keep visible noCall support alert"); @@ -861,20 +861,20 @@ - (void)restoreInitialDisplay:(void (^)(void))completion { [self showNotificationAlert:_errorNotification]; } - + }]; - + }]; } else { [self popToHomeViewControllerAnimated:NO completion:^{ - + if (completion) { completion(); } - + // Enable error notification (Check whether a notification is pending) isErrorNotificationSuspended = NO; if (_errorNotification) @@ -897,13 +897,13 @@ - (UIAlertController*)showErrorAsAlert:(NSError*)error { return nil; } - + // Ignore network reachability error when the app is already offline if (self.isOffline && [error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet) { return nil; } - + // Ignore GDPR Consent not given error. Already caught by kMXHTTPClientUserConsentNotGivenErrorNotification observation if ([MXError isMXError:error]) { @@ -928,7 +928,7 @@ - (UIAlertController*)showErrorAsAlert:(NSError*)error title = [MatrixKitL10n error]; } } - + // Switch in offline mode in case of network reachability error if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet) { @@ -970,7 +970,7 @@ - (void)showNotificationAlert:(UIAlertController*)alert - (void)onSessionCryptoDidCorruptData:(NSNotification *)notification { NSString *userId = notification.object; - + MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId]; if (account) { @@ -978,39 +978,39 @@ - (void)onSessionCryptoDidCorruptData:(NSNotification *)notification { [cryptoDataCorruptedAlert dismissViewControllerAnimated:NO completion:nil]; } - + cryptoDataCorruptedAlert = [UIAlertController alertControllerWithTitle:nil message:[VectorL10n e2eNeedLogInAgain] preferredStyle:UIAlertControllerStyleAlert]; - + __weak typeof(self) weakSelf = self; - + [cryptoDataCorruptedAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n later] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->cryptoDataCorruptedAlert = nil; } - + }]]; - + [cryptoDataCorruptedAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n settingsSignOut] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->cryptoDataCorruptedAlert = nil; - + [[MXKAccountManager sharedManager] removeAccount:account completion:nil]; } - + }]]; - + [self showNotificationAlert:cryptoDataCorruptedAlert]; } } @@ -1075,11 +1075,11 @@ - (void)checkExceptionToReport { return; } - + NSString *description = [[NSString alloc] initWithContentsOfFile:filePath usedEncoding:nil error:nil]; - + MXLogDebug(@"[AppDelegate] Promt user to report crash:\n%@", description); // Ask the user to send a crash report @@ -1113,7 +1113,7 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity { NSURL *webURL = userActivity.webpageURL; MXLogDebug(@"[AppDelegate] handleUniversalLink: %@", webURL.absoluteString); - + // iOS Patch: fix vector.im urls before using it webURL = [Tools fixURLWithSeveralHashKeys:webURL]; @@ -1134,52 +1134,52 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity { return YES; } - + NSString *validateEmailSubmitTokenPath = @"validate/email/submitToken"; - + NSString *validateEmailSubmitTokenAPIPathV1 = [NSString stringWithFormat:@"/%@/%@", kMXIdentityAPIPrefixPathV1, validateEmailSubmitTokenPath]; NSString *validateEmailSubmitTokenAPIPathV2 = [NSString stringWithFormat:@"/%@/%@", kMXIdentityAPIPrefixPathV2, validateEmailSubmitTokenPath]; - + // Manage email validation links from homeserver for registration (/registration/email/submit_token) // and email addition (/add_threepid/email/submit_token) // They look like https://matrix.org/_matrix/client/unstable/registration/email/submit_token?token=vtQjQIZfwdoREDACTEDozrmKYSWlCXsJ&client_secret=53e679ea-oRED-ACTED-92b8-3012c49c6cfa&sid=qlBCREDACTEDEtgxD if ([webURL.path hasSuffix:@"/email/submit_token"]) { MXLogDebug(@"[AppDelegate] handleUniversalLink: Validate link"); - + // We just need to ping the link. // The app should be in the registration flow at the "waiting for email validation" polling state. The server // will indicate the email is validated through this polling API. Then, the app will go to the next flow step. NSURLSessionConfiguration *conf = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:conf]; - + NSURLSessionDataTask * task = [urlSession dataTaskWithURL:webURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - + MXLogDebug(@"[AppDelegate] handleUniversalLink: Link validation response: %@\nData: %@", response, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); - + if (error) { MXLogDebug(@"[AppDelegate] handleUniversalLink: Link validation error: %@", error); [self showErrorAsAlert:error]; } }]; - + [task resume]; - + return YES; } - + // Manage email validation link from identity server v1 or v2 else if ([webURL.path isEqualToString:validateEmailSubmitTokenAPIPathV1] || [webURL.path isEqualToString:validateEmailSubmitTokenAPIPathV2]) { // Validate the email on the passed identity server NSString *identityServer = [NSString stringWithFormat:@"%@://%@", webURL.scheme, webURL.host]; - + MXSession *mainSession = self.mxSessions.firstObject; MXRestClient *homeserverRestClient; - + if (mainSession.matrixRestClient) { homeserverRestClient = mainSession.matrixRestClient; @@ -1188,16 +1188,16 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity { homeserverRestClient = [[MXRestClient alloc] initWithHomeServer:identityServer andOnUnrecognizedCertificateBlock:nil]; } - + MXIdentityService *identityService = [[MXIdentityService alloc] initWithIdentityServer:identityServer accessToken:nil andHomeserverRestClient:homeserverRestClient]; NSString *clientSecret = queryParams[@"client_secret"]; NSString *sid = queryParams[@"sid"]; - + [identityService submit3PIDValidationToken:queryParams[@"token"] medium:kMX3PIDMediumEmail clientSecret:clientSecret sid:sid success:^{ - + MXLogDebug(@"[AppDelegate] handleUniversalLink. Email successfully validated."); - + if (queryParams[@"nextLink"]) { // Continue the registration with the passed nextLink @@ -1208,27 +1208,27 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity else { // No nextLink in Vector world means validation for binding a new email - + // Post a notification about email validation to make a chance to SettingsDiscoveryThreePidDetailsViewModel to make it discoverable or not by the identity server. if (clientSecret && sid) { NSDictionary *userInfo = @{ AppDelegateDidValidateEmailNotificationClientSecretKey : clientSecret, AppDelegateDidValidateEmailNotificationSIDKey : sid }; - + [[NSNotificationCenter defaultCenter] postNotificationName:AppDelegateDidValidateEmailNotification object:nil userInfo:userInfo]; } } - + } failure:^(NSError *error) { - + MXLogDebug(@"[AppDelegate] handleUniversalLink. Error: submitToken failed"); [self showErrorAsAlert:error]; - + }]; - + return YES; } - + return [self handleUniversalLinkFragment:webURL.fragment fromURL:webURL]; } @@ -1242,9 +1242,9 @@ - (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromURL:(NSURL*)universa { ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES stackAboveVisibleViews:NO]; - + UniversalLinkParameters *parameters = [[UniversalLinkParameters alloc] initWithFragment:fragment universalLinkURL:universalLinkURL presentationParameters:presentationParameters]; - + return [self handleUniversalLinkWithParameters:parameters]; } @@ -1254,43 +1254,43 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin NSURL *universalLinkURL = universalLinkParameters.universalLinkURL; ScreenPresentationParameters *screenPresentationParameters = universalLinkParameters.presentationParameters; BOOL restoreInitialDisplay = screenPresentationParameters.restoreInitialDisplay; - + BOOL continueUserActivity = NO; MXKAccountManager *accountManager = [MXKAccountManager sharedManager]; - + MXLogDebug(@"[AppDelegate] Universal link: handleUniversalLinkFragment: %@", fragment); - + // Make sure we have plain utf8 character for separators fragment = [fragment stringByRemovingPercentEncoding]; MXLogDebug(@"[AppDelegate] Universal link: handleUniversalLinkFragment: %@", fragment); - + // The app manages only one universal link at a time // Discard any pending one [self resetPendingUniversalLink]; - + // Extract params NSArray *pathParams; NSMutableDictionary *queryParams; [self parseUniversalLinkFragment:fragment outPathParams:&pathParams outQueryParams:&queryParams]; - + // Sanity check if (!pathParams.count) { MXLogDebug(@"[AppDelegate] Universal link: Error: No path parameters"); return NO; } - + NSString *roomIdOrAlias; NSString *eventId; NSString *userId; NSString *groupId; - + // Check permalink to room or event if ([pathParams[0] isEqualToString:@"room"] && pathParams.count >= 2) { // The link is the form of "/room/[roomIdOrAlias]" or "/room/[roomIdOrAlias]/[eventId]" roomIdOrAlias = pathParams[1]; - + // Is it a link to an event of a room? eventId = (pathParams.count >= 3) ? pathParams[2] : nil; } @@ -1318,7 +1318,7 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin // Such links come from matrix.to permalinks userId = pathParams[0]; } - + // Check the conditions to keep the room alias information of a pending fragment. if (universalLinkFragmentPendingRoomAlias) { @@ -1327,7 +1327,7 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin universalLinkFragmentPendingRoomAlias = nil; } } - + if (roomIdOrAlias) { if (accountManager.activeAccounts.count) @@ -1338,7 +1338,7 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin { NSString *roomId = roomIdOrAlias; MXRoom *room; - + // Translate the alias into the room id if ([roomIdOrAlias hasPrefix:@"#"]) { @@ -1352,21 +1352,21 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin { room = [account.mxSession roomWithRoomId:roomId]; } - + if (room.summary.roomType == MXRoomTypeSpace) { SpaceNavigationParameters *spaceNavigationParameters = [[SpaceNavigationParameters alloc] initWithRoomId:room.roomId mxSession:account.mxSession presentationParameters:screenPresentationParameters]; - + [self showSpaceWithParameters:spaceNavigationParameters]; } else { // Open the room page RoomNavigationParameters *roomNavigationParameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId eventId:eventId mxSession:account.mxSession presentationParameters: screenPresentationParameters]; - + [self showRoomWithParameters:roomNavigationParameters]; } - + continueUserActivity = YES; } else @@ -1375,9 +1375,9 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin if ([_masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) { UIViewController *homeViewController = (UIViewController*)_masterTabBarController.selectedViewController; - + [homeViewController startActivityIndicator]; - + if ([roomIdOrAlias hasPrefix:@"#"]) { // The alias may be not part of user's rooms states @@ -1385,10 +1385,10 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin universalLinkFragmentPending = fragment; MXKAccount* account = accountManager.activeAccounts.firstObject; [account.mxSession.matrixRestClient roomIDForRoomAlias:roomIdOrAlias success:^(NSString *roomId) { - + // Note: the activity indicator will not disappear if the session is not ready [homeViewController stopActivityIndicator]; - + // Check that 'fragment' has not been cancelled if ([universalLinkFragmentPending isEqualToString:fragment]) { @@ -1397,7 +1397,7 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin [fragment stringByReplacingOccurrencesOfString:[MXTools encodeURIComponent:roomIdOrAlias] withString:[MXTools encodeURIComponent:roomId] ]; - + // The previous operation can fail because of percent encoding // TBH we are not clean on data inputs. For the moment, just give another try with no encoding // TODO: Have a dedicated module and tests to handle universal links (matrix.to, email link, etc) @@ -1407,13 +1407,13 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin [fragment stringByReplacingOccurrencesOfString:roomIdOrAlias withString:[MXTools encodeURIComponent:roomId]]; } - + if (![newUniversalLinkFragment isEqualToString:fragment]) { universalLinkFragmentPendingRoomAlias = @{roomId: roomIdOrAlias}; - + UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newUniversalLinkFragment universalLinkURL:universalLinkURL presentationParameters:screenPresentationParameters]; - + [self handleUniversalLinkWithParameters:newParameters]; } else @@ -1422,7 +1422,7 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin MXLogDebug(@"[AppDelegate] Universal link: Error: Cannot resolve alias in %@ to the room id %@", fragment, roomId); } } - + } failure:^(NSError *error) { MXLogDebug(@"[AppDelegate] Universal link: Error: The homeserver failed to resolve the room alias (%@)", roomIdOrAlias); @@ -1439,12 +1439,12 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin // So, wait for the completion of the sync and then retry // FIXME: Manange all user's accounts not only the first one MXKAccount* account = accountManager.activeAccounts.firstObject; - + MXLogDebug(@"[AppDelegate] Universal link: Need to wait for the session to be sync'ed and running"); universalLinkFragmentPending = fragment; - + universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull notif) { - + // Check that 'fragment' has not been cancelled if ([universalLinkFragmentPending isEqualToString:fragment]) { @@ -1460,27 +1460,27 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin else { MXLogDebug(@"[AppDelegate] Universal link: The room (%@) is not known by any account (email invitation: %@). Display its preview to try to join it", roomIdOrAlias, queryParams ? @"YES" : @"NO"); - + // FIXME: In case of multi-account, ask the user which one to use MXKAccount* account = accountManager.activeAccounts.firstObject; - + RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithRoomId:roomIdOrAlias andSession:account.mxSession]; if (queryParams) { roomPreviewData.viaServers = queryParams[@"via"]; } - + RoomPreviewNavigationParameters *roomPreviewNavigationParameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:screenPresentationParameters]; - + [account.mxSession.matrixRestClient roomSummaryWith:roomIdOrAlias via:roomPreviewData.viaServers success:^(MXPublicRoom *room) { if ([room.roomTypeString isEqualToString:MXRoomTypeStringSpace]) { [homeViewController stopActivityIndicator]; - + SpacePreviewNavigationParameters *spacePreviewNavigationParameters = [[SpacePreviewNavigationParameters alloc] initWithPublicRoom:room mxSession:account.mxSession presentationParameters:screenPresentationParameters]; - - [self showSpacePreviewWithParameters:spacePreviewNavigationParameters]; + + [self showSpacePreviewWithParameters:spacePreviewNavigationParameters]; } else { @@ -1490,14 +1490,14 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin [self peekInRoomWithNavigationParameters:roomPreviewNavigationParameters pathParams:pathParams]; }]; } - + } }; - - + + // We will display something but we need to do some requests before. // So, come back to the home VC and show its loading wheel while processing - + if (restoreInitialDisplay) { [self restoreInitialDisplay:^{ @@ -1508,8 +1508,8 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin { findRoom(); } - - + + // Let's say we are handling the case continueUserActivity = YES; } @@ -1520,10 +1520,10 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin // Wait for a successful login MXLogDebug(@"[AppDelegate] Universal link: The user is not logged in. Wait for a successful login"); universalLinkFragmentPending = fragment; - + // Register an observer in order to handle new account universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { - + // Check that 'fragment' has not been cancelled if ([universalLinkFragmentPending isEqualToString:fragment]) { @@ -1567,16 +1567,16 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin if (account) { MXGroup *group = [account.mxSession groupWithGroupId:groupId]; - + if (!group) { // Create a group instance to display its preview group = [[MXGroup alloc] initWithGroupId:groupId]; } - + // Display the group details [self showGroup:group withMatrixSession:account.mxSession presentationParamters:screenPresentationParameters]; - + continueUserActivity = YES; } else @@ -1585,10 +1585,10 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin // Wait for a successful login MXLogDebug(@"[AppDelegate] Universal link: The user is not logged in. Wait for a successful login"); universalLinkFragmentPending = fragment; - + // Register an observer in order to handle new account universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { - + // Check that 'fragment' has not been cancelled if ([universalLinkFragmentPending isEqualToString:fragment]) { @@ -1603,20 +1603,20 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin { MXLogDebug(@"[AppDelegate] Universal link with registration parameters"); continueUserActivity = YES; - + [_masterTabBarController showAuthenticationScreenWithRegistrationParameters:queryParams]; } else { // Unknown command: Do nothing except coming back to the main screen MXLogDebug(@"[AppDelegate] Universal link: TODO: Do not know what to do with the link arguments: %@", pathParams); - + if (restoreInitialDisplay) { [self popToHomeViewControllerAnimated:NO completion:nil]; } } - + return continueUserActivity; } @@ -1624,7 +1624,7 @@ - (BOOL)handleUniversalLinkURL:(NSURL*)universalLinkURL { // iOS Patch: fix vector.im urls before using it NSURL *fixedURL = [Tools fixURLWithSeveralHashKeys:universalLinkURL]; - + return [self handleUniversalLinkFragment:fixedURL.fragment fromURL:universalLinkURL]; } @@ -1642,11 +1642,11 @@ - (void)peekInRoomWithNavigationParameters:(RoomPreviewNavigationParameters*)pre { RoomPreviewData *roomPreviewData = presentationParameters.previewData; NSString *roomIdOrAlias = presentationParameters.roomId; - + // Is it a link to an event of a room? // If yes, the event will be displayed once the room is joined roomPreviewData.eventId = (pathParams.count >= 3) ? pathParams[2] : nil; - + MXWeakify(self); // Try to get more information about the room before opening its preview [roomPreviewData peekInRoom:^(BOOL succeeded) { @@ -1654,28 +1654,28 @@ - (void)peekInRoomWithNavigationParameters:(RoomPreviewNavigationParameters*)pre if ([self.masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) { UIViewController *homeViewController = (UIViewController*)self.masterTabBarController.selectedViewController; - + // Note: the activity indicator will not disappear if the session is not ready [homeViewController stopActivityIndicator]; } - + // If no data is available for this room, we name it with the known room alias (if any). if (!succeeded && self->universalLinkFragmentPendingRoomAlias[roomIdOrAlias]) { roomPreviewData.roomName = self->universalLinkFragmentPendingRoomAlias[roomIdOrAlias]; } self->universalLinkFragmentPendingRoomAlias = nil; - + [self showRoomPreviewWithParameters:presentationParameters]; }]; } /** Extract params from the URL fragment part (after '#') of a vector.im Universal link: - + The fragment can contain a '?'. So there are two kinds of parameters: path params and query params. It is in the form of /[pathParam1]/[pathParam2]?[queryParam1Key]=[queryParam1Value]&[queryParam2Key]=[queryParam2Value] - + @param fragment the fragment to parse. @param outPathParams the decoded path params. @param outQueryParams the decoded query params. If there is no query params, it will be nil. @@ -1683,18 +1683,18 @@ Extract params from the URL fragment part (after '#') of a vector.im Universal l - (void)parseUniversalLinkFragment:(NSString*)fragment outPathParams:(NSArray **)outPathParams outQueryParams:(NSMutableDictionary **)outQueryParams { NSParameterAssert(outPathParams && outQueryParams); - + NSArray *pathParams; NSMutableDictionary *queryParams; - + NSArray *fragments = [fragment componentsSeparatedByString:@"?"]; - + // Extract path params pathParams = [fragments[0] componentsSeparatedByString:@"/"]; - + // Remove the first empty path param string pathParams = [pathParams filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]]; - + // URL decode each path param NSMutableArray *pathParams2 = [NSMutableArray arrayWithArray:pathParams]; for (NSInteger i = 0; i < pathParams.count; i++) @@ -1702,7 +1702,7 @@ - (void)parseUniversalLinkFragment:(NSString*)fragment outPathParams:(NSArrayincomingKeyVerificationObserver) { MXLogDebug(@"[AppDelegate] handleAppState: Set up observers for the crypto module"); - + // Enable listening of incoming key share requests [self enableRoomKeyRequestObserver:mainSession]; - + // Enable listening of incoming key verification requests [self enableIncomingKeyVerificationObserver:mainSession]; } @@ -2390,20 +2390,20 @@ - (void)handleAppState - (void)showLaunchAnimation { UIWindow *window = [[UIApplication sharedApplication] keyWindow]; - + if (!launchAnimationContainerView && window) { MXLogDebug(@"[AppDelegate] showLaunchAnimation"); - + LaunchLoadingView *launchLoadingView = [LaunchLoadingView instantiate]; launchLoadingView.frame = window.bounds; [launchLoadingView updateWithTheme:ThemeService.shared.theme]; launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - + [window addSubview:launchLoadingView]; - + launchAnimationContainerView = launchLoadingView; - + [MXSDKOptions.sharedInstance.profiler startMeasuringTaskWithName:MXTaskProfileNameStartupLaunchScreen]; } } @@ -2417,10 +2417,10 @@ - (void)hideLaunchAnimation if (launchTaskProfile) { [profiler stopMeasuringTaskWithProfile:launchTaskProfile]; - + MXLogDebug(@"[AppDelegate] hideLaunchAnimation: LaunchAnimation was shown for %.3fms", launchTaskProfile.duration * 1000); } - + [self->launchAnimationContainerView removeFromSuperview]; self->launchAnimationContainerView = nil; } @@ -2433,10 +2433,10 @@ - (void)configureCallManagerIfRequiredForSession:(MXSession *)mxSession // already configured return; } - + // Set the VoIP call stack (if supported). id callStack; - + #ifdef MX_CALL_STACK_OPENWEBRTC callStack = [[MXOpenWebRTCCallStack alloc] init]; #endif @@ -2446,17 +2446,17 @@ - (void)configureCallManagerIfRequiredForSession:(MXSession *)mxSession #ifdef CALL_STACK_JINGLE callStack = [[MXJingleCallStack alloc] init]; #endif - + if (callStack) { [mxSession enableVoIPWithCallStack:callStack]; - + // Setup CallKit if ([MXCallKitAdapter callKitAvailable]) { BOOL isCallKitEnabled = [MXKAppSettings standardAppSettings].isCallKitEnabled; [self enableCallKit:isCallKitEnabled forCallManager:mxSession.callManager]; - + // Register for changes performed by the user [[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"enableCallKit" @@ -2479,26 +2479,26 @@ - (void)enableCallKit:(BOOL)enable forCallManager:(MXCallManager *)callManager { #ifdef CALL_STACK_JINGLE JitsiService.shared.enableCallKit = enable; - + if (enable) { // Create adapter for Riot MXCallKitConfiguration *callKitConfiguration = [[MXCallKitConfiguration alloc] init]; callKitConfiguration.iconName = @"callkit_icon"; - + NSData *riotCallKitIconData = UIImagePNGRepresentation([UIImage imageNamed:callKitConfiguration.iconName]); [JitsiService.shared configureCallKitProviderWithLocalizedName:callKitConfiguration.name ringtoneName:callKitConfiguration.ringtoneName iconTemplateImageData:riotCallKitIconData]; MXCallKitAdapter *callKitAdapter = [[MXCallKitAdapter alloc] initWithConfiguration:callKitConfiguration]; - + id audioSessionConfigurator; - + audioSessionConfigurator = [[MXJingleCallAudioSessionConfigurator alloc] init]; - + callKitAdapter.audioSessionConfigurator = audioSessionConfigurator; - + callManager.callKitAdapter = callKitAdapter; } else @@ -2524,7 +2524,7 @@ - (void)checkLocalPrivateKeysInSession:(MXSession*)mxSession { keysCount++; } - + if ((keysCount > 0 && keysCount < 3) || (mxSession.crypto.crossSigning.canTrustCrossSigning && !mxSession.crypto.crossSigning.canCrossSign)) { @@ -2541,7 +2541,7 @@ - (void)authenticationDidComplete /** Ensures room list data is ready. - + @param completion Completion block to be called when it's ready. Not dispatched in case the data is already ready. */ - (void)ensureRoomListDataReadyWithCompletion:(void(^)(void))completion @@ -2577,44 +2577,44 @@ - (void)checkDeviceId:(MXSession*)mxSession if (!isErrorNotificationSuspended && ![[NSUserDefaults standardUserDefaults] boolForKey:@"deviceIdAtStartupChecked"]) { [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"deviceIdAtStartupChecked"]; - + // Check if there is a device id if (!mxSession.matrixRestClient.credentials.deviceId) { MXLogDebug(@"WARNING: The user has no device. Prompt for login again"); - + NSString *msg = [VectorL10n e2eEnablingOnAppUpdate:AppInfo.current.displayName]; - + __weak typeof(self) weakSelf = self; [_errorNotification dismissViewControllerAnimated:NO completion:nil]; _errorNotification = [UIAlertController alertControllerWithTitle:nil message:msg preferredStyle:UIAlertControllerStyleAlert]; - + [_errorNotification addAction:[UIAlertAction actionWithTitle:[VectorL10n later] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->_errorNotification = nil; } - + }]]; - + [_errorNotification addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ok] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->_errorNotification = nil; - + [self logoutWithConfirmation:NO completion:nil]; } - + }]]; - + // Prompt the user [_errorNotification mxk_setAccessibilityIdentifier:@"AppDelegateErrorAlert"]; [self showNotificationAlert:_errorNotification]; @@ -2645,9 +2645,9 @@ - (void)enableInAppNotificationsForAccount:(MXKAccount*)account // Build MXEvent -> NSString formatter EventFormatter *eventFormatter = [[EventFormatter alloc] initWithMatrixSession:account.mxSession]; eventFormatter.isForSubtitle = YES; - + [account listenToNotifications:^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) { - + // Check conditions to display this notification if (![self.visibleRoomId isEqualToString:event.roomId] && !self.window.rootViewController.presentedViewController) @@ -2661,7 +2661,7 @@ - (void)enableInAppNotificationsForAccount:(MXKAccount*)account { [self.mxInAppNotification dismissViewControllerAnimated:NO completion:nil]; } - + // Check whether tweak is required for (MXPushRuleAction *ruleAction in rule.actions) { @@ -2674,31 +2674,31 @@ - (void)enableInAppNotificationsForAccount:(MXKAccount*)account } } } - + MXRoomSummary *roomSummary = [account.mxSession roomSummaryWithRoomId:event.roomId]; - + __weak typeof(self) weakSelf = self; self.mxInAppNotification = [UIAlertController alertControllerWithTitle:roomSummary.displayname message:messageText preferredStyle:UIAlertControllerStyleAlert]; - + [self.mxInAppNotification addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self.mxInAppNotification = nil; [account updateNotificationListenerForRoomId:event.roomId ignore:YES]; } - + }]]; - + [self.mxInAppNotification addAction:[UIAlertAction actionWithTitle:[VectorL10n view] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; @@ -2706,9 +2706,9 @@ - (void)enableInAppNotificationsForAccount:(MXKAccount*)account // Show the room [self showRoom:event.roomId andEventId:nil withMatrixSession:account.mxSession]; } - + }]]; - + [self.window.rootViewController presentViewController:self.mxInAppNotification animated:YES completion:nil]; } } @@ -2719,7 +2719,7 @@ - (void)enableInAppNotificationsForAccount:(MXKAccount*)account [account removeNotificationListener]; } } - + if (self.mxInAppNotification) { [self.mxInAppNotification dismissViewControllerAnimated:NO completion:nil]; @@ -2730,7 +2730,7 @@ - (void)enableInAppNotificationsForAccount:(MXKAccount*)account - (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection { NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; - + if (mxAccounts.count == 1) { if (onSelection) @@ -2741,47 +2741,47 @@ - (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection else if (mxAccounts.count > 1) { [accountPicker dismissViewControllerAnimated:NO completion:nil]; - + accountPicker = [UIAlertController alertControllerWithTitle:[MatrixKitL10n selectAccount] message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - + __weak typeof(self) weakSelf = self; for(MXKAccount *account in mxAccounts) { [accountPicker addAction:[UIAlertAction actionWithTitle:account.mxCredentials.userId style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->accountPicker = nil; - + if (onSelection) { onSelection(account); } } - + }]]; } - + [accountPicker addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->accountPicker = nil; - + if (onSelection) { onSelection(nil); } } - + }]]; - + [self showNotificationAlert:accountPicker]; } } @@ -2841,40 +2841,40 @@ - (void)showRoomWithParameters:(RoomNavigationParameters*)parameters completion: NSString *roomId = parameters.roomId; MXSession *mxSession = parameters.mxSession; BOOL restoreInitialDisplay = parameters.presentationParameters.restoreInitialDisplay; - + if (roomId && mxSession) { MXRoom *room = [mxSession roomWithRoomId:roomId]; - + // Indicates that spaces are not supported if (room.summary.roomType == MXRoomTypeSpace) { - + [self.spaceFeatureUnavailablePresenter presentUnavailableFeatureFrom:self.presentedViewController animated:YES]; - + if (completion) { completion(); } - + return; } } - + void (^selectRoom)(void) = ^() { // Select room to display its details (dispatch this action in order to let TabBarController end its refresh) - + [self.masterTabBarController selectRoomWithParameters:parameters completion:^{ // Remove delivered notifications for this room [self.pushNotificationService removeDeliveredNotificationsWithRoomId:roomId completion:nil]; - + if (completion) { completion(); } }]; }; - + if (restoreInitialDisplay) { [self restoreInitialDisplay:^{ @@ -2891,10 +2891,10 @@ - (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSessi { // Ask to restore initial display ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES]; - + RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId eventId:eventId mxSession:mxSession presentationParameters:presentationParameters]; - + [self showRoomWithParameters:parameters]; } @@ -2903,7 +2903,7 @@ - (void)showRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)paramete void (^showRoomPreview)(void) = ^() { [self.masterTabBarController selectRoomPreviewWithParameters:parameters completion:completion]; }; - + if (parameters.presentationParameters.restoreInitialDisplay) { [self restoreInitialDisplay:^{ @@ -2925,9 +2925,9 @@ - (void)showRoomPreview:(RoomPreviewData*)roomPreviewData { // Ask to restore initial display ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES]; - + RoomPreviewNavigationParameters *parameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:presentationParameters]; - + [self showRoomPreviewWithParameters:parameters]; } @@ -2935,7 +2935,7 @@ - (void)showSpacePreviewWithParameters:(SpacePreviewNavigationParameters*)parame { UIViewController *presentingViewController; UIView *sourceView; - + if (parameters.presentationParameters.presentingViewController) { presentingViewController = parameters.presentationParameters.presentingViewController; @@ -2945,18 +2945,18 @@ - (void)showSpacePreviewWithParameters:(SpacePreviewNavigationParameters*)parame { presentingViewController = self.masterNavigationController; } - + self.spaceDetailPresenter = [SpaceDetailPresenter new]; self.spaceDetailPresenter.delegate = self; - + void(^showSpace)(void) = ^{ [self.spaceDetailPresenter presentForSpaceWithPublicRoom:parameters.publicRoom from:presentingViewController sourceView:sourceView - session:parameters.mxSession + session:parameters.mxSession animated:YES]; }; - + if (parameters.presentationParameters.restoreInitialDisplay) { [self restoreInitialDisplay:^{ @@ -2973,7 +2973,7 @@ - (void)showSpaceWithParameters:(SpaceNavigationParameters*)parameters { UIViewController *presentingViewController; UIView *sourceView; - + if (parameters.presentationParameters.presentingViewController) { presentingViewController = parameters.presentationParameters.presentingViewController; @@ -2986,7 +2986,7 @@ - (void)showSpaceWithParameters:(SpaceNavigationParameters*)parameters self.spaceDetailPresenter = [SpaceDetailPresenter new]; self.spaceDetailPresenter.delegate = self; - + void(^showSpace)(void) = ^{ [self.spaceDetailPresenter presentForSpaceWithId:parameters.roomId from:presentingViewController @@ -2994,7 +2994,7 @@ - (void)showSpaceWithParameters:(SpaceNavigationParameters*)parameters session:parameters.mxSession animated:YES]; }; - + if (parameters.presentationParameters.restoreInitialDisplay) { [self restoreInitialDisplay:^{ @@ -3018,7 +3018,7 @@ - (void)setVisibleRoomId:(NSString *)roomId [account updateNotificationListenerForRoomId:roomId ignore:NO]; } } - + _visibleRoomId = roomId; } @@ -3026,9 +3026,9 @@ - (void)createDirectChatWithUserId:(NSString*)userId completion:(void (^)(void)) { // Handle here potential multiple accounts [self selectMatrixAccount:^(MXKAccount *selectedAccount) { - + MXSession *mxSession = selectedAccount.mxSession; - + if (mxSession) { // Create a new room by inviting the other user only if it is defined and not oneself @@ -3046,7 +3046,7 @@ - (void)createDirectChatWithUserId:(NSString*)userId completion:(void (^)(void)) }; [mxSession vc_canEnableE2EByDefaultInNewRoomWithUsers:invite success:^(BOOL canEnableE2E) { - + MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters new]; roomCreationParameters.visibility = kMXRoomDirectoryVisibilityPrivate; roomCreationParameters.inviteArray = invite; @@ -3078,7 +3078,7 @@ - (void)createDirectChatWithUserId:(NSString*)userId completion:(void (^)(void)) { completion(); } - + }]; } @@ -3086,19 +3086,19 @@ - (void)startDirectChatWithUserId:(NSString*)userId completion:(void (^)(void))c { // Handle here potential multiple accounts [self selectMatrixAccount:^(MXKAccount *selectedAccount) { - + MXSession *mxSession = selectedAccount.mxSession; - + if (mxSession) { MXRoom *directRoom = [mxSession directJoinedRoomWithUserId:userId]; - + // if the room exists if (directRoom) { // open it [self showRoom:directRoom.roomId andEventId:nil withMatrixSession:mxSession]; - + if (completion) { completion(); @@ -3113,7 +3113,7 @@ - (void)startDirectChatWithUserId:(NSString*)userId completion:(void (^)(void))c { completion(); } - + }]; } @@ -3124,7 +3124,7 @@ - (void)showContact:(MXKContact*)contact presentationParameters:(ScreenPresentat void(^showContact)(void) = ^{ [self.masterTabBarController selectContact:contact withPresentationParameters:presentationParameters]; }; - + if (presentationParameters.restoreInitialDisplay) { [self restoreInitialDisplay:^{ @@ -3172,15 +3172,15 @@ - (void)promptForStunServerFallback NSString *message = [NSString stringWithFormat:@"%@\n\n%@", [VectorL10n callNoStunServerErrorMessage1:homeServerName], [VectorL10n callNoStunServerErrorMessage2:stunFallbackHost]]; - + _errorNotification = [UIAlertController alertControllerWithTitle:[VectorL10n callNoStunServerErrorTitle] message:message preferredStyle:UIAlertControllerStyleAlert]; - + [_errorNotification addAction:[UIAlertAction actionWithTitle:[VectorL10n callNoStunServerErrorUseFallbackButton:stunFallbackHost] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + RiotSettings.shared.allowStunServerFallback = YES; mainSession.callManager.fallbackSTUNServer = BuildSettings.stunServerFallbackUrlString; @@ -3241,7 +3241,7 @@ - (void)checkPermissionForNativeWidget:(Widget*)widget fromUrl:(NSURL*)url compl MXLogDebug(@"[WidgetVC] setPermissionForWidget failed. Error: %@", error); sharedSettings = nil; }]; - + completion(granted); }]; } @@ -3253,18 +3253,18 @@ - (void)askNativeWidgetPermissionWithWidget:(Widget*)widget completion:(void (^) { self.slidingModalPresenter = [SlidingModalPresenter new]; } - + [self.slidingModalPresenter dismissWithAnimated:NO completion:nil]; - + NSString *widgetCreatorUserId = widget.widgetEvent.sender ?: [VectorL10n roomParticipantsUnknown]; - + MXSession *session = widget.mxSession; MXRoom *room = [session roomWithRoomId:widget.widgetEvent.roomId]; MXRoomState *roomState = room.dangerousSyncState; MXRoomMember *widgetCreatorRoomMember = [roomState.members memberWithUserId:widgetCreatorUserId]; - + NSString *widgetDomain = @""; - + if (widget.url) { NSString *host = [[NSURL alloc] initWithString:widget.url].host; @@ -3273,45 +3273,45 @@ - (void)askNativeWidgetPermissionWithWidget:(Widget*)widget completion:(void (^) widgetDomain = host; } } - + MXMediaManager *mediaManager = widget.mxSession.mediaManager; NSString *widgetCreatorDisplayName = widgetCreatorRoomMember.displayname; NSString *widgetCreatorAvatarURL = widgetCreatorRoomMember.avatarUrl; - + NSArray *permissionStrings = @[ [VectorL10n roomWidgetPermissionDisplayNamePermission], [VectorL10n roomWidgetPermissionAvatarUrlPermission] ]; - + WidgetPermissionViewModel *widgetPermissionViewModel = [[WidgetPermissionViewModel alloc] initWithCreatorUserId:widgetCreatorUserId creatorDisplayName:widgetCreatorDisplayName creatorAvatarUrl:widgetCreatorAvatarURL widgetDomain:widgetDomain isWebviewWidget:NO widgetPermissions:permissionStrings mediaManager:mediaManager]; - - + + WidgetPermissionViewController *widgetPermissionViewController = [WidgetPermissionViewController instantiateWith:widgetPermissionViewModel]; - + MXWeakify(self); - + widgetPermissionViewController.didTapContinueButton = ^{ - + MXStrongifyAndReturnIfNil(self); - + [self.slidingModalPresenter dismissWithAnimated:YES completion:^{ completion(YES); }]; }; - + widgetPermissionViewController.didTapCloseButton = ^{ - + MXStrongifyAndReturnIfNil(self); - + [self.slidingModalPresenter dismissWithAnimated:YES completion:^{ completion(NO); }]; }; - + [self.slidingModalPresenter present:widgetPermissionViewController from:self.presentedViewController animated:YES @@ -3323,12 +3323,12 @@ - (void)askNativeWidgetPermissionWithWidget:(Widget*)widget completion:(void (^) - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; - + UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self.window]; - + CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame; - + if (CGRectContainsPoint(statusBarFrame, point)) { [[NSNotificationCenter defaultCenter] postNotificationName:kAppDelegateDidTapStatusBarNotification object:nil]; @@ -3338,7 +3338,7 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event #pragma mark - No call support /** Display a "Call not supported" alert when the session receives a call invitation. - + @param mxSession the session to spy */ - (void)enableNoVoIPOnMatrixSession:(MXSession*)mxSession @@ -3355,7 +3355,7 @@ - (void)enableNoVoIPOnMatrixSession:(MXSession*)mxSession kMXEventTypeStringCallNegotiate ] onEvent:^(MXEvent *event, MXTimelineDirection direction, id customObject) { - + if (MXTimelineDirectionForwards == direction) { switch (event.eventType) @@ -3366,71 +3366,71 @@ - (void)enableNoVoIPOnMatrixSession:(MXSession*)mxSession { [noCallSupportAlert dismissViewControllerAnimated:NO completion:nil]; } - + MXCallInviteEventContent *callInviteEventContent = [MXCallInviteEventContent modelFromJSON:event.content]; - + // Sanity and invite expiration checks if (!callInviteEventContent || event.age >= callInviteEventContent.lifetime) { return; } - + MXUser *caller = [mxSession userWithUserId:event.sender]; NSString *callerDisplayname = caller.displayname; if (!callerDisplayname.length) { callerDisplayname = event.sender; } - + NSString *appDisplayName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"]; - + NSString *message = [VectorL10n noVoip:callerDisplayname :appDisplayName]; - + noCallSupportAlert = [UIAlertController alertControllerWithTitle:[VectorL10n noVoipTitle] message:message preferredStyle:UIAlertControllerStyleAlert]; - + __weak typeof(self) weakSelf = self; - + [noCallSupportAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ignore] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + if (weakSelf) { typeof(self) self = weakSelf; self->noCallSupportAlert = nil; } - + }]]; - + [noCallSupportAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n rejectCall] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + // Reject the call by sending the hangup event NSDictionary *content = @{ @"call_id": callInviteEventContent.callId, @"version": kMXCallVersion, @"party_id": mxSession.myDeviceId }; - + [mxSession.matrixRestClient sendEventToRoom:event.roomId eventType:kMXEventTypeStringCallReject content:content txnId:nil success:nil failure:^(NSError *error) { MXLogDebug(@"[AppDelegate] enableNoVoIPOnMatrixSession: ERROR: Cannot send m.call.reject event."); }]; - + if (weakSelf) { typeof(self) self = weakSelf; self->noCallSupportAlert = nil; } - + }]]; - + [self showNotificationAlert:noCallSupportAlert]; break; } - + case MXEventTypeCallAnswer: case MXEventTypeCallHangup: case MXEventTypeCallReject: @@ -3441,19 +3441,19 @@ - (void)enableNoVoIPOnMatrixSession:(MXSession*)mxSession noCallSupportAlert = nil; } break; - + default: break; } } - + }]; - + } - (void)disableNoVoIPOnMatrixSession:(MXSession*)mxSession { - // Stop listening to the call events of this session + // Stop listening to the call events of this session [mxSession removeListener:callEventsListeners[@(mxSession.hash)]]; [callEventsListeners removeObjectForKey:@(mxSession.hash)]; } @@ -3468,16 +3468,16 @@ - (void)checkCrossSigningForSession:(MXSession*)mxSession MXLogDebug(@"[AppDelegate] checkCrossSigningForSession called while the app is not active. Ignore it."); return; } - + if (mxSession.crypto.crossSigning) { // Get the up-to-date cross-signing state MXWeakify(self); [mxSession.crypto.crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) { MXStrongifyAndReturnIfNil(self); - + MXLogDebug(@"[AppDelegate] handleAppState: crossSigning.state: %@", @(mxSession.crypto.crossSigning.state)); - + switch (mxSession.crypto.crossSigning.state) { case MXCrossSigningStateCrossSigningExists: @@ -3547,7 +3547,7 @@ - (void)checkPendingRoomKeyRequestsInSession:(MXSession*)mxSession MXWeakify(self); [mxSession.crypto pendingKeyRequests:^(MXUsersDevicesMap *> *pendingKeyRequests) { - + MXStrongifyAndReturnIfNil(self); MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: cross-signing state: %ld, pendingKeyRequests.count: %@. Already displayed: %@", mxSession.crypto.crossSigning.state, @@ -3581,11 +3581,11 @@ - (void)checkPendingRoomKeyRequestsInSession:(MXSession*)mxSession // Pick the first coming user/device pair NSString *userId = pendingKeyRequests.userIds.firstObject; NSString *deviceId = [pendingKeyRequests deviceIdsForUser:userId].firstObject; - + // Give the client a chance to refresh the device list MXWeakify(self); [mxSession.crypto downloadKeys:@[userId] forceDownload:NO success:^(MXUsersDevicesMap *usersDevicesInfoMap, NSDictionary *crossSigningKeysMap) { - + MXStrongifyAndReturnIfNil(self); MXDeviceInfo *deviceInfo = [usersDevicesInfoMap objectForDevice:deviceId forUser:userId]; if (deviceInfo) @@ -3593,7 +3593,7 @@ - (void)checkPendingRoomKeyRequestsInSession:(MXSession*)mxSession if (!mxSession.crypto.crossSigning || mxSession.crypto.crossSigning.state == MXCrossSigningStateNotBootstrapped) { BOOL wasNewDevice = (deviceInfo.trustLevel.localVerificationStatus == MXDeviceUnknown); - + void (^openDialog)(void) = ^void() { MXLogDebug(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Open dialog for %@", deviceInfo); @@ -3648,7 +3648,7 @@ - (void)checkPendingRoomKeyRequestsInSession:(MXSession*)mxSession }]; } -// Check all opened MXSessions for key share dialog +// Check all opened MXSessions for key share dialog - (void)checkPendingRoomKeyRequests { for (MXSession *mxSession in mxSessionArray) @@ -3725,23 +3725,23 @@ - (BOOL)presentIncomingKeyVerificationRequest:(MXKeyVerificationRequest*)incomin inSession:(MXSession*)session { BOOL presented = NO; - + if (!keyVerificationCoordinatorBridgePresenter.isPresenting) { MXLogDebug(@"[AppDelegate] presentIncomingKeyVerificationRequest"); - + keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:session]; keyVerificationCoordinatorBridgePresenter.delegate = self; - + [keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController incomingKeyVerificationRequest:incomingKeyVerificationRequest animated:YES]; - + presented = YES; } else { MXLogDebug(@"[AppDelegate][MXKeyVerification] presentIncomingKeyVerificationRequest: Controller already presented."); } - + return presented; } @@ -3769,15 +3769,15 @@ - (BOOL)presentIncomingKeyVerification:(MXIncomingSASTransaction*)transaction in - (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember session:(MXSession*)mxSession { MXLogDebug(@"[AppDelegate][MXKeyVerification] presentUserVerificationForRoomMember: %@", roomMember); - + BOOL presented = NO; if (!keyVerificationCoordinatorBridgePresenter.isPresenting) { keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession]; keyVerificationCoordinatorBridgePresenter.delegate = self; - + [keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController roomMember:roomMember animated:YES]; - + presented = YES; } else @@ -3790,15 +3790,15 @@ - (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember session:( - (BOOL)presentSelfVerificationForOtherDeviceId:(NSString*)deviceId inSession:(MXSession*)mxSession { MXLogDebug(@"[AppDelegate][MXKeyVerification] presentSelfVerificationForOtherDeviceId: %@", deviceId); - + BOOL presented = NO; if (!keyVerificationCoordinatorBridgePresenter.isPresenting) { keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession]; keyVerificationCoordinatorBridgePresenter.delegate = self; - + [keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController otherUserId:mxSession.myUser.userId otherDeviceId:deviceId animated:YES]; - + presented = YES; } else @@ -3829,7 +3829,7 @@ - (void)dismissKeyVerificationCoordinatorBridgePresenter [keyVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{ [self checkPendingIncomingKeyVerifications]; }]; - + keyVerificationCoordinatorBridgePresenter = nil; } @@ -3838,12 +3838,12 @@ - (void)dismissKeyVerificationCoordinatorBridgePresenter - (void)registerNewRequestNotificationForSession:(MXSession*)session { MXKeyVerificationManager *keyverificationManager = session.crypto.keyVerificationManager; - + if (!keyverificationManager) { return; } - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyVerificationNewRequestNotification:) name:MXKeyVerificationManagerNewRequestNotification object:keyverificationManager]; } @@ -3853,26 +3853,26 @@ - (void)keyVerificationNewRequestNotification:(NSNotification *)notification { return; } - + if (_masterTabBarController.authenticationInProgress) { MXLogDebug(@"[AppDelegate][KeyVerification] keyVerificationNewRequestNotification: Postpone requests during the authentication process"); - + // 10s is quite arbitrary dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self keyVerificationNewRequestNotification:notification]; }); return; } - + NSDictionary *userInfo = notification.userInfo; - + MXKeyVerificationRequest *keyVerificationRequest = userInfo[MXKeyVerificationManagerNotificationRequestKey]; - + if ([keyVerificationRequest isKindOfClass:MXKeyVerificationByDMRequest.class]) { MXKeyVerificationByDMRequest *keyVerificationByDMRequest = (MXKeyVerificationByDMRequest*)keyVerificationRequest; - + if (!keyVerificationByDMRequest.isFromMyUser && keyVerificationByDMRequest.state == MXKeyVerificationRequestStatePending) { MXKAccount *currentAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject; @@ -3883,13 +3883,13 @@ - (void)keyVerificationNewRequestNotification:(NSNotification *)notification MXLogDebug(@"[AppDelegate][KeyVerification] keyVerificationRequestDidChangeNotification: Unknown room"); return; } - + NSString *sender = keyVerificationByDMRequest.otherUser; [room state:^(MXRoomState *roomState) { NSString *senderName = [roomState.members memberName:sender]; - + [self presentNewKeyVerificationRequestAlertForSession:session senderName:senderName senderId:sender request:keyVerificationByDMRequest]; }]; } @@ -3897,7 +3897,7 @@ - (void)keyVerificationNewRequestNotification:(NSNotification *)notification else if ([keyVerificationRequest isKindOfClass:MXKeyVerificationByToDeviceRequest.class]) { MXKeyVerificationByToDeviceRequest *keyVerificationByToDeviceRequest = (MXKeyVerificationByToDeviceRequest*)keyVerificationRequest; - + if (!keyVerificationByToDeviceRequest.isFromMyDevice && keyVerificationByToDeviceRequest.state == MXKeyVerificationRequestStatePending) { @@ -3905,20 +3905,20 @@ - (void)keyVerificationNewRequestNotification:(NSNotification *)notification { // Self verification MXLogDebug(@"[AppDelegate][KeyVerification] keyVerificationNewRequestNotification: Self verification from %@", keyVerificationByToDeviceRequest.otherDevice); - + if (!self.handleSelfVerificationRequest) { MXLogDebug(@"[AppDelegate][KeyVerification] keyVerificationNewRequestNotification: Self verification handled elsewhere"); return; } - + NSString *myUserId = keyVerificationByToDeviceRequest.otherUser; MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:myUserId]; if (account) { MXSession *session = account.mxSession; MXUser *user = [session userWithUserId:myUserId]; - + [self presentNewKeyVerificationRequestAlertForSession:session senderName:user.displayname senderId:user.userId request:keyVerificationRequest]; } } @@ -3927,7 +3927,7 @@ - (void)keyVerificationNewRequestNotification:(NSNotification *)notification // Device verification from other user // This happens when they or our user do not have cross-signing enabled MXLogDebug(@"[AppDelegate][KeyVerification] keyVerificationNewRequestNotification: Device verification from other user %@:%@", keyVerificationByToDeviceRequest.otherUser, keyVerificationByToDeviceRequest.otherDevice); - + NSString *myUserId = keyVerificationByToDeviceRequest.to; NSString *userId = keyVerificationByToDeviceRequest.otherUser; MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:myUserId]; @@ -3935,7 +3935,7 @@ - (void)keyVerificationNewRequestNotification:(NSNotification *)notification { MXSession *session = account.mxSession; MXUser *user = [session userWithUserId:userId]; - + [self presentNewKeyVerificationRequestAlertForSession:session senderName:user.displayname senderId:user.userId request:keyVerificationRequest]; } } @@ -3957,12 +3957,12 @@ - (void)presentNewKeyVerificationRequestAlertForSession:(MXSession*)session MXLogDebug(@"[AppDelegate] presentNewKeyVerificationRequest: Request already accepted. Do not display it"); return; } - + if (self.incomingKeyVerificationRequestAlertController) { [self.incomingKeyVerificationRequestAlertController dismissViewControllerAnimated:NO completion:nil]; } - + if (self.userNewSignInAlertController && [session.myUserId isEqualToString:senderId]) { @@ -3974,9 +3974,9 @@ - (void)presentNewKeyVerificationRequestAlertForSession:(MXSession*)session [self presentNewKeyVerificationRequestAlertForSession:session senderName:senderName senderId:senderId request:keyVerificationRequest]; }]; } - + NSString *senderInfo; - + if (senderName) { senderInfo = [NSString stringWithFormat:@"%@ (%@)", senderName, senderId]; @@ -3985,8 +3985,8 @@ - (void)presentNewKeyVerificationRequestAlertForSession:(MXSession*)session { senderInfo = senderId; } - - + + __block id observer; void (^removeObserver)(void) = ^() { if (observer) @@ -3995,38 +3995,38 @@ - (void)presentNewKeyVerificationRequestAlertForSession:(MXSession*)session observer = nil; } }; - + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[VectorL10n keyVerificationTileRequestIncomingTitle] message:senderInfo preferredStyle:UIAlertControllerStyleAlert]; - + [alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n keyVerificationTileRequestIncomingApprovalAccept] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { removeObserver(); [self presentIncomingKeyVerificationRequest:keyVerificationRequest inSession:session]; }]]; - + [alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n keyVerificationTileRequestIncomingApprovalDecline] style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { removeObserver(); [keyVerificationRequest cancelWithCancelCode:MXTransactionCancelCode.user success:^{ - + } failure:^(NSError * _Nonnull error) { MXLogDebug(@"[AppDelegate][KeyVerification] Fail to cancel incoming key verification request with error: %@", error); }]; }]]; - + [alertController addAction:[UIAlertAction actionWithTitle:[VectorL10n later] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { removeObserver(); }]]; - + [self presentViewController:alertController animated:YES completion:nil]; self.incomingKeyVerificationRequestAlertController = alertController; - + observer = [[NSNotificationCenter defaultCenter] addObserverForName:MXKeyVerificationRequestDidChangeNotification object:keyVerificationRequest queue:[NSOperationQueue mainQueue] @@ -4047,41 +4047,41 @@ - (void)presentNewKeyVerificationRequestAlertForSession:(MXSession*)session - (void)registerUserDidSignInOnNewDeviceNotificationForSession:(MXSession*)session { MXCrossSigning *crossSigning = session.crypto.crossSigning; - + if (!crossSigning) { return; } - + self.userDidSignInOnNewDeviceObserver = [NSNotificationCenter.defaultCenter addObserverForName:MXCrossSigningMyUserDidSignInOnNewDeviceNotification object:crossSigning queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { NSArray *deviceIds = notification.userInfo[MXCrossSigningNotificationDeviceIdsKey]; - + [session.matrixRestClient devices:^(NSArray *devices) { - + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.deviceId IN %@", deviceIds]; NSArray *newDevices = [devices filteredArrayUsingPredicate:predicate]; - + NSArray *sortedDevices = [newDevices sortedArrayUsingComparator:^NSComparisonResult(MXDevice * _Nonnull device1, MXDevice * _Nonnull device2) { - + if (device1.lastSeenTs == device2.lastSeenTs) { return NSOrderedSame; } - + return device1.lastSeenTs > device2.lastSeenTs ? NSOrderedDescending : NSOrderedAscending; }]; - + MXDevice *mostRecentDevice = sortedDevices.lastObject; - + if (mostRecentDevice) { [self presentNewSignInAlertForDevice:mostRecentDevice inSession:session]; } - + } failure:^(NSError *error) { MXLogDebug(@"[AppDelegate][NewSignIn] Fail to fetch devices"); }]; @@ -4091,14 +4091,14 @@ - (void)registerUserDidSignInOnNewDeviceNotificationForSession:(MXSession*)sessi - (void)presentNewSignInAlertForDevice:(MXDevice*)device inSession:(MXSession*)session { MXLogDebug(@"[AppDelegate] presentNewSignInAlertForDevice: %@", device.deviceId); - + if (self.userNewSignInAlertController) { [self.userNewSignInAlertController dismissViewControllerAnimated:NO completion:nil]; } - + NSString *deviceInfo; - + if (device.displayName) { deviceInfo = [NSString stringWithFormat:@"%@ (%@)", device.displayName, device.deviceId]; @@ -4107,28 +4107,28 @@ - (void)presentNewSignInAlertForDevice:(MXDevice*)device inSession:(MXSession*)s { deviceInfo = device.deviceId; } - + NSString *alertMessage = [VectorL10n deviceVerificationSelfVerifyAlertMessage:deviceInfo]; - + UIAlertController *alert = [UIAlertController alertControllerWithTitle:[VectorL10n deviceVerificationSelfVerifyAlertTitle] message:alertMessage preferredStyle:UIAlertControllerStyleAlert]; - + [alert addAction:[UIAlertAction actionWithTitle:[VectorL10n deviceVerificationSelfVerifyAlertValidateAction] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { self.userNewSignInAlertController = nil; [self presentSelfVerificationForOtherDeviceId:device.deviceId inSession:session]; }]]; - + [alert addAction:[UIAlertAction actionWithTitle:[VectorL10n later] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { self.userNewSignInAlertController = nil; }]]; - + [self presentViewController:alert animated:YES completion:nil]; - + self.userNewSignInAlertController = alert; } @@ -4138,12 +4138,12 @@ - (void)presentNewSignInAlertForDevice:(MXDevice*)device inSession:(MXSession*)s - (void)registerDidChangeCrossSigningKeysNotificationForSession:(MXSession*)session { MXCrossSigning *crossSigning = session.crypto.crossSigning; - + if (!crossSigning) { return; } - + MXWeakify(self); self.userDidChangeCrossSigningKeysObserver = [NSNotificationCenter.defaultCenter addObserverForName:MXCrossSigningDidChangeCrossSigningKeysNotification @@ -4151,15 +4151,15 @@ - (void)registerDidChangeCrossSigningKeysNotificationForSession:(MXSession*)sess queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { - + MXStrongifyAndReturnIfNil(self); - + MXLogDebug(@"[AppDelegate] registerDidChangeCrossSigningKeysNotificationForSession"); - + if (self.userNewSignInAlertController) { MXLogDebug(@"[AppDelegate] registerDidChangeCrossSigningKeysNotificationForSession: Hide NewSignInAlertController"); - + [self.userNewSignInAlertController dismissViewControllerAnimated:NO completion:^{ [self.masterTabBarController presentVerifyCurrentSessionAlertIfNeededWithSession:session]; }]; @@ -4178,15 +4178,15 @@ - (void)registerDidChangeCrossSigningKeysNotificationForSession:(MXSession*)sess - (BOOL)presentCompleteSecurityForSession:(MXSession*)mxSession { MXLogDebug(@"[AppDelegate][MXKeyVerification] presentCompleteSecurityForSession"); - + BOOL presented = NO; if (!keyVerificationCoordinatorBridgePresenter.isPresenting) { keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession]; keyVerificationCoordinatorBridgePresenter.delegate = self; - + [keyVerificationCoordinatorBridgePresenter presentCompleteSecurityFrom:self.presentedViewController isNewSignIn:NO animated:YES]; - + presented = YES; } else @@ -4213,36 +4213,36 @@ - (void)registerUserConsentNotGivenNotification { self.gdprConsentNotGivenAlertController = nil; self.gdprConsentController = nil; - + __weak typeof(self) weakSelf = self; - + MXSession *mainSession = self.mxSessions.firstObject; NSString *homeServerName = mainSession.matrixRestClient.credentials.homeServerName; - + NSString *alertMessage = [VectorL10n gdprConsentNotGivenAlertMessage:homeServerName]; - + UIAlertController *alert = [UIAlertController alertControllerWithTitle:[VectorL10n settingsTermConditions] message:alertMessage preferredStyle:UIAlertControllerStyleAlert]; - + [alert addAction:[UIAlertAction actionWithTitle:[VectorL10n gdprConsentNotGivenAlertReviewNowAction] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - + typeof(weakSelf) strongSelf = weakSelf; - + if (strongSelf) { [strongSelf presentGDPRConsentFromViewController:self.presentedViewController consentURI:consentURI]; } }]]; - + [alert addAction:[UIAlertAction actionWithTitle:[VectorL10n later] style:UIAlertActionStyleCancel handler:nil]]; - + [self presentViewController:alert animated:YES completion:nil]; - + self.gdprConsentNotGivenAlertController = alert; } }]; @@ -4250,26 +4250,26 @@ - (void)registerUserConsentNotGivenNotification - (void)presentGDPRConsentFromViewController:(UIViewController*)viewController consentURI:(NSString*)consentURI { - GDPRConsentViewController *gdprConsentViewController = [[GDPRConsentViewController alloc] initWithURL:consentURI]; - + GDPRConsentViewController *gdprConsentViewController = [[GDPRConsentViewController alloc] initWithURL:consentURI]; + UIBarButtonItem *closeBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[MatrixKitL10n close] style:UIBarButtonItemStylePlain target:self action:@selector(dismissGDPRConsent)]; - + gdprConsentViewController.navigationItem.leftBarButtonItem = closeBarButtonItem; - + UINavigationController *navigationController = [[RiotNavigationController alloc] initWithRootViewController:gdprConsentViewController]; - + [viewController presentViewController:navigationController animated:YES completion:nil]; - + self.gdprConsentController = navigationController; - + gdprConsentViewController.delegate = self; } - (void)dismissGDPRConsent -{ +{ [self.gdprConsentController dismissViewControllerAnimated:YES completion:nil]; } @@ -4281,21 +4281,21 @@ - (void)gdprConsentViewControllerDidConsentToGDPRWithSuccess:(GDPRConsentViewCon // Leave the GDPR consent right now [self dismissGDPRConsent]; - + BOOL botCreationEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableBotCreation"]; if (botCreationEnabled) { // And create the room with riot bot in // self.onBoardingManager = [[OnBoardingManager alloc] initWithSession:session]; - + MXWeakify(self); void (^createRiotBotDMcompletion)(void) = ^() { MXStrongifyAndReturnIfNil(self); self.onBoardingManager = nil; }; - + [self.onBoardingManager createRiotBotDirectMessageIfNeededWithSuccess:^{ createRiotBotDMcompletion(); } failure:^(NSError * _Nonnull error) { @@ -4312,21 +4312,21 @@ - (void)setupUserDefaults NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; NSMutableDictionary *defaults = [[NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp] mutableCopy]; - + // add pusher ids, as they don't belong to plist anymore defaults[@"pushKitAppIdProd"] = BuildSettings.pushKitAppIdProd; defaults[@"pushKitAppIdDev"] = BuildSettings.pushKitAppIdDev; defaults[@"pusherAppIdProd"] = BuildSettings.pusherAppIdProd; defaults[@"pusherAppIdDev"] = BuildSettings.pusherAppIdDev; - + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; - + // Migrates old UserDefaults values if showDecryptedContentInNotifications hasn't been set if (!RiotSettings.shared.isUserDefaultsMigrated) { [RiotSettings.shared migrate]; } - + // Show encrypted message notification content by default. if (!RiotSettings.shared.isShowDecryptedContentInNotificationsHasBeenSetOnce) { @@ -4340,7 +4340,7 @@ - (void)checkAppVersion { // Check if we should display a major update alert [self checkMajorUpdate]; - + // Update the last app version used [AppVersion updateLastUsedVersion]; } @@ -4362,36 +4362,36 @@ - (void)showMajorUpdate { self.slidingModalPresenter = [SlidingModalPresenter new]; } - + [self.slidingModalPresenter dismissWithAnimated:NO completion:nil]; - + MajorUpdateViewController *majorUpdateViewController = [MajorUpdateViewController instantiate]; - + MXWeakify(self); - + majorUpdateViewController.didTapLearnMoreButton = ^{ - + MXStrongifyAndReturnIfNil(self); - + [[UIApplication sharedApplication] vc_open:self.majorUpdateManager.learnMoreURL completionHandler:^(BOOL success) { if (!success) { [self showAlertWithTitle:[MatrixKitL10n error] message:[VectorL10n roomMessageUnableOpenLinkErrorMessage]]; } }]; - + [self.slidingModalPresenter dismissWithAnimated:YES completion:^{ }]; }; - + majorUpdateViewController.didTapDoneButton = ^{ - + MXStrongifyAndReturnIfNil(self); - + [self.slidingModalPresenter dismissWithAnimated:YES completion:^{ }]; }; - + [self.slidingModalPresenter present:majorUpdateViewController from:self.presentedViewController animated:YES @@ -4430,7 +4430,7 @@ - (void)callPresenter:(CallPresenter *)presenter presentCallViewController:(Call { viewController.modalPresentationStyle = UIModalPresentationFullScreen; } - + [self presentViewController:viewController animated:NO completion:completion]; } @@ -4440,7 +4440,7 @@ - (void)callPresenter:(CallPresenter *)presenter dismissCallViewController:(UIVi if (viewController.presentingViewController) { [viewController.presentingViewController dismissViewControllerAnimated:NO completion:^{ - + if ([viewController isKindOfClass:CallViewController.class]) { CallViewController *callVC = (CallViewController *)viewController; @@ -4449,12 +4449,12 @@ - (void)callPresenter:(CallPresenter *)presenter dismissCallViewController:(UIVi [self promptForStunServerFallback]; } } - + if (completion) { completion(); } - + }]; } else @@ -4488,7 +4488,7 @@ - (void)callPresenter:(CallPresenter *)presenter exitPipForCallViewController:(U { viewController.modalPresentationStyle = UIModalPresentationFullScreen; } - + [self presentViewController:viewController animated:YES completion:completion]; } @@ -4497,13 +4497,13 @@ - (void)callPresenter:(CallPresenter *)presenter exitPipForCallViewController:(U - (BOOL)continueSSOLoginWithToken:(NSString*)loginToken txnId:(NSString*)txnId { AuthenticationViewController *authVC = self.masterTabBarController.authViewController; - + if (!authVC) { MXLogDebug(@"[AppDelegate] Fail to continue SSO login"); return NO; } - + return [authVC continueSSOLoginWithToken:loginToken txnId:txnId]; } @@ -4532,9 +4532,9 @@ -(void)openSpaceWithId:(NSString *)spaceId MXWeakify(self); __block __weak id observer = [[NSNotificationCenter defaultCenter] addObserverForName:MXSpaceService.didBuildSpaceGraph object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { MXStrongifyAndReturnIfNil(self); - + [[NSNotificationCenter defaultCenter] removeObserver:observer]; - + if ([session.spaceService getSpaceWithId:spaceId]) { [self restoreInitialDisplay:^{ [self.delegate legacyAppDelegate:self didNavigateToSpaceWithId:spaceId]; diff --git a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift index 2ed3b8e604..bae7d1eadf 100644 --- a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift +++ b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift @@ -21,62 +21,62 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKVi @objc let homeViewController: HomeViewController private var bannerContainerView: UIView! private var stackView: UIStackView! - + init(viewController: HomeViewController) { self.homeViewController = viewController - + super.init(nibName: nil, bundle: nil) - + extendedLayoutIncludesOpaqueBars = true - + self.tabBarItem.tag = viewController.tabBarItem.tag self.tabBarItem.image = viewController.tabBarItem.image self.accessibilityLabel = viewController.accessibilityLabel } - + required init?(coder: NSCoder) { fatalError("Not implemented") } - + override func viewDidLoad() { super.viewDidLoad() - + homeViewController.willMove(toParent: self) - + view.backgroundColor = .clear - + stackView = UIStackView() stackView.axis = .vertical stackView.distribution = .fill stackView.alignment = .fill - + view.vc_addSubViewMatchingParent(stackView) addChild(homeViewController) stackView.addArrangedSubview(homeViewController.view) homeViewController.didMove(toParent: self) } - + // MARK: - BannerPresentationProtocol - + func presentBannerView(_ bannerView: UIView, animated: Bool) { bannerView.alpha = 0.0 bannerView.isHidden = true self.stackView.insertArrangedSubview(bannerView, at: 0) self.stackView.layoutIfNeeded() - + UIView.animate(withDuration: (animated ? 0.25 : 0.0)) { bannerView.alpha = 1.0 bannerView.isHidden = false self.stackView.layoutIfNeeded() } } - + func dismissBannerView(animated: Bool) { guard stackView.arrangedSubviews.count > 1, let bannerView = self.stackView.arrangedSubviews.first else { return } - + UIView.animate(withDuration: (animated ? 0.25 : 0.0)) { bannerView.alpha = 0.0 bannerView.isHidden = true @@ -85,7 +85,7 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKVi bannerView.removeFromSuperview() } } - + // MARK: - MXKViewControllerActivityHandling var activityIndicator: UIActivityIndicatorView! { get { @@ -95,11 +95,11 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKVi homeViewController.activityIndicator = newValue } } - + func startActivityIndicator() { homeViewController.startActivityIndicator() } - + func stopActivityIndicator() { homeViewController.stopActivityIndicator() } From 2fff8d9297221494d6c95d76606061199d0eae82 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 24 Jan 2022 18:39:42 +0000 Subject: [PATCH 14/16] Fix bad formatting from merge moar. --- Riot/Modules/Application/LegacyAppDelegate.m | 2 +- .../HomeViewControllerWithBannerWrapperViewController.swift | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 37ca135d3d..fc7e503a2d 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1654,7 +1654,7 @@ - (void)peekInRoomWithNavigationParameters:(RoomPreviewNavigationParameters*)pre if ([self.masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) { UIViewController *homeViewController = (UIViewController*)self.masterTabBarController.selectedViewController; - + // Note: the activity indicator will not disappear if the session is not ready [homeViewController stopActivityIndicator]; } diff --git a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift index bae7d1eadf..764dc2d599 100644 --- a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift +++ b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift @@ -17,7 +17,7 @@ import Foundation class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKViewControllerActivityHandling, BannerPresentationProtocol { - + @objc let homeViewController: HomeViewController private var bannerContainerView: UIView! private var stackView: UIStackView! @@ -95,11 +95,11 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKVi homeViewController.activityIndicator = newValue } } - + func startActivityIndicator() { homeViewController.startActivityIndicator() } - + func stopActivityIndicator() { homeViewController.stopActivityIndicator() } From 456e269534cfe0d5c20dbacffda3f59ec07d75d9 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 28 Jan 2022 11:47:52 +0000 Subject: [PATCH 15/16] Add nullability checks and remove comment --- .../MatrixKit/Models/Account/MXKAccount.m | 5 --- .../MatrixKit/Models/Account/MXKAccountData.h | 37 ++++--------------- 2 files changed, 7 insertions(+), 35 deletions(-) diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index ad506cc3dd..cd5f5d784b 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -262,11 +262,6 @@ - (NSString*)fullDisplayName } } -//- (NSArray *)threePIDs -//{ -// return _threePIDs; -//} - - (NSArray *)linkedEmails { NSMutableArray *linkedEmails = [NSMutableArray array]; diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h index b5cc5512b1..3098f66d11 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountData.h @@ -37,64 +37,41 @@ /** The account's credentials: homeserver, access token, user id. */ -@property (nonatomic, readonly) MXCredentials *mxCredentials; +@property (nonatomic, readonly, nonnull) MXCredentials *mxCredentials; /** The identity server URL. */ -@property (nonatomic) NSString *identityServerURL; +@property (nonatomic, nonnull) NSString *identityServerURL; /** The antivirus server URL, if any (nil by default). Set a non-null url to configure the antivirus scanner use. */ -@property (nonatomic) NSString *antivirusServerURL; +@property (nonatomic, nullable) NSString *antivirusServerURL; /** The Push Gateway URL used to send event notifications to (nil by default). This URL should be over HTTPS and never over HTTP. */ -@property (nonatomic) NSString *pushGatewayURL; +@property (nonatomic, nullable) NSString *pushGatewayURL; /** The 3PIDs linked to this account. [self load3PIDs] must be called to update the property. */ -@property (nonatomic, readonly) NSArray *threePIDs; - -/** - The email addresses linked to this account. - This is a subset of self.threePIDs. - */ -@property (nonatomic, readonly) NSArray *linkedEmails; - -/** - The phone numbers linked to this account. - This is a subset of self.threePIDs. - */ -@property (nonatomic, readonly) NSArray *linkedPhoneNumbers; +@property (nonatomic, readonly, nullable) NSArray *threePIDs; /** The account user's device. [self loadDeviceInformation] must be called to update the property. */ -@property (nonatomic, readonly) MXDevice *device; - -/** - The account user's tint color: a unique color fixed by the user id. This tint color may be used to highlight - rooms which belong to this account's user. - */ -@property (nonatomic, readonly) UIColor *userTintColor; - -/** - The Apple Push Notification Service activity for this account. YES when APNS is turned on (locally available and synced with server). - */ -@property (nonatomic, readonly) BOOL pushNotificationServiceIsActive; +@property (nonatomic, readonly, nullable) MXDevice *device; /** Transient information storage. */ -@property (nonatomic, strong, readonly) NSMutableDictionary> *others; +@property (nonatomic, strong, readonly, nonnull) NSMutableDictionary> *others; /** Flag to indicate that an APNS pusher has been set on the homeserver for this device. From d8c3992432405cb4577bbadeea272c560360a0e6 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 31 Jan 2022 00:28:31 +0000 Subject: [PATCH 16/16] Disable refresh tokens and revert pod and lockfile --- Config/BuildSettings.swift | 2 +- Podfile | 15 +++++++-------- Podfile.lock | 15 +++++---------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index cac5370578..f4817a070a 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -352,7 +352,7 @@ final class BuildSettings: NSObject { static let authScreenShowSocialLoginSection = true // MARK: - Authentication Options - static let authEnableRefreshTokens = true + static let authEnableRefreshTokens = false // MARK: - Unified Search static let unifiedSearchScreenShowPublicDirectory = true diff --git a/Podfile b/Podfile index a9c67f1e53..2d8c4ed5e3 100644 --- a/Podfile +++ b/Podfile @@ -13,10 +13,9 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -# $matrixSDKVersion = '= 0.20.16' +$matrixSDKVersion = '= 0.20.16' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} -$matrixSDKVersion = { :branch => 'langleyd/5292_refresh_tokens'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } ######################################## @@ -50,8 +49,8 @@ end ######################################## def import_MatrixKit_pods - pod 'HPGrowingTextView', '~> 1.1' - pod 'libPhoneNumber-iOS', '~> 0.9.13' + pod 'HPGrowingTextView', '~> 1.1' + pod 'libPhoneNumber-iOS', '~> 0.9.13' pod 'DTCoreText', '~> 1.6.25' #pod 'DTCoreText/Extension', '~> 1.6.25' pod 'Down', '~> 0.11.0' @@ -97,7 +96,7 @@ abstract_target 'RiotPods' do pod 'SideMenu', '~> 6.5' pod 'DSWaveformImage', '~> 6.1.1' pod 'ffmpeg-kit-ios-audio', '4.5.1' - + pod 'FLEX', '~> 4.5.0', :configurations => ['Debug'] target 'RiotTests' do @@ -112,11 +111,11 @@ abstract_target 'RiotPods' do target "RiotSwiftUI" do import_SwiftUI_pods - end + end target "RiotSwiftUITests" do import_SwiftUI_pods - end + end target "SiriIntents" do import_MatrixSDK @@ -151,4 +150,4 @@ post_install do |installer| config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' end end -end +end \ No newline at end of file diff --git a/Podfile.lock b/Podfile.lock index 65885ca0ee..8d3206d351 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -116,8 +116,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `langleyd/5292_refresh_tokens`) - - MatrixSDK/JingleCallStack (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `langleyd/5292_refresh_tokens`) + - MatrixSDK (= 0.20.16) + - MatrixSDK/JingleCallStack (= 0.20.16) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -157,6 +157,7 @@ SPEC REPOS: - libPhoneNumber-iOS - LoggerAPI - Logging + - MatrixSDK - OLMKit - PostHog - ReadMoreTextView @@ -176,17 +177,11 @@ EXTERNAL SOURCES: AnalyticsEvents: :branch: release/swift :git: https://github.com/matrix-org/matrix-analytics-events.git - MatrixSDK: - :branch: langleyd/5292_refresh_tokens - :git: https://github.com/matrix-org/matrix-ios-sdk.git CHECKOUT OPTIONS: AnalyticsEvents: :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c :git: https://github.com/matrix-org/matrix-analytics-events.git - MatrixSDK: - :commit: b9cbc3bd378c55c5317725e3dbebf18a1cd5d0fc - :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce @@ -214,7 +209,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: fbef8eb1793f8c2b5233bee493b6b1bbe93ae3f7 + MatrixSDK: af6a70532bb43af59f43a1f4dae512a26afeab0b OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -230,6 +225,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: c5f0584d20a092fba207f356f7487bdbea129ab8 +PODFILE CHECKSUM: c9a50c445e32b40b22fadd0f54b376f1bd624ebb COCOAPODS: 1.11.2