mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 17:12:45 +02:00
Merge MatrixKit develop with commit hash: b85b736313bec0592bd1cabc68035d97f5331137
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
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 <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
@class MXKAccount;
|
||||
|
||||
/**
|
||||
Posted when account user information (display name, picture, presence) has been updated.
|
||||
The notification object is the matrix user id of the account.
|
||||
*/
|
||||
extern NSString *const kMXKAccountUserInfoDidChangeNotification;
|
||||
|
||||
/**
|
||||
Posted when the activity of the Apple Push Notification Service has been changed.
|
||||
The notification object is the matrix user id of the account.
|
||||
*/
|
||||
extern NSString *const kMXKAccountAPNSActivityDidChangeNotification;
|
||||
|
||||
/**
|
||||
Posted when the activity of the Push notification based on PushKit has been changed.
|
||||
The notification object is the matrix user id of the account.
|
||||
*/
|
||||
extern NSString *const kMXKAccountPushKitActivityDidChangeNotification;
|
||||
|
||||
/**
|
||||
MXKAccount error domain
|
||||
*/
|
||||
extern NSString *const kMXKAccountErrorDomain;
|
||||
|
||||
/**
|
||||
Block called when a certificate change is observed during authentication challenge from a server.
|
||||
|
||||
@param mxAccount the account concerned by this certificate change.
|
||||
@param certificate the server certificate to evaluate.
|
||||
@return YES to accept/trust this certificate, NO to cancel/ignore it.
|
||||
*/
|
||||
typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *certificate);
|
||||
|
||||
/**
|
||||
`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 <NSCoding>
|
||||
|
||||
/**
|
||||
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 matrix REST client used to make matrix API requests.
|
||||
*/
|
||||
@property (nonatomic, readonly) MXRestClient *mxRestClient;
|
||||
|
||||
/**
|
||||
The matrix session opened with the account (nil by default).
|
||||
*/
|
||||
@property (nonatomic, readonly) MXSession *mxSession;
|
||||
|
||||
/**
|
||||
The account user's display name (nil by default, available if matrix session `mxSession` is opened).
|
||||
The notification `kMXKAccountUserInfoDidChangeNotification` is posted in case of change of this property.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *userDisplayName;
|
||||
|
||||
/**
|
||||
The account user's avatar url (nil by default, available if matrix session `mxSession` is opened).
|
||||
The notification `kMXKAccountUserInfoDidChangeNotification` is posted in case of change of this property.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *userAvatarUrl;
|
||||
|
||||
/**
|
||||
The account display name based on user id and user displayname (if any).
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *fullDisplayName;
|
||||
|
||||
/**
|
||||
The 3PIDs linked to this account.
|
||||
[self load3PIDs] must be called to update the property.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<MXThirdPartyIdentifier *> *threePIDs;
|
||||
|
||||
/**
|
||||
The email addresses linked to this account.
|
||||
This is a subset of self.threePIDs.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *linkedEmails;
|
||||
|
||||
/**
|
||||
The phone numbers linked to this account.
|
||||
This is a subset of self.threePIDs.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *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.
|
||||
*/
|
||||
@property (nonatomic, readonly) MXPresence userPresence;
|
||||
|
||||
/**
|
||||
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<NSString *, id<NSCoding>> *others;
|
||||
|
||||
/**
|
||||
Enable Push notification based on Apple Push Notification Service (APNS).
|
||||
|
||||
This method creates or removes a pusher on the homeserver.
|
||||
|
||||
@param enable YES to enable it.
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)enablePushNotifications:(BOOL)enable
|
||||
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).
|
||||
*/
|
||||
@property (nonatomic, readonly) BOOL isPushKitNotificationActive;
|
||||
|
||||
/**
|
||||
Enable Push notification based on PushKit.
|
||||
|
||||
This method creates or removes a pusher on the homeserver.
|
||||
|
||||
@param enable YES to enable it.
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)enablePushKitNotifications:(BOOL)enable
|
||||
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.
|
||||
|
||||
The presence event must not be sent if the application is launched by a push notification.
|
||||
*/
|
||||
@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).
|
||||
|
||||
@param onCertificateChangeBlock the block that will be used to handle certificate change.
|
||||
*/
|
||||
+ (void)registerOnCertificateChangeBlock:(MXKAccountOnCertificateChange)onCertificateChangeBlock;
|
||||
|
||||
/**
|
||||
Get the color code related to a specific presence.
|
||||
|
||||
@param presence a user presence
|
||||
@return color defined for the provided presence (nil if no color is defined).
|
||||
*/
|
||||
+ (UIColor*)presenceColor:(MXPresence)presence;
|
||||
|
||||
/**
|
||||
Init `MXKAccount` instance with credentials. No matrix session is opened by default.
|
||||
|
||||
@param credentials user's credentials
|
||||
*/
|
||||
- (instancetype)initWithCredentials:(MXCredentials*)credentials;
|
||||
|
||||
/**
|
||||
Create a matrix session based on the provided store.
|
||||
When store data is ready, the live stream is automatically launched by synchronising the session with the server.
|
||||
|
||||
In case of failure during server sync, the method is reiterated until the data is up-to-date with the server.
|
||||
This loop is stopped if you call [MXCAccount closeSession:], it is suspended if you call [MXCAccount pauseInBackgroundTask].
|
||||
|
||||
@param store the store to use for the session.
|
||||
*/
|
||||
-(void)openSessionWithStore:(id<MXStore>)store;
|
||||
|
||||
/**
|
||||
Close the matrix session.
|
||||
|
||||
@param clearStore set YES to delete all store data.
|
||||
*/
|
||||
- (void)closeSession:(BOOL)clearStore;
|
||||
|
||||
/**
|
||||
Invalidate the access token, close the matrix session and delete all store data.
|
||||
|
||||
@note This method is equivalent to `logoutSendingServerRequest:completion:` with `sendLogoutServerRequest` parameter to YES
|
||||
|
||||
@param completion the block to execute at the end of the operation (independently if it succeeded or not).
|
||||
*/
|
||||
- (void)logout:(void (^)(void))completion;
|
||||
|
||||
/**
|
||||
Invalidate the access token, close the matrix session and delete all store data.
|
||||
|
||||
@param sendLogoutServerRequest indicate to send logout request to homeserver.
|
||||
@param completion the block to execute at the end of the operation (independently if it succeeded or not).
|
||||
*/
|
||||
- (void)logoutSendingServerRequest:(BOOL)sendLogoutServerRequest
|
||||
completion:(void (^)(void))completion;
|
||||
|
||||
|
||||
#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.
|
||||
|
||||
The matix session is stopped but the data is kept.
|
||||
*/
|
||||
- (void)softLogout;
|
||||
|
||||
/**
|
||||
Hydrate the account using the credentials provided.
|
||||
|
||||
@param credentials the new credentials.
|
||||
*/
|
||||
- (void)hydrateWithCredentials:(MXCredentials*)credentials;
|
||||
|
||||
/**
|
||||
Pause the current matrix session.
|
||||
|
||||
@warning: This matrix session is paused without using background task if no background mode handler
|
||||
is set in the MXSDKOptions sharedInstance (see `backgroundModeHandler`).
|
||||
*/
|
||||
- (void)pauseInBackgroundTask;
|
||||
|
||||
/**
|
||||
Perform a background sync by keeping the user offline.
|
||||
|
||||
@warning: This operation failed when no background mode handler is set in the
|
||||
MXSDKOptions sharedInstance (see `backgroundModeHandler`).
|
||||
|
||||
@param timeout the timeout in milliseconds.
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)backgroundSync:(unsigned int)timeout success:(void (^)(void))success failure:(void (^)(NSError *))failure;
|
||||
|
||||
/**
|
||||
Resume the current matrix session.
|
||||
*/
|
||||
- (void)resume;
|
||||
|
||||
/**
|
||||
Close the potential matrix session and open a new one if the account is not disabled.
|
||||
|
||||
@param clearCache set YES to delete all store data.
|
||||
*/
|
||||
- (void)reload:(BOOL)clearCache;
|
||||
|
||||
/**
|
||||
Set the display name of the account user.
|
||||
|
||||
@param displayname the new display name.
|
||||
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)setUserDisplayName:(NSString*)displayname success:(void (^)(void))success failure:(void (^)(NSError *error))failure;
|
||||
|
||||
/**
|
||||
Set the avatar url of the account user.
|
||||
|
||||
@param avatarUrl the new avatar url.
|
||||
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)setUserAvatarUrl:(NSString*)avatarUrl success:(void (^)(void))success failure:(void (^)(NSError *error))failure;
|
||||
|
||||
/**
|
||||
Update the account password.
|
||||
|
||||
@param oldPassword the old password.
|
||||
@param newPassword the new password.
|
||||
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)changePassword:(NSString*)oldPassword with:(NSString*)newPassword success:(void (^)(void))success failure:(void (^)(NSError *error))failure;
|
||||
|
||||
/**
|
||||
Load the 3PIDs linked to this account.
|
||||
This method must be called to refresh self.threePIDs and self.linkedEmails.
|
||||
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)load3PIDs:(void (^)(void))success failure:(void (^)(NSError *error))failure;
|
||||
|
||||
/**
|
||||
Load the current device information for this account.
|
||||
This method must be called to refresh self.device.
|
||||
|
||||
@param success A block object called when the operation succeeds.
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)loadDeviceInformation:(void (^)(void))success failure:(void (^)(NSError *error))failure;
|
||||
|
||||
#pragma mark - Push notification listeners
|
||||
/**
|
||||
Register a listener to push notifications for the account's session.
|
||||
|
||||
The listener will be called when a push rule matches a live event.
|
||||
Note: only one listener is supported. Potential existing listener is removed.
|
||||
|
||||
You may use `[MXCAccount updateNotificationListenerForRoomId:]` to disable/enable all notifications from a specific room.
|
||||
|
||||
@param onNotification the block that will be called once a live event matches a push rule.
|
||||
*/
|
||||
- (void)listenToNotifications:(MXOnNotification)onNotification;
|
||||
|
||||
/**
|
||||
Unregister the listener.
|
||||
*/
|
||||
- (void)removeNotificationListener;
|
||||
|
||||
/**
|
||||
Update the listener to ignore or restore notifications from a specific room.
|
||||
|
||||
@param roomID the id of the concerned room.
|
||||
@param isIgnored YES to disable notifications from the specified room. NO to restore them.
|
||||
*/
|
||||
- (void)updateNotificationListenerForRoomId:(NSString*)roomID ignore:(BOOL)isIgnored;
|
||||
|
||||
#pragma mark - Crypto
|
||||
/**
|
||||
Delete the device id.
|
||||
|
||||
Call this method when the current device id cannot be used anymore.
|
||||
*/
|
||||
- (void)resetDeviceId;
|
||||
|
||||
#pragma mark - Sync filter
|
||||
/**
|
||||
Check if the homeserver supports room members lazy loading.
|
||||
@param completion the check result.
|
||||
*/
|
||||
- (void)supportLazyLoadOfRoomMembers:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion;
|
||||
|
||||
/**
|
||||
Call this method at an appropriate time to attempt dehydrating to a new backup device
|
||||
*/
|
||||
- (void)attemptDeviceDehydrationWithKeyData:(NSData *)keyData
|
||||
success:(void (^)(void))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
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 <Foundation/Foundation.h>
|
||||
|
||||
#import "MXKAccount.h"
|
||||
|
||||
/**
|
||||
Posted when the user logged in with a matrix account.
|
||||
The notification object is the new added account.
|
||||
*/
|
||||
extern NSString *const kMXKAccountManagerDidAddAccountNotification;
|
||||
|
||||
/**
|
||||
Posted when an existing account is logged out.
|
||||
The notification object is the removed account.
|
||||
*/
|
||||
extern NSString *const kMXKAccountManagerDidRemoveAccountNotification;
|
||||
|
||||
/**
|
||||
Posted when an existing account is soft logged out.
|
||||
The notification object is the account.
|
||||
*/
|
||||
extern NSString *const kMXKAccountManagerDidSoftlogoutAccountNotification;
|
||||
|
||||
/**
|
||||
Used to identify the type of data when requesting MXKeyProvider
|
||||
*/
|
||||
extern NSString *const MXKAccountManagerDataType;
|
||||
|
||||
/**
|
||||
`MXKAccountManager` manages a pool of `MXKAccount` instances.
|
||||
*/
|
||||
@interface MXKAccountManager : NSObject
|
||||
|
||||
/**
|
||||
The class of store used to open matrix session for the accounts. This class must be conformed to MXStore protocol.
|
||||
By default this class is MXFileStore.
|
||||
*/
|
||||
@property (nonatomic) Class storeClass;
|
||||
|
||||
/**
|
||||
List of all available accounts (enabled and disabled).
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<MXKAccount *> *accounts;
|
||||
|
||||
/**
|
||||
List of active accounts (only enabled accounts)
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<MXKAccount *> *activeAccounts;
|
||||
|
||||
/**
|
||||
The device token used for Apple Push Notification Service registration.
|
||||
*/
|
||||
@property (nonatomic, copy) NSData *apnsDeviceToken;
|
||||
|
||||
/**
|
||||
The APNS status: YES when app is registered for remote notif, and device token is known.
|
||||
*/
|
||||
@property (nonatomic) BOOL isAPNSAvailable;
|
||||
|
||||
/**
|
||||
The device token used for Push notifications registration (PushKit support).
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSData *pushDeviceToken;
|
||||
|
||||
/**
|
||||
The current options of the Push notifications based on PushKit.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSDictionary *pushOptions;
|
||||
|
||||
/**
|
||||
Set the push token and the potential push options.
|
||||
For example, for clients that want to go & fetch the body of the event themselves anyway,
|
||||
the key-value `format: event_id_only` may be used in `pushOptions` dictionary to tell the
|
||||
HTTP pusher to send just the event_id of the event it's notifying about, the room id and
|
||||
the notification counts.
|
||||
|
||||
@param pushDeviceToken the push token.
|
||||
@param pushOptions dictionary of the push options (may be nil).
|
||||
*/
|
||||
- (void)setPushDeviceToken:(NSData *)pushDeviceToken withPushOptions:(NSDictionary *)pushOptions;
|
||||
|
||||
/**
|
||||
The PushKit status: YES when app is registered for push notif, and push token is known.
|
||||
*/
|
||||
@property (nonatomic) BOOL isPushAvailable;
|
||||
|
||||
@property (nonatomic, readonly) MXDehydrationService *dehydrationService;
|
||||
|
||||
/**
|
||||
Retrieve the MXKAccounts manager.
|
||||
|
||||
@return the MXKAccounts manager.
|
||||
*/
|
||||
+ (MXKAccountManager *)sharedManager;
|
||||
|
||||
/**
|
||||
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.
|
||||
The developper must set 'storeClass' before the first call of this method
|
||||
if the default class is not suitable.
|
||||
*/
|
||||
- (void)prepareSessionForActiveAccounts;
|
||||
|
||||
/**
|
||||
Save a snapshot of the current accounts.
|
||||
*/
|
||||
- (void)saveAccounts;
|
||||
|
||||
/**
|
||||
Add an account and save the new account list. Optionally a matrix session may be opened for the provided account.
|
||||
|
||||
@param account a matrix account.
|
||||
@param openSession YES to open a matrix session (this value is ignored if the account is disabled).
|
||||
*/
|
||||
- (void)addAccount:(MXKAccount *)account andOpenSession:(BOOL)openSession;
|
||||
|
||||
/**
|
||||
Remove the provided account and save the new account list. This method is used in case of logout.
|
||||
|
||||
@note equivalent to `removeAccount:sendLogoutRequest:completion:` method with `sendLogoutRequest` parameter to YES
|
||||
|
||||
@param account a matrix account.
|
||||
@param completion the block to execute at the end of the operation.
|
||||
*/
|
||||
- (void)removeAccount:(MXKAccount *)account completion:(void (^)(void))completion;
|
||||
|
||||
|
||||
/**
|
||||
Remove the provided account and save the new account list. This method is used in case of logout or account deactivation.
|
||||
|
||||
@param account a matrix account.
|
||||
@param sendLogoutRequest Indicate whether send logout request to homeserver.
|
||||
@param completion the block to execute at the end of the operation.
|
||||
*/
|
||||
- (void)removeAccount:(MXKAccount*)account
|
||||
sendLogoutRequest:(BOOL)sendLogoutRequest
|
||||
completion:(void (^)(void))completion;
|
||||
|
||||
/**
|
||||
Log out and remove all the existing accounts
|
||||
|
||||
@param completion the block to execute at the end of the operation.
|
||||
*/
|
||||
- (void)logoutWithCompletion:(void (^)(void))completion;
|
||||
|
||||
/**
|
||||
Soft logout an account.
|
||||
|
||||
@param account a matrix account.
|
||||
*/
|
||||
- (void)softLogout:(MXKAccount*)account;
|
||||
|
||||
/**
|
||||
Hydrate an existing account by using the credentials provided.
|
||||
|
||||
This updates account credentials and restarts the account session
|
||||
|
||||
If the credentials belong to a different user from the account already stored,
|
||||
the old account will be cleared automatically.
|
||||
|
||||
@param account a matrix account.
|
||||
@param credentials the new credentials.
|
||||
*/
|
||||
- (void)hydrateAccount:(MXKAccount*)account withCredentials:(MXCredentials*)credentials;
|
||||
|
||||
/**
|
||||
Retrieve the account for a user id.
|
||||
|
||||
@param userId the user id.
|
||||
@return the user's account (nil if no account exist).
|
||||
*/
|
||||
- (MXKAccount *)accountForUserId:(NSString *)userId;
|
||||
|
||||
/**
|
||||
Retrieve an account that knows the room with the passed id or alias.
|
||||
|
||||
Note: The method is not accurate as it returns the first account that matches.
|
||||
|
||||
@param roomIdOrAlias the room id or alias.
|
||||
@return the user's account. Nil if no account matches.
|
||||
*/
|
||||
- (MXKAccount *)accountKnowingRoomWithRoomIdOrAlias:(NSString *)roomIdOrAlias;
|
||||
|
||||
/**
|
||||
Retrieve an account that knows the user with the passed id.
|
||||
|
||||
Note: The method is not accurate as it returns the first account that matches.
|
||||
|
||||
@param userId the user id.
|
||||
@return the user's account. Nil if no account matches.
|
||||
*/
|
||||
- (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;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
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 "MXKAccountManager.h"
|
||||
#import "MXKAppSettings.h"
|
||||
|
||||
#import "MXKTools.h"
|
||||
|
||||
static NSString *const kMXKAccountsKeyOld = @"accounts";
|
||||
static NSString *const kMXKAccountsKey = @"accountsV2";
|
||||
|
||||
NSString *const kMXKAccountManagerDidAddAccountNotification = @"kMXKAccountManagerDidAddAccountNotification";
|
||||
NSString *const kMXKAccountManagerDidRemoveAccountNotification = @"kMXKAccountManagerDidRemoveAccountNotification";
|
||||
NSString *const kMXKAccountManagerDidSoftlogoutAccountNotification = @"kMXKAccountManagerDidSoftlogoutAccountNotification";
|
||||
NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDataType";
|
||||
|
||||
@interface MXKAccountManager()
|
||||
{
|
||||
/**
|
||||
The list of all accounts (enabled and disabled). Each value is a `MXKAccount` instance.
|
||||
*/
|
||||
NSMutableArray<MXKAccount *> *mxAccounts;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MXKAccountManager
|
||||
|
||||
+ (MXKAccountManager *)sharedManager
|
||||
{
|
||||
static MXKAccountManager *sharedAccountManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedAccountManager = [[super allocWithZone:NULL] init];
|
||||
});
|
||||
|
||||
return sharedAccountManager;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
_storeClass = [MXFileStore class];
|
||||
_dehydrationService = [MXDehydrationService new];
|
||||
|
||||
// Migrate old account file to new format
|
||||
[self migrateAccounts];
|
||||
|
||||
// Load existing accounts from local storage
|
||||
[self loadAccounts];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
mxAccounts = nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)prepareSessionForActiveAccounts
|
||||
{
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
// Check whether the account is enabled. Open a new matrix session if none.
|
||||
if (!account.isDisabled && !account.isSoftLogout && !account.mxSession)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] openSession for %@ account", account.mxCredentials.userId);
|
||||
|
||||
id<MXStore> store = [[_storeClass alloc] init];
|
||||
[account openSessionWithStore:store];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)saveAccounts
|
||||
{
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] saveAccounts...");
|
||||
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
|
||||
[encoder encodeObject:mxAccounts forKey:@"mxAccounts"];
|
||||
|
||||
[encoder finishEncoding];
|
||||
|
||||
[data setData:[self encryptData:data]];
|
||||
|
||||
BOOL result = [data writeToFile:[self accountFile] atomically:YES];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] saveAccounts. Done (result: %@) in %.0fms", @(result), [[NSDate date] timeIntervalSinceDate:startDate] * 1000);
|
||||
}
|
||||
|
||||
- (void)addAccount:(MXKAccount *)account andOpenSession:(BOOL)openSession
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] login (%@)", account.mxCredentials.userId);
|
||||
|
||||
[mxAccounts addObject:account];
|
||||
[self saveAccounts];
|
||||
|
||||
// Check conditions to open a matrix session
|
||||
if (openSession && !account.disabled)
|
||||
{
|
||||
// Open a new matrix session by default
|
||||
MXLogDebug(@"[MXKAccountManager] openSession for %@ account (device %@)", account.mxCredentials.userId, account.mxCredentials.deviceId);
|
||||
id<MXStore> store = [[_storeClass alloc] init];
|
||||
[account openSessionWithStore:store];
|
||||
}
|
||||
|
||||
// Post notification
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountManagerDidAddAccountNotification object:account userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)removeAccount:(MXKAccount*)theAccount completion:(void (^)(void))completion
|
||||
{
|
||||
[self removeAccount:theAccount sendLogoutRequest:YES completion:completion];
|
||||
}
|
||||
|
||||
- (void)removeAccount:(MXKAccount*)theAccount
|
||||
sendLogoutRequest:(BOOL)sendLogoutRequest
|
||||
completion:(void (^)(void))completion
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] logout (%@), send logout request to homeserver: %d", theAccount.mxCredentials.userId, sendLogoutRequest);
|
||||
|
||||
// Close session and clear associated store.
|
||||
[theAccount logoutSendingServerRequest:sendLogoutRequest completion:^{
|
||||
|
||||
// Retrieve the corresponding account in the internal array
|
||||
MXKAccount* removedAccount = nil;
|
||||
|
||||
for (MXKAccount *account in self->mxAccounts)
|
||||
{
|
||||
if ([account.mxCredentials.userId isEqualToString:theAccount.mxCredentials.userId])
|
||||
{
|
||||
removedAccount = account;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedAccount)
|
||||
{
|
||||
[self->mxAccounts removeObject:removedAccount];
|
||||
|
||||
[self saveAccounts];
|
||||
|
||||
// Post notification
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountManagerDidRemoveAccountNotification object:removedAccount userInfo:nil];
|
||||
}
|
||||
|
||||
if (completion)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)logoutWithCompletion:(void (^)(void))completion
|
||||
{
|
||||
// Logout one by one the existing accounts
|
||||
if (mxAccounts.count)
|
||||
{
|
||||
[self removeAccount:mxAccounts.lastObject completion:^{
|
||||
|
||||
// loop: logout the next existing account (if any)
|
||||
[self logoutWithCompletion:completion];
|
||||
|
||||
}];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NSUserDefaults *sharedUserDefaults = [MXKAppSettings standardAppSettings].sharedUserDefaults;
|
||||
|
||||
// Remove APNS device token
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"apnsDeviceToken"];
|
||||
|
||||
// Remove Push device token
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushDeviceToken"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushOptions"];
|
||||
|
||||
// Be sure that no account survive in local storage
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kMXKAccountsKey];
|
||||
[sharedUserDefaults removeObjectForKey:kMXKAccountsKey];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self accountFile] error:nil];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)softLogout:(MXKAccount*)account
|
||||
{
|
||||
[account softLogout];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountManagerDidSoftlogoutAccountNotification
|
||||
object:account
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)hydrateAccount:(MXKAccount*)account withCredentials:(MXCredentials*)credentials
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] hydrateAccount: %@", account.mxCredentials.userId);
|
||||
|
||||
if ([account.mxCredentials.userId isEqualToString:credentials.userId])
|
||||
{
|
||||
// Restart the account
|
||||
[account hydrateWithCredentials:credentials];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] hydrateAccount: Open session");
|
||||
|
||||
id<MXStore> store = [[_storeClass alloc] init];
|
||||
[account openSessionWithStore:store];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountManagerDidAddAccountNotification
|
||||
object:account
|
||||
userInfo:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] hydrateAccount: Credentials given for another account: %@", credentials.userId);
|
||||
|
||||
// Logout the old account and create a new one with the new credentials
|
||||
[self removeAccount:account sendLogoutRequest:YES completion:nil];
|
||||
|
||||
MXKAccount *newAccount = [[MXKAccount alloc] initWithCredentials:credentials];
|
||||
[self addAccount:newAccount andOpenSession:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (MXKAccount *)accountForUserId:(NSString *)userId
|
||||
{
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
if ([account.mxCredentials.userId isEqualToString:userId])
|
||||
{
|
||||
return account;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (MXKAccount *)accountKnowingRoomWithRoomIdOrAlias:(NSString *)roomIdOrAlias
|
||||
{
|
||||
MXKAccount *theAccount = nil;
|
||||
|
||||
NSArray *activeAccounts = self.activeAccounts;
|
||||
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
if ([roomIdOrAlias hasPrefix:@"#"])
|
||||
{
|
||||
if ([account.mxSession roomWithAlias:roomIdOrAlias])
|
||||
{
|
||||
theAccount = account;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([account.mxSession roomWithRoomId:roomIdOrAlias])
|
||||
{
|
||||
theAccount = account;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return theAccount;
|
||||
}
|
||||
|
||||
- (MXKAccount *)accountKnowingUserWithUserId:(NSString *)userId
|
||||
{
|
||||
MXKAccount *theAccount = nil;
|
||||
|
||||
NSArray *activeAccounts = self.activeAccounts;
|
||||
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
if ([account.mxSession userWithUserId:userId])
|
||||
{
|
||||
theAccount = account;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return theAccount;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)setStoreClass:(Class)storeClass
|
||||
{
|
||||
// Sanity check
|
||||
NSAssert([storeClass conformsToProtocol:@protocol(MXStore)], @"MXKAccountManager only manages store class that conforms to MXStore protocol");
|
||||
|
||||
_storeClass = storeClass;
|
||||
}
|
||||
|
||||
- (NSArray<MXKAccount *> *)accounts
|
||||
{
|
||||
return [mxAccounts copy];
|
||||
}
|
||||
|
||||
- (NSArray<MXKAccount *> *)activeAccounts
|
||||
{
|
||||
NSMutableArray *activeAccounts = [NSMutableArray arrayWithCapacity:mxAccounts.count];
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
if (!account.disabled && !account.isSoftLogout)
|
||||
{
|
||||
[activeAccounts addObject:account];
|
||||
}
|
||||
}
|
||||
return activeAccounts;
|
||||
}
|
||||
|
||||
- (NSData *)apnsDeviceToken
|
||||
{
|
||||
NSData *token = [[NSUserDefaults standardUserDefaults] objectForKey:@"apnsDeviceToken"];
|
||||
if (!token.length)
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"apnsDeviceToken"];
|
||||
token = nil;
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] apnsDeviceToken: %@", [MXKTools logForPushToken:token]);
|
||||
return token;
|
||||
}
|
||||
|
||||
- (void)setApnsDeviceToken:(NSData *)apnsDeviceToken
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: %@", [MXKTools logForPushToken:apnsDeviceToken]);
|
||||
|
||||
NSData *oldToken = self.apnsDeviceToken;
|
||||
if (!apnsDeviceToken.length)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: reset APNS device token");
|
||||
|
||||
if (oldToken)
|
||||
{
|
||||
// turn off the Apns flag for all accounts if any
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
[account enablePushNotifications:NO success:nil failure:nil];
|
||||
}
|
||||
}
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"apnsDeviceToken"];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSArray *activeAccounts = self.activeAccounts;
|
||||
|
||||
if (!oldToken)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: set APNS device token");
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:apnsDeviceToken forKey:@"apnsDeviceToken"];
|
||||
|
||||
// turn on the Apns flag for all accounts, when the Apns registration succeeds for the first time
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
[account enablePushNotifications:YES success:nil failure:nil];
|
||||
}
|
||||
}
|
||||
else if (![oldToken isEqualToData:apnsDeviceToken])
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: update APNS device token");
|
||||
|
||||
NSMutableArray<MXKAccount*> *accountsWithAPNSPusher = [NSMutableArray new];
|
||||
|
||||
// Delete the pushers related to the old token
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
if (account.hasPusherForPushNotifications)
|
||||
{
|
||||
[accountsWithAPNSPusher addObject:account];
|
||||
}
|
||||
|
||||
[account enablePushNotifications:NO success:nil failure:nil];
|
||||
}
|
||||
|
||||
// Update the token
|
||||
[[NSUserDefaults standardUserDefaults] setObject:apnsDeviceToken forKey:@"apnsDeviceToken"];
|
||||
|
||||
// Refresh pushers with the new token.
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
if ([accountsWithAPNSPusher containsObject:account])
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: Resync APNS for %@ account", account.mxCredentials.userId);
|
||||
[account enablePushNotifications:YES success:nil failure:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: hasPusherForPushNotifications = NO for %@ account. Do not enable Push", account.mxCredentials.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setApnsDeviceToken: Same token. Nothing to do.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isAPNSAvailable
|
||||
{
|
||||
// [UIApplication isRegisteredForRemoteNotifications] tells whether your app can receive
|
||||
// remote notifications or not. Receiving remote notifications does not guarantee it will
|
||||
// display them to the user as they may have notifications set to deliver quietly.
|
||||
|
||||
BOOL isRemoteNotificationsAllowed = NO;
|
||||
|
||||
UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)];
|
||||
if (sharedApplication)
|
||||
{
|
||||
isRemoteNotificationsAllowed = [sharedApplication isRegisteredForRemoteNotifications];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] isAPNSAvailable: The user %@ remote notification", (isRemoteNotificationsAllowed ? @"allowed" : @"denied"));
|
||||
}
|
||||
|
||||
BOOL isAPNSAvailable = (isRemoteNotificationsAllowed && self.apnsDeviceToken);
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] isAPNSAvailable: %@", @(isAPNSAvailable));
|
||||
|
||||
return isAPNSAvailable;
|
||||
}
|
||||
|
||||
- (NSData *)pushDeviceToken
|
||||
{
|
||||
NSData *token = [[NSUserDefaults standardUserDefaults] objectForKey:@"pushDeviceToken"];
|
||||
if (!token.length)
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushDeviceToken"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushOptions"];
|
||||
token = nil;
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] pushDeviceToken: %@", [MXKTools logForPushToken:token]);
|
||||
return token;
|
||||
}
|
||||
|
||||
- (NSDictionary *)pushOptions
|
||||
{
|
||||
NSDictionary *pushOptions = [[NSUserDefaults standardUserDefaults] objectForKey:@"pushOptions"];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] pushOptions: %@", pushOptions);
|
||||
return pushOptions;
|
||||
}
|
||||
|
||||
- (void)setPushDeviceToken:(NSData *)pushDeviceToken withPushOptions:(NSDictionary *)pushOptions
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: %@ withPushOptions: %@", [MXKTools logForPushToken:pushDeviceToken], pushOptions);
|
||||
|
||||
NSData *oldToken = self.pushDeviceToken;
|
||||
if (!pushDeviceToken.length)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: Reset Push device token");
|
||||
|
||||
if (oldToken)
|
||||
{
|
||||
// turn off the Push flag for all accounts if any
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
[account enablePushKitNotifications:NO success:^{
|
||||
// make sure pusher really removed before losing token.
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushDeviceToken"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushOptions"];
|
||||
} failure:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSArray *activeAccounts = self.activeAccounts;
|
||||
|
||||
if (!oldToken)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: Set Push device token");
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:pushDeviceToken forKey:@"pushDeviceToken"];
|
||||
if (pushOptions)
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:pushOptions forKey:@"pushOptions"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushOptions"];
|
||||
}
|
||||
|
||||
// turn on the Push flag for all accounts
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
[account enablePushKitNotifications:YES success:nil failure:nil];
|
||||
}
|
||||
}
|
||||
else if (![oldToken isEqualToData:pushDeviceToken])
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: Update Push device token");
|
||||
|
||||
NSMutableArray<MXKAccount*> *accountsWithPushKitPusher = [NSMutableArray new];
|
||||
|
||||
// Delete the pushers related to the old token
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
if (account.hasPusherForPushKitNotifications)
|
||||
{
|
||||
[accountsWithPushKitPusher addObject:account];
|
||||
}
|
||||
|
||||
[account enablePushKitNotifications:NO success:nil failure:nil];
|
||||
}
|
||||
|
||||
// Update the token
|
||||
[[NSUserDefaults standardUserDefaults] setObject:pushDeviceToken forKey:@"pushDeviceToken"];
|
||||
if (pushOptions)
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:pushOptions forKey:@"pushOptions"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"pushOptions"];
|
||||
}
|
||||
|
||||
// Refresh pushers with the new token.
|
||||
for (MXKAccount *account in activeAccounts)
|
||||
{
|
||||
if ([accountsWithPushKitPusher containsObject:account])
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: Resync Push for %@ account", account.mxCredentials.userId);
|
||||
[account enablePushKitNotifications:YES success:nil failure:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: hasPusherForPushKitNotifications = NO for %@ account. Do not enable Push", account.mxCredentials.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager][Push] setPushDeviceToken: Same token. Nothing to do.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isPushAvailable
|
||||
{
|
||||
// [UIApplication isRegisteredForRemoteNotifications] tells whether your app can receive
|
||||
// remote notifications or not. Receiving remote notifications does not guarantee it will
|
||||
// display them to the user as they may have notifications set to deliver quietly.
|
||||
|
||||
BOOL isRemoteNotificationsAllowed = NO;
|
||||
|
||||
UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)];
|
||||
if (sharedApplication)
|
||||
{
|
||||
isRemoteNotificationsAllowed = [sharedApplication isRegisteredForRemoteNotifications];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] isPushAvailable: The user %@ remote notification", (isRemoteNotificationsAllowed ? @"allowed" : @"denied"));
|
||||
}
|
||||
|
||||
BOOL isPushAvailable = (isRemoteNotificationsAllowed && self.pushDeviceToken);
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager][Push] isPushAvailable: %@", @(isPushAvailable));
|
||||
return isPushAvailable;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// Return the path of the file containing stored MXAccounts array
|
||||
- (NSString*)accountFile
|
||||
{
|
||||
NSString *matrixKitCacheFolder = [MXKAppSettings cacheFolder];
|
||||
return [matrixKitCacheFolder stringByAppendingPathComponent:kMXKAccountsKey];
|
||||
}
|
||||
|
||||
- (void)loadAccounts
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] loadAccounts");
|
||||
|
||||
NSString *accountFile = [self accountFile];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:accountFile])
|
||||
{
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
NSError *error = nil;
|
||||
NSData* filecontent = [NSData dataWithContentsOfFile:accountFile options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:&error];
|
||||
|
||||
if (!error)
|
||||
{
|
||||
// Decrypt data if encryption method is provided
|
||||
NSData *unciphered = [self decryptData:filecontent];
|
||||
NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:unciphered];
|
||||
mxAccounts = [decoder decodeObjectForKey:@"mxAccounts"];
|
||||
|
||||
if (!mxAccounts && [[MXKeyProvider sharedInstance] isEncryptionAvailableForDataOfType:MXKAccountManagerDataType])
|
||||
{
|
||||
// This happens if the V2 file has not been encrypted -> read file content then save encrypted accounts
|
||||
MXLogDebug(@"[MXKAccountManager] loadAccounts. Failed to read decrypted data: reading file data without encryption.");
|
||||
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:filecontent];
|
||||
mxAccounts = [decoder decodeObjectForKey:@"mxAccounts"];
|
||||
|
||||
if (mxAccounts)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] loadAccounts. saving encrypted accounts");
|
||||
[self saveAccounts];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] loadAccounts. %tu accounts loaded in %.0fms", mxAccounts.count, [[NSDate date] timeIntervalSinceDate:startDate] * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Migration of accountData from sharedUserDefaults to a file
|
||||
NSUserDefaults *sharedDefaults = [MXKAppSettings standardAppSettings].sharedUserDefaults;
|
||||
|
||||
NSData *accountData = [sharedDefaults objectForKey:kMXKAccountsKey];
|
||||
if (!accountData)
|
||||
{
|
||||
// Migration of accountData from [NSUserDefaults standardUserDefaults], the first location storage
|
||||
accountData = [[NSUserDefaults standardUserDefaults] objectForKey:kMXKAccountsKey];
|
||||
}
|
||||
|
||||
if (accountData)
|
||||
{
|
||||
mxAccounts = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:accountData]];
|
||||
[self saveAccounts];
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] loadAccounts: performed data migration");
|
||||
|
||||
// Now that data has been migrated, erase old location of accountData
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kMXKAccountsKey];
|
||||
|
||||
[sharedDefaults removeObjectForKey:kMXKAccountsKey];
|
||||
}
|
||||
}
|
||||
|
||||
if (!mxAccounts)
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] loadAccounts. No accounts");
|
||||
mxAccounts = [NSMutableArray array];
|
||||
}
|
||||
}
|
||||
|
||||
- (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
|
||||
// is provided.
|
||||
MXKeyData *keyData = [[MXKeyProvider sharedInstance] requestKeyForDataOfType:MXKAccountManagerDataType isMandatory:YES expectedKeyType:kAes];
|
||||
if (keyData && [keyData isKindOfClass:[MXAesKeyData class]])
|
||||
{
|
||||
MXAesKeyData *aesKey = (MXAesKeyData *) keyData;
|
||||
NSData *cipher = [MXAes encrypt:data aesKey:aesKey.key iv:aesKey.iv error:nil];
|
||||
return cipher;
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] encryptData: no key method provided for encryption.");
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSData*)decryptData:(NSData*)data
|
||||
{
|
||||
// Exceptions are not cached as the key is always needed if the KeyProviderDelegate
|
||||
// is provided.
|
||||
MXKeyData *keyData = [[MXKeyProvider sharedInstance] requestKeyForDataOfType:MXKAccountManagerDataType isMandatory:YES expectedKeyType:kAes];
|
||||
if (keyData && [keyData isKindOfClass:[MXAesKeyData class]])
|
||||
{
|
||||
MXAesKeyData *aesKey = (MXAesKeyData *) keyData;
|
||||
NSData *decrypt = [MXAes decrypt:data aesKey:aesKey.key iv:aesKey.iv error:nil];
|
||||
return decrypt;
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] decryptData: no key method provided for decryption.");
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)migrateAccounts
|
||||
{
|
||||
NSString *pathOld = [[MXKAppSettings cacheFolder] stringByAppendingPathComponent:kMXKAccountsKeyOld];
|
||||
NSString *pathNew = [[MXKAppSettings cacheFolder] stringByAppendingPathComponent:kMXKAccountsKey];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if ([fileManager fileExistsAtPath:pathOld])
|
||||
{
|
||||
if (![fileManager fileExistsAtPath:pathNew])
|
||||
{
|
||||
MXLogDebug(@"[MXKAccountManager] migrateAccounts: reading account");
|
||||
mxAccounts = [NSKeyedUnarchiver unarchiveObjectWithFile:pathOld];
|
||||
MXLogDebug(@"[MXKAccountManager] migrateAccounts: writing to accountV2");
|
||||
[self saveAccounts];
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKAccountManager] migrateAccounts: removing account");
|
||||
[fileManager removeItemAtPath:pathOld error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user