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 "AppDelegate.h"
# import "AvatarGenerator.h"
# import "ThemeService.h"
# import "Riot-Swift.h"
enum
{
2020-01-30 12:14:17 +00:00
SECTION_CRYPTO _SESSIONS ,
2020-03-12 10:21:47 +00:00
SECTION_CROSSSIGNING ,
SECTION_CRYPTOGRAPHY ,
2020-04-23 14:46:44 +00:00
SECTION_KEYBACKUP ,
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-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-01-28 20:09:51 +00:00
SettingsKeyBackupTableViewSectionDelegate ,
KeyBackupSetupCoordinatorBridgePresenterDelegate ,
KeyBackupRecoverCoordinatorBridgePresenterDelegate ,
2020-01-28 21:36:50 +00:00
UIDocumentInteractionControllerDelegate >
2020-01-28 20:09:51 +00:00
{
// Current alert ( if any ) .
UIAlertController * currentAlert ;
// Devices
NSMutableArray < MXDevice * > * devicesArray ;
// 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 ;
SettingsKeyBackupTableViewSection * keyBackupSection ;
KeyBackupSetupCoordinatorBridgePresenter * keyBackupSetupCoordinatorBridgePresenter ;
KeyBackupRecoverCoordinatorBridgePresenter * keyBackupRecoverCoordinatorBridgePresenter ;
}
2020-02-10 09:51:30 +00:00
@ property ( nonatomic ) BOOL isLoadingDevices ;
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 ] ] ;
// Enable self sizing cells
self . tableView . rowHeight = UITableViewAutomaticDimension ;
self . tableView . estimatedRowHeight = 50 ;
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 ;
}
}
// 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-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 ;
}
keyBackupSetupCoordinatorBridgePresenter = nil ;
keyBackupRecoverCoordinatorBridgePresenter = nil ;
}
- ( 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
{
// 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
case MXCrossSigningStateCanCrossSignAsynchronously : // 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 :
crossSigningInformation = @ "Cross-signing is not yet set up." ;
break ;
case MXCrossSigningStateCrossSigningExists :
crossSigningInformation = @ "Your account has a cross-signing identity, but it is not yet trusted by this session." ;
break ;
case MXCrossSigningStateTrustCrossSigning :
crossSigningInformation = @ "Cross-signing is enabled. You can trust other users and your other sessions based on cross-signing but you cannot cross-sign from this session because it does not have cross-signing private keys." ;
break ;
case MXCrossSigningStateCanCrossSign :
case MXCrossSigningStateCanCrossSignAsynchronously :
crossSigningInformation = @ "Cross-signing is enabled." ;
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
case MXCrossSigningStateCanCrossSignAsynchronously : // Action : Reset
[ self setUpcrossSigningButtonCellForReset : buttonCell ] ;
break ;
case MXCrossSigningStateCrossSigningExists : // Actions : Verify this session , Reset
switch ( action )
{
case CROSSSIGNING_FIRST _ACTION :
[ self setUpcrossSigningButtonCellForVerifyingThisSession : buttonCell ] ;
break ;
case CROSSSIGNING_SECOND _ACTION :
[ self setUpcrossSigningButtonCellForReset : buttonCell ] ;
break ;
}
break ;
case MXCrossSigningStateTrustCrossSigning : // Actions : Request keys , Reset
switch ( action )
{
case CROSSSIGNING_FIRST _ACTION :
[ self setUpcrossSigningButtonCellForPrivateKeysRequest : buttonCell ] ;
break ;
case CROSSSIGNING_SECOND _ACTION :
[ self setUpcrossSigningButtonCellForReset : buttonCell ] ;
break ;
}
break ;
}
return buttonCell ;
}
- ( void ) setUpcrossSigningButtonCellForBootstrap : ( MXKTableViewCellWithButton * ) buttonCell
{
NSString * btnTitle = @ "Bootstrap cross-signing" ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
[ buttonCell . mxkButton addTarget : self action : @ selector ( bootstrapCrossSigning : ) forControlEvents : UIControlEventTouchUpInside ] ;
}
- ( void ) bootstrapCrossSigning : ( UITapGestureRecognizer * ) recognizer
{
[ self displayComingSoon ] ;
}
- ( void ) setUpcrossSigningButtonCellForReset : ( MXKTableViewCellWithButton * ) buttonCell
{
NSString * btnTitle = @ "Reset cross-signing" ;
[ 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 ] ;
}
- ( void ) resetCrossSigning : ( UITapGestureRecognizer * ) recognizer
{
[ self displayComingSoon ] ;
}
- ( void ) setUpcrossSigningButtonCellForVerifyingThisSession : ( MXKTableViewCellWithButton * ) buttonCell
{
NSString * btnTitle = @ "Verify this session" ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
[ buttonCell . mxkButton addTarget : self action : @ selector ( verifyThisSession : ) forControlEvents : UIControlEventTouchUpInside ] ;
}
- ( void ) verifyThisSession : ( UITapGestureRecognizer * ) recognizer
{
// TODO : We should
[ [ AppDelegate theDelegate ] showAlertWithTitle : nil message : @ "Verify this session from a session which trusts the existing cross-sign identity" ] ;
}
- ( void ) setUpcrossSigningButtonCellForPrivateKeysRequest : ( MXKTableViewCellWithButton * ) buttonCell
{
NSString * btnTitle = @ "Request keys" ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ buttonCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
[ buttonCell . mxkButton addTarget : self action : @ selector ( requestCrossSigningPrivateKeys : ) forControlEvents : UIControlEventTouchUpInside ] ;
}
2020-03-27 16:39:11 +00:00
- ( void ) requestCrossSigningPrivateKeys : ( id ) recognizer
2020-03-18 11:20:14 +00:00
{
2020-03-25 09:15:34 +00:00
UIButton * button ;
if ( [ recognizer isKindOfClass : UIButton . class ] )
{
button = ( UIButton * ) recognizer ;
}
button . enabled = NO ;
[ self . mainSession . crypto . crossSigning requestPrivateKeysToDeviceIds : nil success : ^ {
} onPrivateKeysReceived : ^ {
button . enabled = YES ;
[ self loadCrossSigning ] ;
[ self reloadData ] ;
} failure : ^ ( NSError * _Nonnull error ) {
NSLog ( @ "[SecurityVC] requestCrossSigningPrivateKeys: Cannot request cross-signing private keys. Error: %@" , error ) ;
button . enabled = YES ;
} ] ;
2020-03-18 11:20:14 +00:00
}
- ( void ) displayComingSoon
{
[ [ AppDelegate theDelegate ] showAlertWithTitle : nil message : @ "Sorry. This action is not available on Riot-iOS yet. Please use another Matrix client." ] ;
}
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-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 ;
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 ;
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-01-28 20:09:51 +00:00
cell . mxkLabelLeadingConstraint . constant = cell . separatorInset . left ;
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 ;
cell . accessoryType = UITableViewCellAccessoryDisclosureIndicator ;
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 )
{
return [ UIImage imageNamed : @ "encryption_normal" ] ;
}
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 ] ;
textViewCell . mxkTextViewLeadingConstraint . constant = tableView . separatorInset . left ;
textViewCell . mxkTextViewTrailingConstraint . constant = tableView . separatorInset . right ;
textViewCell . mxkTextView . accessibilityIdentifier = nil ;
2020-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
return textViewCell ;
}
- ( 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-01-30 12:14:17 +00:00
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
withText : NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions_description" , @ "Vector" , nil ) ] ;
}
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
withText : NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions_description" , @ "Vector" , nil ) ] ;
}
2020-01-28 20:09:51 +00:00
}
2020-01-29 07:19:48 +00:00
}
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-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
{
MXKTableViewCellWithButton * exportKeysBtnCell = [ tableView dequeueReusableCellWithIdentifier : [ MXKTableViewCellWithButton defaultReuseIdentifier ] ] ;
if ( ! exportKeysBtnCell )
{
exportKeysBtnCell = [ [ MXKTableViewCellWithButton alloc ] init ] ;
}
2020-03-12 10:21:47 +00:00
else
{
exportKeysBtnCell . mxkButton . titleLabel . text = nil ;
exportKeysBtnCell . mxkButton . enabled = YES ;
}
NSString * btnTitle = NSLocalizedStringFromTable ( @ "security_settings_export_keys_manually" , @ "Vector" , nil ) ;
2020-01-29 14:56:06 +00:00
[ exportKeysBtnCell . mxkButton setTitle : btnTitle forState : UIControlStateNormal ] ;
[ exportKeysBtnCell . mxkButton setTitle : btnTitle forState : UIControlStateHighlighted ] ;
[ exportKeysBtnCell . mxkButton setTintColor : ThemeService . shared . theme . tintColor ] ;
exportKeysBtnCell . mxkButton . titleLabel . font = [ UIFont systemFontOfSize : 17 ] ;
2020-03-12 10:21:47 +00:00
2020-01-29 14:56:06 +00:00
[ exportKeysBtnCell . mxkButton removeTarget : self action : nil forControlEvents : UIControlEventTouchUpInside ] ;
2020-03-12 10:21:47 +00:00
[ exportKeysBtnCell . mxkButton addTarget : self action : @ selector ( exportEncryptionKeys : ) forControlEvents : UIControlEventTouchUpInside ] ;
2020-01-29 14:56:06 +00:00
exportKeysBtnCell . mxkButton . accessibilityIdentifier = nil ;
2020-03-12 10:21:47 +00:00
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-01-30 12:14:17 +00:00
case SECTION_CRYPTO _SESSIONS :
return NSLocalizedStringFromTable ( @ "security_settings_crypto_sessions" , @ "Vector" , nil ) ;
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 ) ;
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-23 13:50:01 +00:00
if ( self . mainSession . crypto . crossSigning . canCrossSign )
{
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-01-28 21:36:50 +00:00
2020-01-28 20:09:51 +00:00
# pragma mark - SettingsKeyBackupTableViewSectionDelegate
- ( 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
{
MXKTableViewCellWithButton * cell = [ self . tableView dequeueReusableCellWithIdentifier : [ MXKTableViewCellWithButton defaultReuseIdentifier ] ] ;
if ( ! cell )
{
cell = [ [ MXKTableViewCellWithButton alloc ] init ] ;
}
else
{
// Fix https : // github . com / vector - im / riot - ios / issues / 1354
cell . mxkButton . titleLabel . text = nil ;
2020-01-29 14:56:06 +00:00
cell . mxkButton . enabled = YES ;
2020-01-28 20:09:51 +00:00
}
cell . mxkButton . titleLabel . font = [ UIFont systemFontOfSize : 17 ] ;
[ cell . mxkButton setTintColor : ThemeService . shared . theme . tintColor ] ;
return cell ;
}
- ( void ) settingsKeyBackupTableViewSectionShowKeyBackupSetup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection
{
[ self showKeyBackupSetupFromSignOutFlow : NO ] ;
}
- ( void ) settingsKeyBackup : ( SettingsKeyBackupTableViewSection * ) settingsKeyBackupTableViewSection showKeyBackupRecover : ( MXKeyBackupVersion * ) keyBackupVersion
{
[ self showKeyBackupRecover : keyBackupVersion ] ;
}
- ( 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 ] ;
}
# pragma mark - KeyBackupRecoverCoordinatorBridgePresenter
- ( void ) showKeyBackupRecover : ( MXKeyBackupVersion * ) keyBackupVersion
{
keyBackupRecoverCoordinatorBridgePresenter = [ [ KeyBackupRecoverCoordinatorBridgePresenter alloc ] initWithSession : self . mainSession keyBackupVersion : keyBackupVersion ] ;
[ keyBackupRecoverCoordinatorBridgePresenter presentFrom : self animated : true ] ;
keyBackupRecoverCoordinatorBridgePresenter . delegate = self ;
}
- ( void ) keyBackupRecoverCoordinatorBridgePresenterDidCancel : ( KeyBackupRecoverCoordinatorBridgePresenter * ) bridgePresenter {
[ keyBackupRecoverCoordinatorBridgePresenter dismissWithAnimated : true ] ;
keyBackupRecoverCoordinatorBridgePresenter = nil ;
}
- ( void ) keyBackupRecoverCoordinatorBridgePresenterDidRecover : ( KeyBackupRecoverCoordinatorBridgePresenter * ) bridgePresenter {
[ keyBackupRecoverCoordinatorBridgePresenter dismissWithAnimated : true ] ;
keyBackupRecoverCoordinatorBridgePresenter = nil ;
}
@ end