2020-01-28 20:09:51 +00:00
/ *
2020-01-28 21:05:11 +00:00
Copyright 2020 New Vector Ltd
2020-01-28 20:09:51 +00:00
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 "SecurityViewController.h"
2020-01-29 16:56:24 +00:00
# import "ManageSessionViewController.h"
2020-01-28 20:09:51 +00:00
# import < MatrixKit / MatrixKit . h >
# import < OLMKit / OLMKit . h >
# import "AvatarGenerator.h"
# import "ThemeService.h"
# import "Riot-Swift.h"
2020-06-30 13:04:50 +00:00
// Dev flag to have more options
// # define CROSS_SIGNING _AND _BACKUP _DEV
2020-01-28 20:09:51 +00:00
enum
{
2020-07-21 13:17:13 +00:00
SECTION_PIN _CODE ,
2020-01-30 12:14:17 +00:00
SECTION_CRYPTO _SESSIONS ,
2020-06-18 13:34:24 +00:00
SECTION_SECURE _BACKUP ,
2020-03-12 10:21:47 +00:00
SECTION_CRYPTOGRAPHY ,
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-06-30 13:56:05 +00:00
SECTION_CROSSSIGNING ,
2020-04-23 14:46:44 +00:00
SECTION_KEYBACKUP ,
2020-06-30 13:04:50 +00:00
# endif
2020-01-29 07:19:48 +00:00
SECTION_ADVANCED ,
SECTION_COUNT
2020-01-28 20:09:51 +00:00
} ;
enum {
2020-03-12 10:21:47 +00:00
CROSSSIGNING_INFO ,
2020-03-18 11:20:14 +00:00
CROSSSIGNING_FIRST _ACTION , // Bootstrap , Reset , Verify this session , Request keys
CROSSSIGNING_SECOND _ACTION , // Reset
2020-01-28 20:09:51 +00:00
} ;
2020-06-18 13:34:24 +00:00
enum {
SECURE_BACKUP _DESCRIPTION ,
// TODO : We can display the state of 4 S both locally and on the server . Then , provide actions according to all combinations .
// - Does the 4 S contains all the 4 keys server side ?
// - Advice the user to do a recovery if there is less keys locally
2020-06-25 15:16:03 +00:00
// - Advice them to do a recovery if local keys are obsolete -> We cannot know now
2020-06-18 13:34:24 +00:00
// - Advice them to fix a secure backup if there is 4 S but no key backup
// - Warm them if there is no 4 S and they do not have all 3 signing keys locally . They will set up a not complete secure backup
2020-06-30 13:56:05 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-06-18 13:34:24 +00:00
SECURE_BACKUP _INFO ,
2020-06-30 13:56:05 +00:00
# endif
2020-06-18 13:34:24 +00:00
SECURE_BACKUP _SETUP ,
SECURE_BACKUP _RESTORE ,
SECURE_BACKUP _DELETE ,
SECURE_BACKUP _MANAGE _MANUALLY , // TODO : What to do with that ?
} ;
2020-07-21 13:17:13 +00:00
enum {
PIN_CODE _SETTING ,
PIN_CODE _DESCRIPTION ,
2020-07-24 14:54:44 +00:00
PIN_CODE _BIOMETRICS ,
2020-07-21 13:17:13 +00:00
PIN_CODE _COUNT
} ;
2020-06-18 13:34:24 +00:00
2020-01-29 14:56:06 +00:00
enum {
2020-03-12 10:21:47 +00:00
CRYPTOGRAPHY_INFO ,
CRYPTOGRAPHY_EXPORT , // TODO : To move to SECTION_KEYBACKUP
CRYPTOGRAPHY_COUNT
} ;
enum {
ADVANCED_BLACKLIST _UNVERIFIED _DEVICES ,
ADVANCED_BLACKLIST _UNVERIFIED _DEVICES _DESCRIPTION ,
ADVANCED_COUNT
2020-01-29 14:56:06 +00:00
} ;
2020-01-28 20:09:51 +00:00
2020-01-28 21:36:50 +00:00
@ interface SecurityViewController ( ) <
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-28 20:09:51 +00:00
SettingsKeyBackupTableViewSectionDelegate ,
KeyBackupSetupCoordinatorBridgePresenterDelegate ,
KeyBackupRecoverCoordinatorBridgePresenterDelegate ,
2020-06-30 13:04:50 +00:00
# endif
2020-06-15 14:30:58 +00:00
UIDocumentInteractionControllerDelegate ,
2020-06-25 18:23:40 +00:00
SecretsRecoveryCoordinatorBridgePresenterDelegate ,
2020-07-21 13:17:13 +00:00
SecureBackupSetupCoordinatorBridgePresenterDelegate ,
SetPinCoordinatorBridgePresenterDelegate >
2020-01-28 20:09:51 +00:00
{
// Current alert ( if any ) .
UIAlertController * currentAlert ;
// Devices
NSMutableArray < MXDevice * > * devicesArray ;
2020-06-18 13:34:24 +00:00
// SECURE_BACKUP _ * rows to display
NSArray < NSNumber * > * secureBackupSectionState ;
2020-01-28 20:09:51 +00:00
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change .
id kThemeServiceDidChangeThemeNotificationObserver ;
// The view used to export e2e keys
MXKEncryptionKeysExportView * exportView ;
// The document interaction Controller used to export e2e keys
UIDocumentInteractionController * documentInteractionController ;
NSURL * keyExportsFile ;
NSTimer * keyExportsFileDeletionTimer ;
// The current pushed view controller
UIViewController * pushedViewController ;
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-28 20:09:51 +00:00
SettingsKeyBackupTableViewSection * keyBackupSection ;
KeyBackupSetupCoordinatorBridgePresenter * keyBackupSetupCoordinatorBridgePresenter ;
2020-06-30 13:04:50 +00:00
# endif
2020-01-28 20:09:51 +00:00
KeyBackupRecoverCoordinatorBridgePresenter * keyBackupRecoverCoordinatorBridgePresenter ;
2020-06-30 13:04:50 +00:00
2020-06-15 14:30:58 +00:00
SecretsRecoveryCoordinatorBridgePresenter * secretsRecoveryCoordinatorBridgePresenter ;
2020-01-28 20:09:51 +00:00
}
2020-02-10 09:51:30 +00:00
@ property ( nonatomic ) BOOL isLoadingDevices ;
2020-06-15 14:30:58 +00:00
@ property ( nonatomic , strong ) MXKeyBackupVersion * currentkeyBackupVersion ;
2020-06-26 12:30:21 +00:00
@ property ( nonatomic , strong ) SecureBackupSetupCoordinatorBridgePresenter * secureBackupSetupCoordinatorBridgePresenter ;
2020-06-26 05:42:37 +00:00
@ property ( nonatomic , strong ) AuthenticatedSessionViewControllerFactory * authenticatedSessionViewControllerFactory ;
2020-07-21 13:17:13 +00:00
@ property ( nonatomic , strong ) SetPinCoordinatorBridgePresenter * setPinCoordinatorBridgePresenter ;
2020-02-10 09:51:30 +00:00
2020-01-28 20:09:51 +00:00
@ end
@ implementation SecurityViewController
# pragma mark - Setup & Teardown
+ ( SecurityViewController * ) instantiateWithMatrixSession : ( MXSession * ) matrixSession
{
SecurityViewController * viewController = [ [ UIStoryboard storyboardWithName : @ "Security" bundle : [ NSBundle mainBundle ] ] instantiateInitialViewController ] ;
[ viewController addMatrixSession : matrixSession ] ;
return viewController ;
}
# pragma mark - View life cycle
- ( void ) finalizeInit
{
[ super finalizeInit ] ;
// Setup ` MXKViewControllerHandling` properties
self . enableBarTintColorStatusChange = NO ;
self . rageShakeManager = [ RageShakeManager sharedManager ] ;
}
- ( void ) viewDidLoad
{
[ super viewDidLoad ] ;
// Do any additional setup after loading the view , typically from a nib .
2020-01-29 07:19:48 +00:00
self . navigationItem . title = NSLocalizedStringFromTable ( @ "security_settings_title" , @ "Vector" , nil ) ;
2020-01-28 20:09:51 +00:00
// Remove back bar button title when pushing a view controller
self . navigationItem . backBarButtonItem = [ [ UIBarButtonItem alloc ] initWithTitle : @ "" style : UIBarButtonItemStylePlain target : nil action : nil ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
[ self . tableView registerClass : MXKTableViewCellWithLabelAndSwitch . class forCellReuseIdentifier : [ MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier ] ] ;
[ self . tableView registerNib : MXKTableViewCellWithTextView . nib forCellReuseIdentifier : [ MXKTableViewCellWithTextView defaultReuseIdentifier ] ] ;
2020-06-18 09:47:53 +00:00
[ self . tableView registerNib : MXKTableViewCellWithButton . nib forCellReuseIdentifier : [ MXKTableViewCellWithButton defaultReuseIdentifier ] ] ;
2020-01-28 20:09:51 +00:00
// Enable self sizing cells
self . tableView . rowHeight = UITableViewAutomaticDimension ;
self . tableView . estimatedRowHeight = 50 ;
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-28 20:09:51 +00:00
if ( self . mainSession . crypto . backup )
{
MXDeviceInfo * deviceInfo = [ self . mainSession . crypto . deviceList storedDevice : self . mainSession . matrixRestClient . credentials . userId
deviceId : self . mainSession . matrixRestClient . credentials . deviceId ] ;
if ( deviceInfo )
{
keyBackupSection = [ [ SettingsKeyBackupTableViewSection alloc ] initWithKeyBackup : self . mainSession . crypto . backup userDevice : deviceInfo ] ;
keyBackupSection . delegate = self ;
}
}
2020-06-30 13:04:50 +00:00
# endif
2020-01-28 20:09:51 +00:00
// Observe user interface theme change .
kThemeServiceDidChangeThemeNotificationObserver = [ [ NSNotificationCenter defaultCenter ] addObserverForName : kThemeServiceDidChangeThemeNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( NSNotification * notif ) {
[ self userInterfaceThemeDidChange ] ;
} ] ;
[ self userInterfaceThemeDidChange ] ;
}
- ( void ) userInterfaceThemeDidChange
{
[ ThemeService . shared . theme applyStyleOnNavigationBar : self . navigationController . navigationBar ] ;
self . activityIndicator . backgroundColor = ThemeService . shared . theme . overlayBackgroundColor ;
// Check the table view style to select its bg color .
self . tableView . backgroundColor = ( ( self . tableView . style = = UITableViewStylePlain ) ? ThemeService . shared . theme . backgroundColor : ThemeService . shared . theme . headerBackgroundColor ) ;
self . view . backgroundColor = self . tableView . backgroundColor ;
self . tableView . separatorColor = ThemeService . shared . theme . lineBreakColor ;
2020-01-30 12:14:17 +00:00
[ self reloadData ] ;
2020-04-08 10:58:12 +00:00
[ self setNeedsStatusBarAppearanceUpdate ] ;
2020-01-28 20:09:51 +00:00
}
- ( UIStatusBarStyle ) preferredStatusBarStyle
{
return ThemeService . shared . theme . statusBarStyle ;
}
- ( void ) didReceiveMemoryWarning
{
[ super didReceiveMemoryWarning ] ;
// Dispose of any resources that can be recreated .
}
- ( void ) destroy
{
// Release the potential pushed view controller
[ self releasePushedViewController ] ;
if ( documentInteractionController )
{
[ documentInteractionController dismissPreviewAnimated : NO ] ;
[ documentInteractionController dismissMenuAnimated : NO ] ;
documentInteractionController = nil ;
}
if ( kThemeServiceDidChangeThemeNotificationObserver )
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : kThemeServiceDidChangeThemeNotificationObserver ] ;
kThemeServiceDidChangeThemeNotificationObserver = nil ;
}
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-28 20:09:51 +00:00
keyBackupSetupCoordinatorBridgePresenter = nil ;
2020-06-30 13:04:50 +00:00
# endif
2020-01-28 20:09:51 +00:00
keyBackupRecoverCoordinatorBridgePresenter = nil ;
2020-06-30 13:04:50 +00:00
2020-01-28 20:09:51 +00:00
}
- ( void ) viewWillAppear : ( BOOL ) animated
{
[ super viewWillAppear : animated ] ;
// Screen tracking
2020-01-30 12:14:17 +00:00
[ [ Analytics sharedInstance ] trackScreen : @ "Security" ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Release the potential pushed view controller
[ self releasePushedViewController ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Refresh display
2020-01-30 06:14:35 +00:00
[ self reloadData ] ;
2020-01-28 20:09:51 +00:00
// Refresh the current device information in parallel
[ self loadCurrentDeviceInformation ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Refresh devices in parallel
[ self loadDevices ] ;
2020-03-25 09:14:25 +00:00
[ self loadCrossSigning ] ;
2020-01-28 20:09:51 +00:00
}
- ( void ) viewWillDisappear : ( BOOL ) animated
{
[ super viewWillDisappear : animated ] ;
if ( currentAlert )
{
[ currentAlert dismissViewControllerAnimated : NO completion : nil ] ;
currentAlert = nil ;
}
}
# pragma mark - Internal methods
2020-02-10 09:51:30 +00:00
- ( BOOL ) showLoadingDevicesInformation
{
return self . isLoadingDevices && devicesArray . count = = 0 ;
}
2020-01-28 20:09:51 +00:00
- ( void ) pushViewController : ( UIViewController * ) viewController
{
// Keep ref on pushed view controller
pushedViewController = viewController ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Hide back button title
self . navigationItem . backBarButtonItem = [ [ UIBarButtonItem alloc ] initWithTitle : @ "" style : UIBarButtonItemStylePlain target : nil action : nil ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
[ self . navigationController pushViewController : viewController animated : YES ] ;
}
- ( void ) releasePushedViewController
{
if ( pushedViewController )
{
if ( [ pushedViewController isKindOfClass : [ UINavigationController class ] ] )
{
UINavigationController * navigationController = ( UINavigationController * ) pushedViewController ;
for ( id subViewController in navigationController . viewControllers )
{
if ( [ subViewController respondsToSelector : @ selector ( destroy ) ] )
{
[ subViewController destroy ] ;
}
}
}
else if ( [ pushedViewController respondsToSelector : @ selector ( destroy ) ] )
{
[ ( id ) pushedViewController destroy ] ;
}
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
pushedViewController = nil ;
}
}
- ( void ) reset
{
// Remove observers
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
}
- ( void ) loadCurrentDeviceInformation
{
// Refresh the current device information
MXKAccount * account = [ MXKAccountManager sharedManager ] . activeAccounts . firstObject ;
[ account loadDeviceInformation : ^ {
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Refresh all the table ( A slide down animation is observed when we limit the refresh to the concerned section ) .
// Note : The use of ' reloadData ' handles the case where the account has been logged out .
2020-01-30 06:14:35 +00:00
[ self reloadData ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
} failure : nil ] ;
}
- ( NSAttributedString * ) cryptographyInformation
{
// TODO Handle multi accounts
MXKAccount * account = [ MXKAccountManager sharedManager ] . activeAccounts . firstObject ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Crypto information
NSMutableAttributedString * cryptoInformationString = [ [ NSMutableAttributedString alloc ]
initWithString : NSLocalizedStringFromTable ( @ "settings_crypto_device_name" , @ "Vector" , nil )
attributes : @ { NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont systemFontOfSize : 17 ] } ] ;
[ cryptoInformationString appendAttributedString : [ [ NSMutableAttributedString alloc ]
initWithString : account . device . displayName ? account . device . displayName : @ ""
attributes : @ { NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont systemFontOfSize : 17 ] } ] ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
[ cryptoInformationString appendAttributedString : [ [ NSMutableAttributedString alloc ]
initWithString : NSLocalizedStringFromTable ( @ "settings_crypto_device_id" , @ "Vector" , nil )
attributes : @ { NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont systemFontOfSize : 17 ] } ] ] ;
[ cryptoInformationString appendAttributedString : [ [ NSMutableAttributedString alloc ]
initWithString : account . device . deviceId ? account . device . deviceId : @ ""
attributes : @ { NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont systemFontOfSize : 17 ] } ] ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
[ cryptoInformationString appendAttributedString : [ [ NSMutableAttributedString alloc ]
initWithString : NSLocalizedStringFromTable ( @ "settings_crypto_device_key" , @ "Vector" , nil )
attributes : @ { NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont systemFontOfSize : 17 ] } ] ] ;
NSString * fingerprint = account . mxSession . crypto . deviceEd25519Key ;
if ( fingerprint )
{
fingerprint = [ MXTools addWhiteSpacesToString : fingerprint every : 4 ] ;
}
[ cryptoInformationString appendAttributedString : [ [ NSMutableAttributedString alloc ]
initWithString : fingerprint ? fingerprint : @ ""
attributes : @ { NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont boldSystemFontOfSize : 17 ] } ] ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
return cryptoInformationString ;
}
- ( void ) loadDevices
{
2020-02-10 09:51:30 +00:00
self . isLoadingDevices = YES ;
2020-01-28 20:09:51 +00:00
// Refresh the account devices list
2020-01-28 21:36:50 +00:00
MXWeakify ( self ) ;
2020-01-28 22:27:45 +00:00
[ self . mainSession . matrixRestClient devices : ^ ( NSArray < MXDevice * > * devices ) {
2020-01-28 21:36:50 +00:00
MXStrongifyAndReturnIfNil ( self ) ;
2020-02-10 09:51:30 +00:00
self . isLoadingDevices = NO ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
if ( devices )
{
2020-01-28 21:36:50 +00:00
self -> devicesArray = [ NSMutableArray arrayWithArray : devices ] ;
2020-01-28 20:09:51 +00:00
// Sort devices according to the last seen date .
NSComparator comparator = ^ NSComparisonResult ( MXDevice * deviceA , MXDevice * deviceB ) {
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
if ( deviceA . lastSeenTs > deviceB . lastSeenTs )
{
return NSOrderedAscending ;
}
if ( deviceA . lastSeenTs < deviceB . lastSeenTs )
{
return NSOrderedDescending ;
}
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
return NSOrderedSame ;
} ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Sort devices list
2020-01-28 21:36:50 +00:00
[ self -> devicesArray sortUsingComparator : comparator ] ;
2020-01-28 20:09:51 +00:00
}
else
{
2020-01-28 21:36:50 +00:00
self -> devicesArray = nil ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Refresh all the table ( A slide down animation is observed when we limit the refresh to the concerned section ) .
// Note : The use of ' reloadData ' handles the case where the account has been logged out .
2020-01-30 06:14:35 +00:00
[ self reloadData ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
} failure : ^ ( NSError * error ) {
2020-01-28 21:36:50 +00:00
2020-02-10 09:51:30 +00:00
self . isLoadingDevices = NO ;
2020-01-28 20:09:51 +00:00
// Display the data that has been loaded last time
// Note : The use of ' reloadData ' handles the case where the account has been logged out .
2020-01-30 06:14:35 +00:00
[ self reloadData ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
} ] ;
}
2020-01-30 06:14:35 +00:00
- ( void ) reloadData
2020-01-28 20:09:51 +00:00
{
2020-06-18 13:34:24 +00:00
[ self refreshSecureBackupSectionData ] ;
2020-01-28 20:09:51 +00:00
// Trigger a full table reloadData
[ self . tableView reloadData ] ;
}
2020-03-18 11:20:14 +00:00
# pragma mark - Cross - signing
2020-03-25 09:14:25 +00:00
- ( void ) loadCrossSigning
{
MXCrossSigning * crossSigning = self . mainSession . crypto . crossSigning ;
[ crossSigning refreshStateWithSuccess : ^ ( BOOL stateUpdated ) {
if ( stateUpdated )
{
[ self reloadData ] ;
}
} failure : ^ ( NSError * _Nonnull error ) {
NSLog ( @ "[SecurityVC] loadCrossSigning: Cannot refresh cross-signing state. Error: %@" , error ) ;
} ] ;
}
2020-03-18 11:20:14 +00:00
- ( NSInteger ) numberOfRowsInCrossSigningSection
{
NSInteger numberOfRowsInCrossSigningSection ;
MXCrossSigning * crossSigning = self . mainSession . crypto . crossSigning ;
switch ( crossSigning . state )
{
case MXCrossSigningStateNotBootstrapped : // Action : Bootstrap
case MXCrossSigningStateCanCrossSign : // Action : Reset
numberOfRowsInCrossSigningSection = CROSSSIGNING_FIRST _ACTION + 1 ;
break ;
case MXCrossSigningStateCrossSigningExists : // Actions : Verify this session , Reset
case MXCrossSigningStateTrustCrossSigning : // Actions : Request keys , Reset
numberOfRowsInCrossSigningSection = CROSSSIGNING_SECOND _ACTION + 1 ;
break ;
}
return numberOfRowsInCrossSigningSection ;
}
- ( NSAttributedString * ) crossSigningInformation
{
MXCrossSigning * crossSigning = self . mainSession . crypto . crossSigning ;
NSString * crossSigningInformation ;
switch ( crossSigning . state )
{
case MXCrossSigningStateNotBootstrapped :
2020-04-23 15:07:35 +00:00
crossSigningInformation = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_info_not_bootstrapped" ] ;
2020-03-18 11:20:14 +00:00
break ;
case MXCrossSigningStateCrossSigningExists :
2020-04-23 15:07:35 +00:00
crossSigningInformation = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_info_exists" ] ;
2020-03-18 11:20:14 +00:00
break ;
case MXCrossSigningStateTrustCrossSigning :
2020-04-23 15:07:35 +00:00
crossSigningInformation = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_info_trusted" ] ;
2020-03-18 11:20:14 +00:00
break ;
case MXCrossSigningStateCanCrossSign :
2020-04-23 15:07:35 +00:00
crossSigningInformation = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_info_ok" ] ;
2020-06-24 08:07:58 +00:00
if ( ! [ self . mainSession . crypto . recoveryService hasSecretLocally : MXSecretId . crossSigningMaster ] )
{
crossSigningInformation = [ crossSigningInformation stringByAppendingString : @ "\n\n⚠️ The MSK is missing. Verify this device again or use the Secure Backup below to synchronise your keys accross your devices" ] ;
}
2020-03-18 11:20:14 +00:00
break ;
}
return [ [ NSAttributedString alloc ] initWithString : crossSigningInformation
attributes : @ {
NSForegroundColorAttributeName : ThemeService . shared . theme . textPrimaryColor ,
NSFontAttributeName : [ UIFont systemFontOfSize : 17 ]
} ] ;
}
- ( UITableViewCell * ) crossSigningButtonCellInTableView : ( UITableView * ) tableView forAction : ( NSInteger ) action
{
// Get a button cell
MXKTableViewCellWithButton * buttonCell = [ tableView dequeueReusableCellWithIdentifier : [ MXKTableViewCellWithButton defaultReuseIdentifier ] ] ;
if ( ! buttonCell )
{
buttonCell = [ [ MXKTableViewCellWithButton alloc ] init ] ;
}
[ buttonCell . mxkButton setTintColor : ThemeService . shared . theme . tintColor ] ;
buttonCell . mxkButton . titleLabel . font = [ UIFont systemFontOfSize : 17 ] ;
[ buttonCell . mxkButton removeTarget : self action : nil forControlEvents : UIControlEventTouchUpInside ] ;
buttonCell . mxkButton . accessibilityIdentifier = nil ;
// And customise it
MXCrossSigning * crossSigning = self . mainSession . crypto . crossSigning ;
switch ( crossSigning . state )
{
case MXCrossSigningStateNotBootstrapped : // Action : Bootstrap
[ self setUpcrossSigningButtonCellForBootstrap : buttonCell ] ;
break ;
case MXCrossSigningStateCanCrossSign : // Action : Reset
[ self setUpcrossSigningButtonCellForReset : buttonCell ] ;
break ;
case MXCrossSigningStateCrossSigningExists : // Actions : Verify this session , Reset
switch ( action )
{
case CROSSSIGNING_FIRST _ACTION :
2020-04-23 15:31:49 +00:00
[ self setUpcrossSigningButtonCellForCompletingSecurity : buttonCell ] ;
2020-03-18 11:20:14 +00:00
break ;
case CROSSSIGNING_SECOND _ACTION :
[ self setUpcrossSigningButtonCellForReset : buttonCell ] ;
break ;
}
break ;
case MXCrossSigningStateTrustCrossSigning : // Actions : Request keys , Reset
switch ( action )
{
case CROSSSIGNING_FIRST _ACTION :
2020-04-23 15:31:49 +00:00
// By verifying our device again , it will get cross - signing keys by gossiping
[ self setUpcrossSigningButtonCellForCompletingSecurity : buttonCell ] ;
2020-03-18 11:20:14 +00:00
break ;
case CROSSSIGNING_SECOND _ACTION :
[ self setUpcrossSigningButtonCellForReset : buttonCell ] ;
break ;
}
break ;
}
return buttonCell ;
}
- ( void ) setUpcrossSigningButtonCellForBootstrap : ( MXKTableViewCellWithButton * ) buttonCell
{
2020-04-23 15:07:35 +00:00
NSString * btnTitle = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_bootstrap" ] ;
2020-03-18 11:20:14 +00:00
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
2020-06-19 07:32:27 +00:00
[ buttonCell . mxkButton addTarget : self action : @ selector ( setupCrossSigning : ) forControlEvents : UIControlEventTouchUpInside ] ;
2020-03-18 11:20:14 +00:00
}
2020-06-25 15:16:25 +00:00
- ( void ) setupCrossSigning : ( id ) sender
2020-03-18 11:20:14 +00:00
{
2020-06-30 15:03:33 +00:00
[ self setupCrossSigningWithTitle : @ "Set up cross-signing" // TODO
message : NSLocalizedStringFromTable ( @ "security_settings_user_password_description" , @ "Vector" , nil )
success : ^ {
} failure : ^ ( NSError * error ) {
} ] ;
}
- ( void ) setupCrossSigningWithTitle : ( NSString * ) title
message : ( NSString * ) message
success : ( void ( ^ ) ( void ) ) success
failure : ( void ( ^ ) ( NSError * error ) ) failure
2020-03-18 11:20:14 +00:00
{
2020-06-26 05:42:37 +00:00
__block UIViewController * viewController ;
[ self startActivityIndicator ] ;
// Get credentials to set up cross - signing
NSString * path = [ NSString stringWithFormat : @ "%@/keys/device_signing/upload" , kMXAPIPrefixPathUnstable ] ;
_authenticatedSessionViewControllerFactory = [ [ AuthenticatedSessionViewControllerFactory alloc ] initWithSession : self . mainSession ] ;
[ _authenticatedSessionViewControllerFactory viewControllerForPath : path
httpMethod : @ "POST"
2020-06-30 15:03:33 +00:00
title : title
message : message
2020-06-26 05:42:37 +00:00
onViewController : ^ ( UIViewController * _Nonnull theViewController )
{
viewController = theViewController ;
[ self presentViewController : viewController animated : YES completion : nil ] ;
} onAuthenticated : ^ ( NSDictionary * _Nonnull authParams ) {
[ viewController dismissViewControllerAnimated : NO completion : nil ] ;
viewController = nil ;
MXCrossSigning * crossSigning = self . mainSession . crypto . crossSigning ;
if ( crossSigning )
{
[ crossSigning setupWithAuthParams : authParams success : ^ {
[ self stopActivityIndicator ] ;
[ self reloadData ] ;
2020-06-30 15:03:33 +00:00
success ( ) ;
2020-06-26 05:42:37 +00:00
} failure : ^ ( NSError * _Nonnull error ) {
[ self stopActivityIndicator ] ;
[ self reloadData ] ;
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
2020-06-30 15:03:33 +00:00
failure ( error ) ;
2020-06-26 05:42:37 +00:00
} ] ;
}
} onCancelled : ^ {
[ self stopActivityIndicator ] ;
[ viewController dismissViewControllerAnimated : NO completion : nil ] ;
viewController = nil ;
2020-06-30 15:03:33 +00:00
failure ( nil ) ;
2020-06-26 05:42:37 +00:00
} onFailure : ^ ( NSError * _Nonnull error ) {
[ self stopActivityIndicator ] ;
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
[ viewController dismissViewControllerAnimated : NO completion : nil ] ;
viewController = nil ;
2020-06-30 15:03:33 +00:00
failure ( error ) ;
2020-06-26 05:42:37 +00:00
} ] ;
2020-06-19 07:32:27 +00:00
}
2020-06-25 15:16:32 +00:00
- ( void ) resetCrossSigning : ( id ) sender
2020-06-19 07:32:27 +00:00
{
[ currentAlert dismissViewControllerAnimated : NO completion : nil ] ;
// Double confirmation
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : @ "Are you sure?" // TODO
2020-06-26 05:42:37 +00:00
message : @ "Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from." // TODO
2020-06-19 07:32:27 +00:00
preferredStyle : UIAlertControllerStyleAlert ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : @ "Reset"
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action )
{
// Setup and reset are the same thing
2020-06-25 15:17:04 +00:00
[ self setupCrossSigning : nil ] ;
2020-06-19 07:32:27 +00:00
} ] ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : [ NSBundle mxk_localizedStringForKey : @ "cancel" ]
style : UIAlertActionStyleCancel
handler : nil ] ] ;
[ self presentViewController : alertController animated : YES completion : nil ] ;
currentAlert = alertController ;
2020-03-18 11:20:14 +00:00
}
- ( void ) setUpcrossSigningButtonCellForReset : ( MXKTableViewCellWithButton * ) buttonCell
{
2020-04-23 15:07:35 +00:00
NSString * btnTitle = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_reset" ] ;
2020-03-18 11:20:14 +00:00
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
buttonCell . mxkButton . tintColor = ThemeService . shared . theme . warningColor ;
[ buttonCell . mxkButton addTarget : self action : @ selector ( resetCrossSigning : ) forControlEvents : UIControlEventTouchUpInside ] ;
}
2020-04-23 15:31:49 +00:00
- ( void ) setUpcrossSigningButtonCellForCompletingSecurity : ( MXKTableViewCellWithButton * ) buttonCell
2020-03-18 11:20:14 +00:00
{
2020-04-23 15:31:49 +00:00
NSString * btnTitle = [ NSBundle mxk_localizedStringForKey : @ "security_settings_crosssigning_complete_security" ] ;
2020-03-18 11:20:14 +00:00
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
2020-04-23 15:31:49 +00:00
[ buttonCell . mxkButton addTarget : self action : @ selector ( presentCompleteSecurity ) forControlEvents : UIControlEventTouchUpInside ] ;
2020-03-18 11:20:14 +00:00
}
- ( void ) displayComingSoon
{
2020-04-23 15:07:35 +00:00
[ [ AppDelegate theDelegate ] showAlertWithTitle : nil message : [ NSBundle mxk_localizedStringForKey : @ "security_settings_coming_soon" ] ] ;
2020-03-18 11:20:14 +00:00
}
2020-06-18 13:34:24 +00:00
# pragma mark - SSSS
- ( void ) refreshSecureBackupSectionData
{
2020-06-24 07:35:46 +00:00
MXRecoveryService * recoveryService = self . mainSession . crypto . recoveryService ;
if ( recoveryService . hasRecovery )
2020-06-18 13:34:24 +00:00
{
secureBackupSectionState = @ [
@ ( SECURE_BACKUP _RESTORE ) ,
@ ( SECURE_BACKUP _DELETE ) ,
@ ( SECURE_BACKUP _DESCRIPTION ) ,
// @ ( SECURE_BACKUP _MANAGE _MANUALLY ) ,
] ;
}
else
{
2020-06-30 15:03:33 +00:00
secureBackupSectionState = @ [
@ ( SECURE_BACKUP _SETUP ) ,
@ ( SECURE_BACKUP _DESCRIPTION ) ,
// @ ( SECURE_BACKUP _MANAGE _MANUALLY ) ,
] ;
2020-06-18 13:34:24 +00:00
}
2020-06-30 13:56:05 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
secureBackupSectionState = [ @ [ @ ( SECURE_BACKUP _INFO ) ] arrayByAddingObjectsFromArray : secureBackupSectionState ] ;
# endif
2020-06-18 13:34:24 +00:00
}
- ( NSUInteger ) secureBackupSectionEnumForRow : ( NSUInteger ) row
{
if ( row < secureBackupSectionState . count )
{
return secureBackupSectionState [ row ] . unsignedIntegerValue ;
}
return SECURE_BACKUP _DESCRIPTION ;
}
- ( NSUInteger ) numberOfRowsInSecureBackupSection
{
return secureBackupSectionState . count ;
}
2020-06-24 07:35:46 +00:00
- ( NSString * ) secureBackupInformation
{
NSString * secureBackupInformation ;
MXRecoveryService * recoveryService = self . mainSession . crypto . recoveryService ;
if ( recoveryService . hasRecovery )
{
NSMutableString * mutableString = [ @ "Your account has a Secure Backup.\n" mutableCopy ] ;
// Check all keys that should be in the SSSSS
// TODO : Check obsoletes ones but need spec update
BOOL hasWarning = NO ;
NSString * keyState = [ self informationForSecret : MXSecretId . crossSigningMaster secretName : @ "Cross-signing" hasWarning : & hasWarning ] ;
if ( keyState )
{
[ mutableString appendString : keyState ] ;
}
keyState = [ self informationForSecret : MXSecretId . crossSigningSelfSigning secretName : @ "Self signing" hasWarning : & hasWarning ] ;
if ( keyState )
{
[ mutableString appendString : keyState ] ;
}
keyState = [ self informationForSecret : MXSecretId . crossSigningUserSigning secretName : @ "User signing" hasWarning : & hasWarning ] ;
if ( keyState )
{
[ mutableString appendString : keyState ] ;
}
keyState = [ self informationForSecret : MXSecretId . keyBackup secretName : @ "Message Backup" hasWarning : & hasWarning ] ;
if ( keyState )
{
[ mutableString appendString : keyState ] ;
}
else
{
if ( self . mainSession . crypto . backup . keyBackupVersion )
{
[ mutableString appendString : @ "\n\n⚠️ The key of your current Message backup is not in the Secure Backup. Restore it first (see below)." ] ;
}
else
{
[ mutableString appendString : @ "\n\n⚠️ Consider create a Message Backup (see below)." ] ;
}
}
if ( ! hasWarning )
{
[ mutableString appendFormat : @ "\n\nIf you are facing an issue, synchronise your Secure Backup." ] ;
}
secureBackupInformation = mutableString ;
}
else
{
if ( self . canSetupSecureBackup )
{
secureBackupInformation = [ NSString stringWithFormat : @ "No Secure Backup. Create one.\n-----\nKeys to back up: %@" , recoveryService . secretsStoredLocally ] ;
}
else
{
secureBackupInformation = [ NSString stringWithFormat : @ "No Secure Backup. Set up cross-signing first (see above)" ] ;
}
}
return secureBackupInformation ;
}
- ( nullable NSString * ) informationForSecret : ( NSString * ) secretId secretName : ( NSString * ) secretName hasWarning : ( BOOL * ) hasWarning
{
NSString * information ;
2020-06-25 15:16:44 +00:00
MXRecoveryService * recoveryService = self . mainSession . crypto . recoveryService ;
2020-06-24 07:35:46 +00:00
if ( [ recoveryService hasSecretWithSecretId : secretId ] )
{
if ( [ recoveryService hasSecretLocally : secretId ] )
{
information = [ NSString stringWithFormat : @ "\n ✅ %@ is in the backup" , secretName ] ;
}
else
{
2020-06-24 08:07:58 +00:00
information = [ NSString stringWithFormat : @ "\n ⚠️ %@ is in the backup but not locally. Tap Synchronise" , secretName ] ;
2020-06-24 07:35:46 +00:00
* hasWarning | = YES ;
}
}
else
{
if ( [ recoveryService hasSecretLocally : secretId ] )
{
information = [ NSString stringWithFormat : @ "\n ⚠️ %@ is not in the backup. Tap Synchronise" , secretName ] ;
* hasWarning | = YES ;
}
}
return information ;
}
- ( BOOL ) canSetupSecureBackup
{
// Accept to create a setup only if we have the 3 cross - signing keys
// This is the path to have a sane state
MXRecoveryService * recoveryService = self . mainSession . crypto . recoveryService ;
NSArray * crossSigningServiceSecrets = @ [
MXSecretId . crossSigningMaster ,
MXSecretId . crossSigningSelfSigning ,
MXSecretId . crossSigningUserSigning ] ;
return ( [ recoveryService . secretsStoredLocally mx_intersectArray : crossSigningServiceSecrets ] . count
= = crossSigningServiceSecrets . count ) ;
}
2020-06-19 07:32:27 +00:00
- ( void ) setupSecureBackup
{
2020-06-30 15:03:33 +00:00
if ( self . canSetupSecureBackup )
{
[ self setupSecureBackup2 ] ;
}
else
{
// Set up cross - signing first
[ self setupCrossSigningWithTitle : NSLocalizedStringFromTable ( @ "secure_key_backup_setup_intro_title" , @ "Vector" , nil )
message : NSLocalizedStringFromTable ( @ "security_settings_user_password_description" , @ "Vector" , nil )
success : ^ {
[ self setupSecureBackup2 ] ;
} failure : ^ ( NSError * error ) {
} ] ;
}
}
- ( void ) setupSecureBackup2
2020-06-19 07:32:27 +00:00
{
2020-06-26 12:36:27 +00:00
SecureBackupSetupCoordinatorBridgePresenter * secureBackupSetupCoordinatorBridgePresenter = [ [ SecureBackupSetupCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession ] ;
2020-06-25 18:23:40 +00:00
secureBackupSetupCoordinatorBridgePresenter . delegate = self ;
[ secureBackupSetupCoordinatorBridgePresenter presentFrom : self animated : YES ] ;
self . secureBackupSetupCoordinatorBridgePresenter = secureBackupSetupCoordinatorBridgePresenter ;
2020-06-19 07:32:27 +00:00
}
2020-06-18 13:34:24 +00:00
- ( void ) restoreFromSecureBackup
{
secretsRecoveryCoordinatorBridgePresenter = [ [ SecretsRecoveryCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession recoveryGoal : SecretsRecoveryGoalRestoreSecureBackup ] ;
[ secretsRecoveryCoordinatorBridgePresenter presentFrom : self animated : true ] ;
secretsRecoveryCoordinatorBridgePresenter . delegate = self ;
}
2020-06-19 06:00:22 +00:00
- ( void ) deleteSecureBackup
{
2020-06-25 15:16:51 +00:00
MXRecoveryService * recoveryService = self . mainSession . crypto . recoveryService ;
2020-06-19 06:00:22 +00:00
if ( recoveryService )
{
[ self startActivityIndicator ] ;
2020-06-30 12:02:47 +00:00
[ recoveryService deleteRecoveryWithDeleteServicesBackups : YES success : ^ {
2020-06-19 06:00:22 +00:00
[ self stopActivityIndicator ] ;
[ self reloadData ] ;
} failure : ^ ( NSError * _Nonnull error ) {
[ self stopActivityIndicator ] ;
[ self reloadData ] ;
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
}
}
2020-06-18 13:34:24 +00:00
2020-01-28 20:09:51 +00:00
# pragma mark - Segues
- ( void ) prepareForSegue : ( UIStoryboardSegue * ) segue sender : ( id ) sender
{
// Keep ref on destinationViewController
[ super prepareForSegue : segue sender : sender ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// FIXME add night mode
}
# pragma mark - UITableView data source
- ( NSInteger ) numberOfSectionsInTableView : ( UITableView * ) tableView
{
2020-01-29 07:19:48 +00:00
return SECTION_COUNT ;
2020-01-28 20:09:51 +00:00
}
- ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section
{
NSInteger count = 0 ;
2020-01-28 21:36:50 +00:00
2020-01-29 07:19:48 +00:00
switch ( section )
2020-01-28 20:09:51 +00:00
{
2020-07-21 13:17:13 +00:00
case SECTION_PIN _CODE :
2020-07-24 14:54:44 +00:00
count = PIN_CODE _COUNT ;
if ( ! [ PinCodePreferences shared ] . isBiometricsAvailable )
2020-07-21 13:17:13 +00:00
{
2020-07-24 14:54:44 +00:00
count - = 1 ;
2020-07-21 13:17:13 +00:00
}
break ;
2020-01-30 12:14:17 +00:00
case SECTION_CRYPTO _SESSIONS :
2020-02-10 09:51:30 +00:00
if ( self . showLoadingDevicesInformation )
{
count = 2 ;
}
else
{
count = devicesArray . count + 1 ;
}
2020-01-29 07:19:48 +00:00
break ;
2020-06-18 13:34:24 +00:00
case SECTION_SECURE _BACKUP :
count = [ self numberOfRowsInSecureBackupSection ] ;
break ;
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-29 07:19:48 +00:00
case SECTION_KEYBACKUP :
2020-01-28 20:09:51 +00:00
count = keyBackupSection . numberOfRows ;
2020-01-29 07:19:48 +00:00
break ;
2020-03-12 10:21:47 +00:00
case SECTION_CROSSSIGNING :
2020-03-18 11:20:14 +00:00
count = [ self numberOfRowsInCrossSigningSection ] ;
2020-03-12 10:21:47 +00:00
break ;
2020-06-30 13:56:05 +00:00
# endif
2020-03-12 10:21:47 +00:00
case SECTION_CRYPTOGRAPHY :
count = CRYPTOGRAPHY_COUNT ;
break ;
2020-01-29 07:19:48 +00:00
case SECTION_ADVANCED :
count = ADVANCED_COUNT ;
break ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
2020-01-28 20:09:51 +00:00
return count ;
}
- ( MXKTableViewCellWithLabelAndSwitch * ) getLabelAndSwitchCell : ( UITableView * ) tableview forIndexPath : ( NSIndexPath * ) indexPath
{
MXKTableViewCellWithLabelAndSwitch * cell = [ tableview dequeueReusableCellWithIdentifier : [ MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier ] forIndexPath : indexPath ] ;
2020-01-28 21:36:50 +00:00
2020-04-22 13:15:30 +00:00
cell . mxkLabelLeadingConstraint . constant = cell . vc_separatorInset . left ;
2020-01-28 20:09:51 +00:00
cell . mxkSwitchTrailingConstraint . constant = 15 ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
cell . mxkLabel . textColor = ThemeService . shared . theme . textPrimaryColor ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
[ cell . mxkSwitch removeTarget : self action : nil forControlEvents : UIControlEventTouchUpInside ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
// Force layout before reusing a cell ( fix switch displayed outside the screen )
[ cell layoutIfNeeded ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
return cell ;
}
- ( MXKTableViewCell * ) getDefaultTableViewCell : ( UITableView * ) tableView
{
MXKTableViewCell * cell = [ tableView dequeueReusableCellWithIdentifier : [ MXKTableViewCell defaultReuseIdentifier ] ] ;
if ( ! cell )
{
cell = [ [ MXKTableViewCell alloc ] init ] ;
}
else
{
cell . selectionStyle = UITableViewCellSelectionStyleDefault ;
cell . accessoryType = UITableViewCellAccessoryNone ;
cell . accessoryView = nil ;
2020-01-29 08:32:50 +00:00
cell . imageView . image = nil ;
2020-01-28 20:09:51 +00:00
}
cell . textLabel . accessibilityIdentifier = nil ;
cell . textLabel . font = [ UIFont systemFontOfSize : 17 ] ;
cell . textLabel . textColor = ThemeService . shared . theme . textPrimaryColor ;
cell . contentView . backgroundColor = UIColor . clearColor ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
return cell ;
}
2020-01-29 08:32:50 +00:00
- ( MXKTableViewCell * ) deviceCellWithDevice : ( MXDevice * ) device forTableView : ( UITableView * ) tableView
{
MXKTableViewCell * cell = [ self getDefaultTableViewCell : tableView ] ;
NSString * name = device . displayName ;
NSString * deviceId = device . deviceId ;
cell . textLabel . text = ( name . length ? [ NSString stringWithFormat : @ "%@ (%@)" , name , deviceId ] : [ NSString stringWithFormat : @ "(%@)" , deviceId ] ) ;
cell . textLabel . numberOfLines = 0 ;
2020-07-16 21:16:11 +00:00
[ cell vc_setAccessoryDisclosureIndicatorWithCurrentTheme ] ;
2020-01-29 08:32:50 +00:00
if ( [ deviceId isEqualToString : self . mainSession . matrixRestClient . credentials . deviceId ] )
{
cell . textLabel . font = [ UIFont boldSystemFontOfSize : 17 ] ;
}
cell . imageView . image = [ self shieldImageForDevice : deviceId ] ;
return cell ;
}
- ( UIImage * ) shieldImageForDevice : ( NSString * ) deviceId
{
2020-04-23 13:50:01 +00:00
if ( ! self . mainSession . crypto . crossSigning . canCrossSign )
{
2020-04-28 14:15:31 +00:00
if ( [ deviceId isEqualToString : self . mainSession . myDeviceId ] )
{
return [ UIImage imageNamed : @ "encryption_warning" ] ;
}
else
{
return [ UIImage imageNamed : @ "encryption_normal" ] ;
}
2020-04-23 13:50:01 +00:00
}
2020-01-29 08:32:50 +00:00
UIImage * shieldImageForDevice = [ UIImage imageNamed : @ "encryption_warning" ] ;
MXDeviceInfo * device = [ self . mainSession . crypto deviceWithDeviceId : deviceId ofUser : self . mainSession . myUser . userId ] ;
if ( device . trustLevel . isVerified )
{
shieldImageForDevice = [ UIImage imageNamed : @ "encryption_trusted" ] ;
}
return shieldImageForDevice ;
}
2020-01-29 07:19:48 +00:00
- ( MXKTableViewCell * ) descriptionCellForTableView : ( UITableView * ) tableView withText : ( NSString * ) text
{
MXKTableViewCell * cell = [ self getDefaultTableViewCell : tableView ] ;
cell . textLabel . text = text ;
cell . textLabel . textColor = ThemeService . shared . theme . textPrimaryColor ;
cell . textLabel . numberOfLines = 0 ;
cell . contentView . backgroundColor = ThemeService . shared . theme . headerBackgroundColor ;
cell . selectionStyle = UITableViewCellSelectionStyleNone ;
return cell ;
}
2020-01-28 20:09:51 +00:00
- ( MXKTableViewCellWithTextView * ) textViewCellForTableView : ( UITableView * ) tableView atIndexPath : ( NSIndexPath * ) indexPath
{
MXKTableViewCellWithTextView * textViewCell = [ tableView dequeueReusableCellWithIdentifier : [ MXKTableViewCellWithTextView defaultReuseIdentifier ] forIndexPath : indexPath ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
textViewCell . mxkTextView . textColor = ThemeService . shared . theme . textPrimaryColor ;
textViewCell . mxkTextView . font = [ UIFont systemFontOfSize : 17 ] ;
textViewCell . mxkTextView . backgroundColor = [ UIColor clearColor ] ;
2020-04-22 13:15:30 +00:00
textViewCell . mxkTextViewLeadingConstraint . constant = tableView . vc_separatorInset . left ;
textViewCell . mxkTextViewTrailingConstraint . constant = tableView . vc_separatorInset . right ;
2020-01-28 20:09:51 +00:00
textViewCell . mxkTextView . accessibilityIdentifier = nil ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
return textViewCell ;
}
2020-06-18 09:47:53 +00:00
- ( MXKTableViewCellWithButton * ) buttonCellForTableView : ( UITableView * ) tableView atIndexPath : ( NSIndexPath * ) indexPath
{
MXKTableViewCellWithButton * cell = [ self . tableView dequeueReusableCellWithIdentifier : [ MXKTableViewCellWithButton defaultReuseIdentifier ] forIndexPath : indexPath ] ;
if ( ! cell )
{
cell = [ [ MXKTableViewCellWithButton alloc ] init ] ;
}
else
{
// Fix https : // github . com / vector - im / riot - ios / issues / 1354
cell . mxkButton . titleLabel . text = nil ;
cell . mxkButton . enabled = YES ;
}
cell . mxkButton . titleLabel . font = [ UIFont systemFontOfSize : 17 ] ;
[ cell . mxkButton setTintColor : ThemeService . shared . theme . tintColor ] ;
return cell ;
}
- ( MXKTableViewCellWithButton * ) buttonCellWithTitle : ( NSString * ) title
action : ( SEL ) action
forTableView : ( UITableView * ) tableView
atIndexPath : ( NSIndexPath * ) indexPath
{
MXKTableViewCellWithButton * cell = [ self buttonCellForTableView : tableView atIndexPath : indexPath ] ;
[ cell . mxkButton setTitle : title forState : UIControlStateNormal ] ;
[ cell . mxkButton setTitle : title forState : UIControlStateHighlighted ] ;
[ cell . mxkButton removeTarget : self action : nil forControlEvents : UIControlEventTouchUpInside ] ;
[ cell . mxkButton addTarget : self action : action forControlEvents : UIControlEventTouchUpInside ] ;
cell . mxkButton . accessibilityIdentifier = nil ;
return cell ;
}
2020-01-28 20:09:51 +00:00
- ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath
{
NSInteger section = indexPath . section ;
NSInteger row = indexPath . row ;
// set the cell to a default value to avoid application crashes
UITableViewCell * cell = [ [ UITableViewCell alloc ] init ] ;
cell . backgroundColor = [ UIColor redColor ] ;
2020-01-28 21:36:50 +00:00
MXSession * session = self . mainSession ;
2020-07-21 13:17:13 +00:00
if ( section = = SECTION_PIN _CODE )
{
2020-07-24 14:54:44 +00:00
if ( indexPath . row = = PIN_CODE _SETTING )
2020-07-21 13:17:13 +00:00
{
2020-07-24 14:54:44 +00:00
if ( [ PinCodePreferences shared ] . forcePinProtection )
2020-07-21 13:17:13 +00:00
{
cell = [ self getDefaultTableViewCell : tableView ] ;
cell . textLabel . text = NSLocalizedStringFromTable ( @ "pin_protection_settings_enabled_forced" , @ "Vector" , nil ) ;
}
2020-07-24 14:54:44 +00:00
else
2020-07-21 13:17:13 +00:00
{
MXKTableViewCellWithLabelAndSwitch * switchCell = [ self getLabelAndSwitchCell : tableView forIndexPath : indexPath ] ;
switchCell . mxkLabel . text = NSLocalizedStringFromTable ( @ "pin_protection_settings_enable_pin" , @ "Vector" , nil ) ;
switchCell . mxkSwitch . on = [ PinCodePreferences shared ] . isPinSet ;
[ switchCell . mxkSwitch addTarget : self action : @ selector ( enablePinCodeSwitchValueChanged : ) forControlEvents : UIControlEventValueChanged ] ;
cell = switchCell ;
}
2020-08-12 10:17:59 +00:00
cell . selectionStyle = UITableViewCellSelectionStyleNone ;
2020-07-24 14:54:44 +00:00
}
else if ( indexPath . row = = PIN_CODE _DESCRIPTION )
{
if ( [ PinCodePreferences shared ] . isPinSet )
2020-07-21 13:17:13 +00:00
{
cell = [ self descriptionCellForTableView : tableView
withText : NSLocalizedStringFromTable ( @ "pin_protection_settings_section_footer" , @ "Vector" , nil ) ] ;
}
2020-07-24 14:54:44 +00:00
else
{
cell = [ self descriptionCellForTableView : tableView withText : nil ] ;
}
}
else if ( indexPath . row = = PIN_CODE _BIOMETRICS )
{
MXKTableViewCellWithLabelAndSwitch * switchCell = [ self getLabelAndSwitchCell : tableView forIndexPath : indexPath ] ;
NSString * format = NSLocalizedStringFromTable ( @ "biometrics_settings_enable_x" , @ "Vector" , nil ) ;
switchCell . mxkLabel . text = [ NSString stringWithFormat : format , [ PinCodePreferences shared ] . localizedBiometricsName ] ;
switchCell . mxkSwitch . on = [ PinCodePreferences shared ] . isBiometricsSet ;
switchCell . mxkSwitch . enabled = [ PinCodePreferences shared ] . isBiometricsAvailable ;
[ switchCell . mxkSwitch addTarget : self action : @ selector ( enableBiometricsSwitchValueChanged : ) forControlEvents : UIControlEventValueChanged ] ;
cell = switchCell ;
2020-07-21 13:17:13 +00:00
}
}
else if ( section = = SECTION_CRYPTO _SESSIONS )
2020-01-28 20:09:51 +00:00
{
2020-02-10 09:51:30 +00:00
if ( self . showLoadingDevicesInformation )
2020-01-28 20:09:51 +00:00
{
2020-02-10 09:51:30 +00:00
if ( indexPath . row = = 0 )
{
cell = [ self descriptionCellForTableView : tableView
withText : NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions_loading" , @ "Vector" , nil ) ] ;
}
else
{
cell = [ self descriptionCellForTableView : tableView
2020-06-30 16:12:50 +00:00
withText : NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions_description_2" , @ "Vector" , nil ) ] ;
2020-02-10 09:51:30 +00:00
}
2020-01-28 20:09:51 +00:00
}
2020-02-10 09:51:30 +00:00
else
2020-01-28 20:09:51 +00:00
{
2020-02-10 09:51:30 +00:00
if ( row < devicesArray . count )
{
cell = [ self deviceCellWithDevice : devicesArray [ row ] forTableView : tableView ] ;
}
else if ( row = = devicesArray . count )
{
cell = [ self descriptionCellForTableView : tableView
2020-06-30 16:12:50 +00:00
withText : NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions_description_2" , @ "Vector" , nil ) ] ;
2020-02-10 09:51:30 +00:00
}
2020-01-28 20:09:51 +00:00
}
2020-01-29 07:19:48 +00:00
}
2020-06-18 13:34:24 +00:00
else if ( section = = SECTION_SECURE _BACKUP )
{
switch ( [ self secureBackupSectionEnumForRow : row ] )
{
case SECURE_BACKUP _DESCRIPTION :
{
cell = [ self descriptionCellForTableView : tableView
2020-06-30 13:04:50 +00:00
withText : NSLocalizedStringFromTable ( @ "security_settings_secure_backup_description" , @ "Vector" , nil ) ] ;
2020-06-18 13:34:24 +00:00
break ;
}
2020-06-30 13:56:05 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-06-24 07:35:46 +00:00
case SECURE_BACKUP _INFO :
{
cell = [ self descriptionCellForTableView : tableView
withText : self . secureBackupInformation ] ;
break ;
}
2020-06-30 13:56:05 +00:00
# endif
2020-06-18 13:34:24 +00:00
case SECURE_BACKUP _SETUP :
{
2020-06-30 14:23:29 +00:00
MXKTableViewCellWithButton * buttonCell = [ self buttonCellWithTitle : NSLocalizedStringFromTable ( @ "security_settings_secure_backup_setup" , @ "Vector" , nil )
2020-06-19 07:32:27 +00:00
action : @ selector ( setupSecureBackup )
2020-06-18 13:34:24 +00:00
forTableView : tableView
atIndexPath : indexPath ] ;
cell = buttonCell ;
break ;
}
case SECURE_BACKUP _RESTORE :
{
2020-06-30 14:23:29 +00:00
MXKTableViewCellWithButton * buttonCell = [ self buttonCellWithTitle : NSLocalizedStringFromTable ( @ "security_settings_secure_backup_synchronise" , @ "Vector" , nil )
action : @ selector ( restoreFromSecureBackup )
forTableView : tableView
atIndexPath : indexPath ] ;
2020-06-18 13:34:24 +00:00
cell = buttonCell ;
break ;
}
case SECURE_BACKUP _DELETE :
{
2020-06-30 14:23:29 +00:00
MXKTableViewCellWithButton * buttonCell = [ self buttonCellWithTitle : NSLocalizedStringFromTable ( @ "security_settings_secure_backup_delete" , @ "Vector" , nil )
2020-06-19 06:00:22 +00:00
action : @ selector ( deleteSecureBackup )
2020-06-18 13:34:24 +00:00
forTableView : tableView
atIndexPath : indexPath ] ;
buttonCell . mxkButton . tintColor = ThemeService . shared . theme . warningColor ;
cell = buttonCell ;
break ;
}
case SECURE_BACKUP _MANAGE _MANUALLY :
{
MXKTableViewCellWithTextView * textCell = [ self textViewCellForTableView : tableView atIndexPath : indexPath ] ;
textCell . mxkTextView . text = @ "Advanced: Manually manage keys" ; // TODO
2020-07-16 21:16:11 +00:00
[ textCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme ] ;
2020-06-18 13:34:24 +00:00
cell = textCell ;
break ;
}
}
}
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-03-12 10:21:47 +00:00
else if ( section = = SECTION_KEYBACKUP )
{
cell = [ keyBackupSection cellForRowAtRow : row ] ;
}
else if ( section = = SECTION_CROSSSIGNING )
2020-01-29 07:19:48 +00:00
{
switch ( row )
2020-01-28 20:09:51 +00:00
{
2020-03-12 10:21:47 +00:00
case CROSSSIGNING_INFO :
2020-01-28 20:09:51 +00:00
{
2020-03-12 10:21:47 +00:00
MXKTableViewCellWithTextView * cryptoCell = [ self textViewCellForTableView : tableView atIndexPath : indexPath ] ;
2020-03-18 08:41:27 +00:00
cryptoCell . mxkTextView . attributedText = [ self crossSigningInformation ] ;
2020-03-12 10:21:47 +00:00
cell = cryptoCell ;
2020-01-29 07:19:48 +00:00
break ;
2020-01-28 20:09:51 +00:00
}
2020-03-18 11:20:14 +00:00
case CROSSSIGNING_FIRST _ACTION :
cell = [ self crossSigningButtonCellInTableView : tableView forAction : CROSSSIGNING_FIRST _ACTION ] ;
break ;
case CROSSSIGNING_SECOND _ACTION :
cell = [ self crossSigningButtonCellInTableView : tableView forAction : CROSSSIGNING_SECOND _ACTION ] ;
2020-01-29 07:19:48 +00:00
break ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
}
2020-06-30 13:56:05 +00:00
# endif
2020-03-12 10:21:47 +00:00
else if ( section = = SECTION_CRYPTOGRAPHY )
2020-01-29 07:19:48 +00:00
{
2020-01-29 14:56:06 +00:00
switch ( row )
{
2020-03-12 10:21:47 +00:00
case CRYPTOGRAPHY_INFO :
2020-01-29 14:56:06 +00:00
{
MXKTableViewCellWithTextView * cryptoCell = [ self textViewCellForTableView : tableView atIndexPath : indexPath ] ;
cryptoCell . mxkTextView . attributedText = [ self cryptographyInformation ] ;
cell = cryptoCell ;
break ;
}
2020-03-12 10:21:47 +00:00
case CRYPTOGRAPHY_EXPORT :
2020-01-29 14:56:06 +00:00
{
2020-06-18 09:47:53 +00:00
MXKTableViewCellWithButton * exportKeysBtnCell = [ self buttonCellWithTitle : NSLocalizedStringFromTable ( @ "security_settings_export_keys_manually" , @ "Vector" , nil )
action : @ selector ( exportEncryptionKeys : )
forTableView : tableView
atIndexPath : indexPath ] ;
2020-01-29 14:56:06 +00:00
cell = exportKeysBtnCell ;
break ;
}
}
2020-01-29 07:19:48 +00:00
}
2020-03-12 10:21:47 +00:00
else if ( section = = SECTION_ADVANCED )
{
switch ( row )
{
case ADVANCED_BLACKLIST _UNVERIFIED _DEVICES :
{
MXKTableViewCellWithLabelAndSwitch * labelAndSwitchCell = [ self getLabelAndSwitchCell : tableView forIndexPath : indexPath ] ;
labelAndSwitchCell . mxkLabel . text = NSLocalizedStringFromTable ( @ "security_settings_blacklist_unverified_devices" , @ "Vector" , nil ) ;
labelAndSwitchCell . mxkSwitch . on = session . crypto . globalBlacklistUnverifiedDevices ;
labelAndSwitchCell . mxkSwitch . onTintColor = ThemeService . shared . theme . tintColor ;
labelAndSwitchCell . mxkSwitch . enabled = YES ;
[ labelAndSwitchCell . mxkSwitch addTarget : self action : @ selector ( toggleBlacklistUnverifiedDevices : ) forControlEvents : UIControlEventTouchUpInside ] ;
cell = labelAndSwitchCell ;
break ;
}
case ADVANCED_BLACKLIST _UNVERIFIED _DEVICES _DESCRIPTION :
{
cell = [ self descriptionCellForTableView : tableView
withText : NSLocalizedStringFromTable ( @ "security_settings_blacklist_unverified_devices_description" , @ "Vector" , nil ) ] ;
break ;
}
}
}
2020-01-28 21:05:11 +00:00
return cell ;
}
- ( nullable NSString * ) tableView : ( UITableView * ) tableView titleForHeaderInSection : ( NSInteger ) section
{
2020-01-29 07:19:48 +00:00
switch ( section )
2020-01-28 20:09:51 +00:00
{
2020-07-21 13:17:13 +00:00
case SECTION_PIN _CODE :
2020-07-24 14:54:44 +00:00
{
NSString * format = NSLocalizedStringFromTable ( @ "pin_protection_settings_section_header_x" , @ "Vector" , nil ) ;
return [ NSString stringWithFormat : format , [ PinCodePreferences shared ] . localizedBiometricsName ] ;
}
2020-01-30 12:14:17 +00:00
case SECTION_CRYPTO _SESSIONS :
return NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions" , @ "Vector" , nil ) ;
2020-06-18 13:34:24 +00:00
case SECTION_SECURE _BACKUP :
2020-06-30 13:04:50 +00:00
return NSLocalizedStringFromTable ( @ "security_settings_secure_backup" , @ "Vector" , nil ) ;
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-29 07:19:48 +00:00
case SECTION_KEYBACKUP :
return NSLocalizedStringFromTable ( @ "security_settings_backup" , @ "Vector" , nil ) ;
2020-03-12 10:21:47 +00:00
case SECTION_CROSSSIGNING :
return NSLocalizedStringFromTable ( @ "security_settings_crosssigning" , @ "Vector" , nil ) ;
2020-06-30 13:56:05 +00:00
# endif
2020-03-12 10:21:47 +00:00
case SECTION_CRYPTOGRAPHY :
return NSLocalizedStringFromTable ( @ "security_settings_cryptography" , @ "Vector" , nil ) ;
2020-01-29 07:19:48 +00:00
case SECTION_ADVANCED :
return NSLocalizedStringFromTable ( @ "security_settings_advanced" , @ "Vector" , nil ) ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:36:50 +00:00
2020-01-28 21:05:11 +00:00
return nil ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
- ( void ) tableView : ( UITableView * ) tableView willDisplayHeaderView : ( UIView * ) view forSection : ( NSInteger ) section
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
if ( [ view isKindOfClass : UITableViewHeaderFooterView . class ] )
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
// Customize label style
UITableViewHeaderFooterView * tableViewHeaderFooterView = ( UITableViewHeaderFooterView * ) view ;
tableViewHeaderFooterView . textLabel . textColor = ThemeService . shared . theme . textPrimaryColor ;
tableViewHeaderFooterView . textLabel . font = [ UIFont systemFontOfSize : 15 ] ;
2020-01-28 20:09:51 +00:00
}
}
2020-01-28 21:05:11 +00:00
# pragma mark - UITableView delegate
2020-01-28 20:09:51 +00:00
2020-01-28 21:05:11 +00:00
- ( void ) tableView : ( UITableView * ) tableView willDisplayCell : ( UITableViewCell * ) cell forRowAtIndexPath : ( NSIndexPath * ) indexPath ;
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
cell . backgroundColor = ThemeService . shared . theme . backgroundColor ;
2020-01-28 21:36:50 +00:00
2020-01-28 21:05:11 +00:00
if ( cell . selectionStyle ! = UITableViewCellSelectionStyleNone )
2020-01-28 21:36:50 +00:00
{
2020-01-28 21:05:11 +00:00
// Update the selected background view
if ( ThemeService . shared . theme . selectedBackgroundColor )
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
cell . selectedBackgroundView = [ [ UIView alloc ] init ] ;
cell . selectedBackgroundView . backgroundColor = ThemeService . shared . theme . selectedBackgroundColor ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
else
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
if ( tableView . style = = UITableViewStylePlain )
{
cell . selectedBackgroundView = nil ;
}
else
{
cell . selectedBackgroundView . backgroundColor = nil ;
}
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
}
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
- ( CGFloat ) tableView : ( UITableView * ) tableView heightForHeaderInSection : ( NSInteger ) section
2020-01-28 20:09:51 +00:00
{
2020-01-30 12:14:17 +00:00
if ( section = = SECTION_CRYPTO _SESSIONS )
2020-01-29 07:19:48 +00:00
{
return 44 ;
}
2020-01-28 21:05:11 +00:00
return 24 ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
- ( CGFloat ) tableView : ( UITableView * ) tableView heightForFooterInSection : ( NSInteger ) section
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
return 24 ;
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:05:11 +00:00
- ( void ) tableView : ( UITableView * ) tableView didSelectRowAtIndexPath : ( NSIndexPath * ) indexPath
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
if ( self . tableView = = tableView )
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
NSInteger section = indexPath . section ;
NSInteger row = indexPath . row ;
2020-01-30 12:14:17 +00:00
if ( section = = SECTION_CRYPTO _SESSIONS )
2020-01-28 20:09:51 +00:00
{
2020-01-29 07:19:48 +00:00
NSUInteger deviceIndex = row ;
if ( deviceIndex < devicesArray . count )
2020-01-28 21:05:11 +00:00
{
2020-04-23 13:50:01 +00:00
MXDevice * device = devicesArray [ deviceIndex ] ;
2020-01-29 16:56:24 +00:00
2020-04-24 16:47:57 +00:00
if ( self . mainSession . crypto . crossSigning . state = = MXCrossSigningStateNotBootstrapped )
{
// Display the device details . The verification will fail there .
ManageSessionViewController * viewController = [ ManageSessionViewController instantiateWithMatrixSession : self . mainSession andDevice : device ] ;
[ self pushViewController : viewController ] ;
}
else if ( self . mainSession . crypto . crossSigning . canCrossSign )
2020-04-23 13:50:01 +00:00
{
ManageSessionViewController * viewController = [ ManageSessionViewController instantiateWithMatrixSession : self . mainSession andDevice : device ] ;
[ self pushViewController : viewController ] ;
}
else
{
if ( [ device . deviceId isEqualToString : self . mainSession . matrixRestClient . credentials . deviceId ] )
{
[ self presentCompleteSecurity ] ;
}
else
{
[ self presentShouldCompleteSecurityAlert ] ;
}
}
2020-01-28 21:05:11 +00:00
}
2020-01-28 20:09:51 +00:00
}
2020-01-28 21:36:50 +00:00
2020-01-28 21:05:11 +00:00
[ tableView deselectRowAtIndexPath : indexPath animated : YES ] ;
2020-01-28 20:09:51 +00:00
}
}
2020-04-23 13:50:01 +00:00
- ( void ) presentCompleteSecurity
{
[ [ AppDelegate theDelegate ] presentCompleteSecurityForSession : self . mainSession ] ;
}
- ( void ) presentShouldCompleteSecurityAlert
{
[ currentAlert dismissViewControllerAnimated : NO completion : nil ] ;
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : NSLocalizedStringFromTable ( @ "security_settings_complete_security_alert_title" , @ "Vector" , nil )
message : NSLocalizedStringFromTable ( @ "security_settings_complete_security_alert_message" , @ "Vector" , nil )
preferredStyle : UIAlertControllerStyleAlert ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : [ NSBundle mxk_localizedStringForKey : @ "ok" ]
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
[ self presentCompleteSecurity ] ;
} ] ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : NSLocalizedStringFromTable ( @ "later" , @ "Vector" , nil )
style : UIAlertActionStyleCancel
handler : nil ] ] ;
[ self presentViewController : alertController animated : YES completion : nil ] ;
currentAlert = alertController ;
[ currentAlert mxk_setAccessibilityIdentifier : @ "SettingsVCCompleteSecurity" ] ;
}
2020-01-28 21:36:50 +00:00
# pragma mark - UIDocumentInteractionControllerDelegate
- ( void ) documentInteractionController : ( UIDocumentInteractionController * ) controller didEndSendingToApplication : ( NSString * ) application
{
// If iOS wants to call this method , this is the right time to remove the file
[ self deleteKeyExportFile ] ;
}
- ( void ) documentInteractionControllerDidDismissOptionsMenu : ( UIDocumentInteractionController * ) controller
{
documentInteractionController = nil ;
}
2020-01-28 21:05:11 +00:00
# pragma mark - actions
2020-01-28 20:09:51 +00:00
2020-01-28 21:05:11 +00:00
- ( void ) exportEncryptionKeys : ( UITapGestureRecognizer * ) recognizer
2020-01-28 20:09:51 +00:00
{
2020-01-28 21:05:11 +00:00
[ currentAlert dismissViewControllerAnimated : NO completion : nil ] ;
2020-01-28 20:09:51 +00:00
2020-01-28 21:05:11 +00:00
exportView = [ [ MXKEncryptionKeysExportView alloc ] initWithMatrixSession : self . mainSession ] ;
currentAlert = exportView . alertController ;
2020-01-28 20:09:51 +00:00
2020-01-28 21:05:11 +00:00
// Use a temporary file for the export
keyExportsFile = [ NSURL fileURLWithPath : [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : @ "riot-keys.txt" ] ] ;
2020-01-28 20:09:51 +00:00
2020-01-28 21:05:11 +00:00
// Make sure the file is empty
[ self deleteKeyExportFile ] ;
2020-01-28 20:09:51 +00:00
2020-01-28 21:05:11 +00:00
// Show the export dialog
2020-01-28 21:36:50 +00:00
MXWeakify ( self ) ;
2020-01-28 21:05:11 +00:00
[ exportView showInViewController : self toExportKeysToFile : keyExportsFile onComplete : ^ ( BOOL success ) {
2020-01-28 21:36:50 +00:00
MXStrongifyAndReturnIfNil ( self ) ;
self -> currentAlert = nil ;
self -> exportView = nil ;
2020-01-28 21:05:11 +00:00
2020-01-28 21:36:50 +00:00
if ( success )
2020-01-28 21:05:11 +00:00
{
2020-01-28 21:36:50 +00:00
// Let another app handling this file
self -> documentInteractionController = [ UIDocumentInteractionController interactionControllerWithURL : self -> keyExportsFile ] ;
[ self -> documentInteractionController setDelegate : self ] ;
2020-01-28 21:05:11 +00:00
2020-01-28 21:36:50 +00:00
if ( [ self -> documentInteractionController presentOptionsMenuFromRect : self . view . bounds inView : self . view animated : YES ] )
2020-01-28 21:05:11 +00:00
{
2020-01-28 21:36:50 +00:00
// We want to delete the temp keys file after it has been processed by the other app .
// We use [ UIDocumentInteractionControllerDelegate didEndSendingToApplication ] for that
// but it is not reliable for all cases ( see http : // stackoverflow . com / a / 21867096 ) .
// So , arm a timer to auto delete the file after 10 mins .
self -> keyExportsFileDeletionTimer = [ NSTimer scheduledTimerWithTimeInterval : 600 target : self selector : @ selector ( deleteKeyExportFile ) userInfo : self repeats : NO ] ;
}
else
{
self -> documentInteractionController = nil ;
[ self deleteKeyExportFile ] ;
2020-01-28 21:05:11 +00:00
}
}
} ] ;
}
- ( void ) deleteKeyExportFile
{
// Cancel the deletion timer if it is still here
if ( keyExportsFileDeletionTimer )
{
[ keyExportsFileDeletionTimer invalidate ] ;
keyExportsFileDeletionTimer = nil ;
}
// And delete the file
if ( keyExportsFile && [ [ NSFileManager defaultManager ] fileExistsAtPath : keyExportsFile . path ] )
{
[ [ NSFileManager defaultManager ] removeItemAtPath : keyExportsFile . path error : nil ] ;
2020-01-28 20:09:51 +00:00
}
}
2020-01-28 21:36:50 +00:00
- ( void ) toggleBlacklistUnverifiedDevices : ( id ) sender
{
UISwitch * switchButton = ( UISwitch * ) sender ;
2020-01-28 21:05:11 +00:00
2020-01-28 21:36:50 +00:00
self . mainSession . crypto . globalBlacklistUnverifiedDevices = switchButton . on ;
2020-01-28 21:05:11 +00:00
2020-01-28 21:36:50 +00:00
[ self . tableView reloadData ] ;
2020-01-28 20:09:51 +00:00
}
2020-07-21 13:17:13 +00:00
- ( void ) enablePinCodeSwitchValueChanged : ( UISwitch * ) sender
{
SetPinCoordinatorViewMode viewMode = sender . isOn ? SetPinCoordinatorViewModeSetPin : SetPinCoordinatorViewModeConfirmPinToDeactivate ;
self . setPinCoordinatorBridgePresenter = [ [ SetPinCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession viewMode : viewMode ] ;
self . setPinCoordinatorBridgePresenter . delegate = self ;
[ self . setPinCoordinatorBridgePresenter presentFrom : self animated : YES ] ;
}
2020-01-28 21:36:50 +00:00
2020-07-24 14:54:44 +00:00
- ( void ) enableBiometricsSwitchValueChanged : ( UISwitch * ) sender
{
SetPinCoordinatorViewMode viewMode = sender . isOn ? SetPinCoordinatorViewModeSetupBiometricsFromSettings : SetPinCoordinatorViewModeConfirmBiometricsToDeactivate ;
self . setPinCoordinatorBridgePresenter = [ [ SetPinCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession viewMode : viewMode ] ;
self . setPinCoordinatorBridgePresenter . delegate = self ;
[ self . setPinCoordinatorBridgePresenter presentFrom : self animated : YES ] ;
}
2020-01-28 20:09:51 +00:00
# pragma mark - SettingsKeyBackupTableViewSectionDelegate
2020-06-30 13:04:50 +00:00
# ifdef CROSS_SIGNING _AND _BACKUP _DEV
2020-01-28 20:09:51 +00:00
- ( void ) settingsKeyBackupTableViewSectionDidUpdate : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection
{
[ self . tableView reloadData ] ;
}
- ( MXKTableViewCellWithTextView * ) settingsKeyBackupTableViewSection : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection textCellForRow : ( NSInteger ) textCellForRow
{
2020-01-29 07:19:48 +00:00
return [ self textViewCellForTableView : self . tableView atIndexPath : [ NSIndexPath indexPathForRow : textCellForRow inSection : SECTION_KEYBACKUP ] ] ;
2020-01-28 20:09:51 +00:00
}
- ( MXKTableViewCellWithButton * ) settingsKeyBackupTableViewSection : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection buttonCellForRow : ( NSInteger ) buttonCellForRow
{
2020-06-18 09:47:53 +00:00
return [ self buttonCellForTableView : self . tableView
atIndexPath : [ NSIndexPath indexPathForRow : buttonCellForRow inSection : SECTION_KEYBACKUP ] ] ;
2020-01-28 20:09:51 +00:00
}
- ( void ) settingsKeyBackupTableViewSectionShowKeyBackupSetup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection
{
[ self showKeyBackupSetupFromSignOutFlow : NO ] ;
}
- ( void ) settingsKeyBackup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection showKeyBackupRecover : ( MXKeyBackupVersion * ) keyBackupVersion
{
2020-06-15 14:30:58 +00:00
self . currentkeyBackupVersion = keyBackupVersion ;
// If key backup key is stored in SSSS ask for secrets recovery before restoring key backup .
if ( ! self . mainSession . crypto . backup . hasPrivateKeyInCryptoStore
&& self . mainSession . crypto . recoveryService . hasRecovery
&& [ self . mainSession . crypto . recoveryService hasSecretWithSecretId : MXSecretId . keyBackup ] )
{
[ self showSecretsRecovery ] ;
}
else
{
[ self showKeyBackupRecover : keyBackupVersion fromViewController : self ] ;
}
2020-01-28 20:09:51 +00:00
}
- ( void ) settingsKeyBackup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection showKeyBackupDeleteConfirm : ( MXKeyBackupVersion * ) keyBackupVersion
{
MXWeakify ( self ) ;
[ currentAlert dismissViewControllerAnimated : NO completion : nil ] ;
currentAlert =
[ UIAlertController alertControllerWithTitle : NSLocalizedStringFromTable ( @ "settings_key_backup_delete_confirmation_prompt_title" , @ "Vector" , nil )
message : NSLocalizedStringFromTable ( @ "settings_key_backup_delete_confirmation_prompt_msg" , @ "Vector" , nil )
preferredStyle : UIAlertControllerStyleAlert ] ;
[ currentAlert addAction : [ UIAlertAction actionWithTitle : [ NSBundle mxk_localizedStringForKey : @ "cancel" ]
style : UIAlertActionStyleCancel
handler : ^ ( UIAlertAction * action ) {
MXStrongifyAndReturnIfNil ( self ) ;
self -> currentAlert = nil ;
} ] ] ;
[ currentAlert addAction : [ UIAlertAction actionWithTitle : NSLocalizedStringFromTable ( @ "settings_key_backup_button_delete" , @ "Vector" , nil )
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
MXStrongifyAndReturnIfNil ( self ) ;
self -> currentAlert = nil ;
[ self -> keyBackupSection deleteWithKeyBackupVersion : keyBackupVersion ] ;
} ] ] ;
[ currentAlert mxk_setAccessibilityIdentifier : @ "SettingsVCDeleteKeyBackup" ] ;
[ self presentViewController : currentAlert animated : YES completion : nil ] ;
}
- ( void ) settingsKeyBackup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection showActivityIndicator : ( BOOL ) show
{
if ( show )
{
[ self startActivityIndicator ] ;
}
else
{
[ self stopActivityIndicator ] ;
}
}
- ( void ) settingsKeyBackup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection showError : ( NSError * ) error
{
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
}
# pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
- ( void ) showKeyBackupSetupFromSignOutFlow : ( BOOL ) showFromSignOutFlow
{
keyBackupSetupCoordinatorBridgePresenter = [ [ KeyBackupSetupCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
[ keyBackupSetupCoordinatorBridgePresenter presentFrom : self
isStartedFromSignOut : showFromSignOutFlow
animated : true ] ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
keyBackupSetupCoordinatorBridgePresenter . delegate = self ;
}
- ( void ) keyBackupSetupCoordinatorBridgePresenterDelegateDidCancel : ( KeyBackupSetupCoordinatorBridgePresenter * ) bridgePresenter {
[ keyBackupSetupCoordinatorBridgePresenter dismissWithAnimated : true ] ;
keyBackupSetupCoordinatorBridgePresenter = nil ;
}
- ( void ) keyBackupSetupCoordinatorBridgePresenterDelegateDidSetupRecoveryKey : ( KeyBackupSetupCoordinatorBridgePresenter * ) bridgePresenter {
[ keyBackupSetupCoordinatorBridgePresenter dismissWithAnimated : true ] ;
keyBackupSetupCoordinatorBridgePresenter = nil ;
[ keyBackupSection reload ] ;
}
2020-06-30 13:04:50 +00:00
# endif
2020-01-28 20:09:51 +00:00
# pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
2020-06-15 14:30:58 +00:00
- ( void ) showKeyBackupRecover : ( MXKeyBackupVersion * ) keyBackupVersion fromViewController : ( UIViewController * ) presentingViewController
2020-01-28 20:09:51 +00:00
{
keyBackupRecoverCoordinatorBridgePresenter = [ [ KeyBackupRecoverCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession keyBackupVersion : keyBackupVersion ] ;
2020-06-15 14:30:58 +00:00
[ keyBackupRecoverCoordinatorBridgePresenter presentFrom : presentingViewController animated : true ] ;
keyBackupRecoverCoordinatorBridgePresenter . delegate = self ;
}
- ( void ) pushKeyBackupRecover : ( MXKeyBackupVersion * ) keyBackupVersion fromNavigationController : ( UINavigationController * ) navigationController
{
keyBackupRecoverCoordinatorBridgePresenter = [ [ KeyBackupRecoverCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession keyBackupVersion : keyBackupVersion ] ;
[ keyBackupRecoverCoordinatorBridgePresenter pushFrom : navigationController animated : YES ] ;
2020-01-28 20:09:51 +00:00
keyBackupRecoverCoordinatorBridgePresenter . delegate = self ;
}
- ( void ) keyBackupRecoverCoordinatorBridgePresenterDidCancel : ( KeyBackupRecoverCoordinatorBridgePresenter * ) bridgePresenter {
[ keyBackupRecoverCoordinatorBridgePresenter dismissWithAnimated : true ] ;
keyBackupRecoverCoordinatorBridgePresenter = nil ;
2020-06-15 14:30:58 +00:00
secretsRecoveryCoordinatorBridgePresenter = nil ;
2020-01-28 20:09:51 +00:00
}
- ( void ) keyBackupRecoverCoordinatorBridgePresenterDidRecover : ( KeyBackupRecoverCoordinatorBridgePresenter * ) bridgePresenter {
[ keyBackupRecoverCoordinatorBridgePresenter dismissWithAnimated : true ] ;
keyBackupRecoverCoordinatorBridgePresenter = nil ;
2020-06-15 14:30:58 +00:00
secretsRecoveryCoordinatorBridgePresenter = nil ;
}
# pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
- ( void ) showSecretsRecovery
{
secretsRecoveryCoordinatorBridgePresenter = [ [ SecretsRecoveryCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession recoveryGoal : SecretsRecoveryGoalKeyBackup ] ;
[ secretsRecoveryCoordinatorBridgePresenter presentFrom : self animated : true ] ;
secretsRecoveryCoordinatorBridgePresenter . delegate = self ;
}
- ( void ) secretsRecoveryCoordinatorBridgePresenterDelegateDidCancel : ( SecretsRecoveryCoordinatorBridgePresenter * ) coordinatorBridgePresenter
{
[ secretsRecoveryCoordinatorBridgePresenter dismissWithAnimated : YES completion : nil ] ;
secretsRecoveryCoordinatorBridgePresenter = nil ;
}
- ( void ) secretsRecoveryCoordinatorBridgePresenterDelegateDidComplete : ( SecretsRecoveryCoordinatorBridgePresenter * ) coordinatorBridgePresenter
{
UIViewController * presentedViewController = [ coordinatorBridgePresenter toPresentable ] ;
2020-06-18 13:34:24 +00:00
if ( coordinatorBridgePresenter . recoveryGoal = = SecretsRecoveryGoalKeyBackup )
2020-06-15 14:30:58 +00:00
{
2020-06-18 13:34:24 +00:00
// Go to the true key backup recovery screen
if ( [ presentedViewController isKindOfClass : UINavigationController . class ] )
{
UINavigationController * navigationController = ( UINavigationController * ) self . presentedViewController ;
[ self pushKeyBackupRecover : self . currentkeyBackupVersion fromNavigationController : navigationController ] ;
}
else
{
[ self showKeyBackupRecover : self . currentkeyBackupVersion fromViewController : presentedViewController ] ;
}
2020-06-15 14:30:58 +00:00
}
else
{
2020-06-18 13:34:24 +00:00
[ secretsRecoveryCoordinatorBridgePresenter dismissWithAnimated : YES completion : nil ] ;
secretsRecoveryCoordinatorBridgePresenter = nil ;
2020-06-15 14:30:58 +00:00
}
2020-01-28 20:09:51 +00:00
}
2020-06-26 12:36:27 +00:00
# pragma mark - SecureBackupSetupCoordinatorBridgePresenterDelegate
2020-06-26 05:42:37 +00:00
2020-06-26 12:36:27 +00:00
- ( void ) secureBackupSetupCoordinatorBridgePresenterDelegateDidComplete : ( SecureBackupSetupCoordinatorBridgePresenter * ) coordinatorBridgePresenter
2020-06-26 05:42:37 +00:00
{
[ self . secureBackupSetupCoordinatorBridgePresenter dismissWithAnimated : YES completion : nil ] ;
self . secureBackupSetupCoordinatorBridgePresenter = nil ;
}
2020-06-26 12:36:27 +00:00
- ( void ) secureBackupSetupCoordinatorBridgePresenterDelegateDidCancel : ( SecureBackupSetupCoordinatorBridgePresenter * ) coordinatorBridgePresenter
2020-06-26 05:42:37 +00:00
{
[ self . secureBackupSetupCoordinatorBridgePresenter dismissWithAnimated : YES completion : nil ] ;
self . secureBackupSetupCoordinatorBridgePresenter = nil ;
2020-01-28 20:09:51 +00:00
}
2020-07-21 13:17:13 +00:00
# pragma mark - SetPinCoordinatorBridgePresenterDelegate
- ( void ) setPinCoordinatorBridgePresenterDelegateDidComplete : ( SetPinCoordinatorBridgePresenter * ) coordinatorBridgePresenter
{
[ self . tableView reloadData ] ;
[ self dismissViewControllerAnimated : YES completion : nil ] ;
}
- ( void ) setPinCoordinatorBridgePresenterDelegateDidCancel : ( SetPinCoordinatorBridgePresenter * ) coordinatorBridgePresenter
{
[ self . tableView reloadData ] ;
[ self dismissViewControllerAnimated : YES completion : nil ] ;
}
2020-01-28 20:09:51 +00:00
@ end