2017-01-19 21:15:47 +08:00
//
// S e t t i n g s T a b l e V i e w C o n t r o l l e r . s w i f t
// p a s s
//
// C r e a t e d b y M i n g s h e n S u n o n 1 8 / 1 / 2 0 1 7 .
// C o p y r i g h t © 2 0 1 7 B o b S u n . A l l r i g h t s r e s e r v e d .
//
import UIKit
import SVProgressHUD
import CoreData
2017-02-07 20:24:58 +08:00
import PasscodeLock
2017-05-26 09:25:36 -07:00
import LocalAuthentication
2017-06-13 11:42:49 +08:00
import passKit
2017-01-19 21:15:47 +08:00
class SettingsTableViewController : UITableViewController {
2017-02-07 20:24:58 +08:00
2017-03-02 16:51:46 +08:00
lazy var touchIDSwitch : UISwitch = {
let uiSwitch = UISwitch ( frame : CGRect . zero )
uiSwitch . onTintColor = Globals . blue
uiSwitch . addTarget ( self , action : #selector ( touchIDSwitchAction ) , for : UIControlEvents . valueChanged )
return uiSwitch
} ( )
2017-02-07 20:57:06 +08:00
2017-01-22 01:42:36 +08:00
@IBOutlet weak var pgpKeyTableViewCell : UITableViewCell !
2017-02-07 17:56:31 +08:00
@IBOutlet weak var touchIDTableViewCell : UITableViewCell !
@IBOutlet weak var passcodeTableViewCell : UITableViewCell !
2017-02-21 13:07:14 +08:00
@IBOutlet weak var passwordRepositoryTableViewCell : UITableViewCell !
2017-03-16 22:39:03 -07:00
let passwordStore = PasswordStore . shared
2017-06-13 11:42:49 +08:00
var passcodeLockConfig = PasscodeLockConfiguration . shared
2017-03-16 22:39:03 -07:00
2017-02-17 13:44:25 +08:00
@IBAction func cancelPGPKey ( segue : UIStoryboardSegue ) {
2017-01-19 21:15:47 +08:00
}
2017-02-17 13:44:25 +08:00
@IBAction func savePGPKey ( segue : UIStoryboardSegue ) {
2017-02-09 21:45:31 +08:00
if let controller = segue . source as ? PGPKeySettingTableViewController {
2017-06-13 11:42:49 +08:00
SharedDefaults [ . pgpPrivateKeyURL ] = URL ( string : controller . pgpPrivateKeyURLTextField . text ! )
SharedDefaults [ . pgpPublicKeyURL ] = URL ( string : controller . pgpPublicKeyURLTextField . text ! )
if SharedDefaults [ . isRememberPassphraseOn ] {
2017-04-25 20:13:59 -07:00
self . passwordStore . pgpKeyPassphrase = controller . pgpPassphrase
}
2017-06-13 11:42:49 +08:00
SharedDefaults [ . pgpKeySource ] = " url "
2017-02-17 13:44:25 +08:00
2017-02-17 14:58:27 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
SVProgressHUD . setDefaultStyle ( . light )
SVProgressHUD . show ( withStatus : " Fetching PGP Key " )
DispatchQueue . global ( qos : . userInitiated ) . async { [ unowned self ] in
do {
2017-06-13 11:42:49 +08:00
try self . passwordStore . initPGPKey ( from : SharedDefaults [ . pgpPublicKeyURL ] ! , keyType : . public )
try self . passwordStore . initPGPKey ( from : SharedDefaults [ . pgpPrivateKeyURL ] ! , keyType : . secret )
2017-02-17 14:58:27 +08:00
DispatchQueue . main . async {
2017-03-16 22:39:03 -07:00
self . pgpKeyTableViewCell . detailTextLabel ? . text = self . passwordStore . pgpKeyID
2017-02-20 22:02:49 +08:00
SVProgressHUD . showSuccess ( withStatus : " Success " )
2017-02-17 14:58:27 +08:00
SVProgressHUD . dismiss ( withDelay : 1 )
2017-04-23 10:23:54 -07:00
Utils . alert ( title : " Remember to Remove the Key " , message : " Remember to remove the key from the server. " , controller : self , completion : nil )
2017-02-17 14:58:27 +08:00
}
} catch {
DispatchQueue . main . async {
self . pgpKeyTableViewCell . detailTextLabel ? . text = " Not Set "
2017-03-16 23:12:31 -07:00
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-01-22 01:42:36 +08:00
}
}
2017-02-17 14:58:27 +08:00
}
2017-01-22 01:42:36 +08:00
2017-02-17 13:44:25 +08:00
} else if let controller = segue . source as ? PGPKeyArmorSettingTableViewController {
2017-06-13 11:42:49 +08:00
SharedDefaults [ . pgpKeySource ] = " armor "
if SharedDefaults [ . isRememberPassphraseOn ] {
2017-04-25 20:13:59 -07:00
self . passwordStore . pgpKeyPassphrase = controller . pgpPassphrase
2017-02-28 12:25:52 +08:00
}
2017-02-19 22:10:36 +08:00
2017-06-13 11:42:49 +08:00
SharedDefaults [ . pgpPublicKeyArmor ] = controller . armorPublicKeyTextView . text !
SharedDefaults [ . pgpPrivateKeyArmor ] = controller . armorPrivateKeyTextView . text !
2017-02-17 13:44:25 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
SVProgressHUD . setDefaultStyle ( . light )
SVProgressHUD . show ( withStatus : " Fetching PGP Key " )
DispatchQueue . global ( qos : . userInitiated ) . async { [ unowned self ] in
do {
2017-03-16 22:39:03 -07:00
try self . passwordStore . initPGPKey ( with : controller . armorPublicKeyTextView . text , keyType : . public )
try self . passwordStore . initPGPKey ( with : controller . armorPrivateKeyTextView . text , keyType : . secret )
2017-02-17 13:44:25 +08:00
DispatchQueue . main . async {
2017-03-16 22:39:03 -07:00
self . pgpKeyTableViewCell . detailTextLabel ? . text = self . passwordStore . pgpKeyID
2017-02-20 22:02:49 +08:00
SVProgressHUD . showSuccess ( withStatus : " Success " )
2017-02-17 13:44:25 +08:00
SVProgressHUD . dismiss ( withDelay : 1 )
}
} catch {
DispatchQueue . main . async {
self . pgpKeyTableViewCell . detailTextLabel ? . text = " Not Set "
2017-03-16 23:12:31 -07:00
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-02-17 13:44:25 +08:00
}
}
}
2017-01-19 21:15:47 +08:00
}
}
2017-06-07 21:11:01 +08:00
private func saveImportedPGPKey ( ) {
// l o a d k e y s
2017-06-13 11:42:49 +08:00
SharedDefaults [ . pgpKeySource ] = " file "
2017-06-07 21:11:01 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
SVProgressHUD . setDefaultStyle ( . light )
SVProgressHUD . show ( withStatus : " Fetching PGP Key " )
2017-06-14 20:22:15 +08:00
passwordStore . pgpKeyImportFromFileSharing ( )
2017-06-07 21:11:01 +08:00
DispatchQueue . global ( qos : . userInitiated ) . async { [ unowned self ] in
do {
try self . passwordStore . initPGPKeys ( )
DispatchQueue . main . async {
self . pgpKeyTableViewCell . detailTextLabel ? . text = self . passwordStore . pgpKeyID
2017-06-14 20:22:15 +08:00
SVProgressHUD . showSuccess ( withStatus : " Imported " )
2017-06-07 21:11:01 +08:00
SVProgressHUD . dismiss ( withDelay : 1 )
}
} catch {
DispatchQueue . main . async {
self . pgpKeyTableViewCell . detailTextLabel ? . text = " Not Set "
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
}
}
}
}
2017-02-21 13:07:14 +08:00
@IBAction func cancelGitServerSetting ( segue : UIStoryboardSegue ) {
}
@IBAction func saveGitServerSetting ( segue : UIStoryboardSegue ) {
2017-06-13 11:42:49 +08:00
self . passwordRepositoryTableViewCell . detailTextLabel ? . text = SharedDefaults [ . gitURL ] ? . host
2017-02-21 13:07:14 +08:00
}
2017-05-26 09:25:36 -07:00
override func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
// S e c u r i t y s e c t i o n , h i d e T o u c h I D i f t h e d e v i c e d o e s n ' t s u p p o r t
if section = = 1 {
if hasTouchID ( ) {
return 2
} else {
return 1
}
}
return super . tableView ( tableView , numberOfRowsInSection : section )
}
2017-01-19 21:15:47 +08:00
override func viewDidLoad ( ) {
super . viewDidLoad ( )
2017-03-18 00:18:55 +08:00
NotificationCenter . default . addObserver ( self , selector : #selector ( SettingsTableViewController . actOnPasswordStoreErasedNotification ) , name : . passwordStoreErased , object : nil )
2017-06-13 11:42:49 +08:00
self . passwordRepositoryTableViewCell . detailTextLabel ? . text = SharedDefaults [ . gitURL ] ? . host
2017-02-07 17:56:31 +08:00
touchIDTableViewCell . accessoryView = touchIDSwitch
2017-02-26 20:59:27 +08:00
setPGPKeyTableViewCellDetailText ( )
setPasswordRepositoryTableViewCellDetailText ( )
2017-05-14 20:52:24 +08:00
setPasscodeLockTouchIDCells ( )
2017-02-26 20:59:27 +08:00
}
2017-05-26 09:25:36 -07:00
private func hasTouchID ( ) -> Bool {
let context = LAContext ( )
var error : NSError ?
if context . canEvaluatePolicy ( LAPolicy . deviceOwnerAuthenticationWithBiometrics , error : & error ) {
return true
} else {
switch error ! . code {
case LAError . Code . touchIDNotEnrolled . rawValue :
return true
case LAError . Code . passcodeNotSet . rawValue :
return true
default :
return false
}
}
}
private func isTouchIDEnabled ( ) -> Bool {
let context = LAContext ( )
return context . canEvaluatePolicy ( . deviceOwnerAuthenticationWithBiometrics , error : nil )
}
2017-05-14 20:52:24 +08:00
private func setPasscodeLockTouchIDCells ( ) {
2017-06-14 14:16:26 +08:00
if PasscodeLockConfiguration . shared . repository . hasPasscode {
2017-02-26 20:59:27 +08:00
self . passcodeTableViewCell . detailTextLabel ? . text = " On "
2017-06-13 11:42:49 +08:00
passcodeLockConfig . isTouchIDAllowed = true
touchIDSwitch . isOn = SharedDefaults [ . isTouchIDOn ]
2017-02-26 20:59:27 +08:00
} else {
self . passcodeTableViewCell . detailTextLabel ? . text = " Off "
2017-06-13 11:42:49 +08:00
passcodeLockConfig . isTouchIDAllowed = false
SharedDefaults [ . isTouchIDOn ] = false
touchIDSwitch . isOn = SharedDefaults [ . isTouchIDOn ]
2017-02-26 20:59:27 +08:00
}
}
private func setPGPKeyTableViewCellDetailText ( ) {
2017-03-16 22:39:03 -07:00
if let pgpKeyID = self . passwordStore . pgpKeyID {
2017-03-16 22:06:39 -07:00
pgpKeyTableViewCell . detailTextLabel ? . text = pgpKeyID
2017-02-09 11:31:49 +08:00
} else {
2017-03-16 22:06:39 -07:00
pgpKeyTableViewCell . detailTextLabel ? . text = " Not Set "
2017-02-09 11:31:49 +08:00
}
2017-02-26 20:59:27 +08:00
}
private func setPasswordRepositoryTableViewCellDetailText ( ) {
2017-06-13 11:42:49 +08:00
if SharedDefaults [ . gitURL ] = = nil {
2017-02-26 20:59:27 +08:00
passwordRepositoryTableViewCell . detailTextLabel ? . text = " Not Set "
} else {
2017-06-13 11:42:49 +08:00
passwordRepositoryTableViewCell . detailTextLabel ? . text = SharedDefaults [ . gitURL ] ! . host
2017-02-26 20:59:27 +08:00
}
}
2017-02-09 11:31:49 +08:00
func actOnPasswordStoreErasedNotification ( ) {
2017-02-26 20:59:27 +08:00
setPGPKeyTableViewCellDetailText ( )
setPasswordRepositoryTableViewCellDetailText ( )
2017-05-14 20:52:24 +08:00
setPasscodeLockTouchIDCells ( )
2017-02-09 11:31:49 +08:00
let appDelegate = UIApplication . shared . delegate as ! AppDelegate
2017-06-13 11:42:49 +08:00
appDelegate . passcodeLockPresenter = PasscodeLockPresenter ( mainWindow : appDelegate . window , configuration : passcodeLockConfig )
2017-02-09 11:31:49 +08:00
}
2017-02-07 17:56:31 +08:00
override func tableView ( _ tableView : UITableView , didSelectRowAt indexPath : IndexPath ) {
if tableView . cellForRow ( at : indexPath ) = = passcodeTableViewCell {
2017-06-13 11:42:49 +08:00
if SharedDefaults [ . passcodeKey ] != nil {
2017-02-07 20:24:58 +08:00
showPasscodeActionSheet ( )
} else {
setPasscodeLock ( )
}
2017-02-17 13:44:25 +08:00
} else if tableView . cellForRow ( at : indexPath ) = = pgpKeyTableViewCell {
showPGPKeyActionSheet ( )
2017-02-07 17:56:31 +08:00
}
2017-02-17 13:44:25 +08:00
tableView . deselectRow ( at : indexPath , animated : true )
2017-02-07 16:45:14 +08:00
}
2017-02-07 17:56:31 +08:00
func touchIDSwitchAction ( uiSwitch : UISwitch ) {
2017-06-13 11:42:49 +08:00
if ! passcodeLockConfig . isTouchIDAllowed || ! isTouchIDEnabled ( ) {
2017-05-14 20:52:24 +08:00
// s w i t c h o f f
2017-05-26 09:25:36 -07:00
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + . milliseconds ( 500 ) ) {
2017-06-13 11:42:49 +08:00
uiSwitch . isOn = SharedDefaults [ . isTouchIDOn ] // f a l s e
2017-05-26 09:25:36 -07:00
Utils . alert ( title : " Notice " , message : " Please enable Touch ID and set the passcode lock first. " , controller : self , completion : nil )
}
2017-02-07 17:56:31 +08:00
} else {
2017-06-13 11:42:49 +08:00
SharedDefaults [ . isTouchIDOn ] = uiSwitch . isOn
2017-02-07 17:56:31 +08:00
}
2017-02-08 14:53:07 +08:00
let appDelegate = UIApplication . shared . delegate as ! AppDelegate
2017-06-13 11:42:49 +08:00
appDelegate . passcodeLockPresenter = PasscodeLockPresenter ( mainWindow : appDelegate . window , configuration : passcodeLockConfig )
2017-02-07 17:56:31 +08:00
}
2017-02-17 13:44:25 +08:00
func showPGPKeyActionSheet ( ) {
let optionMenu = UIAlertController ( title : nil , message : nil , preferredStyle : . actionSheet )
var urlActionTitle = " Download from URL "
var armorActionTitle = " ASCII-Armor Encrypted Key "
2017-06-14 20:22:15 +08:00
var fileActionTitle = " iTunes File Sharing "
2017-02-17 13:44:25 +08:00
2017-06-13 11:42:49 +08:00
if SharedDefaults [ . pgpKeySource ] = = " url " {
2017-02-17 13:44:25 +08:00
urlActionTitle = " ✓ \( urlActionTitle ) "
2017-06-13 11:42:49 +08:00
} else if SharedDefaults [ . pgpKeySource ] = = " armor " {
2017-02-17 13:44:25 +08:00
armorActionTitle = " ✓ \( armorActionTitle ) "
2017-06-13 11:42:49 +08:00
} else if SharedDefaults [ . pgpKeySource ] = = " file " {
2017-02-24 17:59:04 +03:00
fileActionTitle = " ✓ \( fileActionTitle ) "
2017-02-17 13:44:25 +08:00
}
let urlAction = UIAlertAction ( title : urlActionTitle , style : . default ) { _ in
self . performSegue ( withIdentifier : " setPGPKeyByURLSegue " , sender : self )
}
let armorAction = UIAlertAction ( title : armorActionTitle , style : . default ) { _ in
self . performSegue ( withIdentifier : " setPGPKeyByASCIISegue " , sender : self )
}
let cancelAction = UIAlertAction ( title : " Cancel " , style : . cancel , handler : nil )
optionMenu . addAction ( urlAction )
optionMenu . addAction ( armorAction )
2017-02-24 17:59:04 +03:00
2017-06-14 20:22:15 +08:00
if passwordStore . pgpKeyExists ( inFileSharing : true ) {
fileActionTitle . append ( " (Import) " )
2017-02-24 17:59:04 +03:00
let fileAction = UIAlertAction ( title : fileActionTitle , style : . default ) { _ in
2017-06-07 21:11:01 +08:00
// p a s s p h r a s e r e l a t e d
let savePassphraseAlert = UIAlertController ( title : " Passphrase " , message : " Do you want to save the passphrase for later decryption? " , preferredStyle : UIAlertControllerStyle . alert )
// n o
savePassphraseAlert . addAction ( UIAlertAction ( title : " No " , style : UIAlertActionStyle . default ) { _ in
self . passwordStore . pgpKeyPassphrase = nil
2017-06-13 11:42:49 +08:00
SharedDefaults [ . isRememberPassphraseOn ] = false
2017-06-07 21:11:01 +08:00
self . saveImportedPGPKey ( )
} )
// y e s
savePassphraseAlert . addAction ( UIAlertAction ( title : " Yes " , style : UIAlertActionStyle . destructive ) { _ in
// a s k f o r t h e p a s s p h r a s e
let alert = UIAlertController ( title : " Passphrase " , message : " Please fill in the passphrase of your PGP secret key. " , preferredStyle : UIAlertControllerStyle . alert )
alert . addAction ( UIAlertAction ( title : " OK " , style : UIAlertActionStyle . default , handler : { _ in
self . passwordStore . pgpKeyPassphrase = alert . textFields ? . first ? . text
2017-06-13 11:42:49 +08:00
SharedDefaults [ . isRememberPassphraseOn ] = true
2017-06-07 21:11:01 +08:00
self . saveImportedPGPKey ( )
} ) )
alert . addTextField ( configurationHandler : { ( textField : UITextField ! ) in
textField . text = " "
textField . isSecureTextEntry = true
} )
self . present ( alert , animated : true , completion : nil )
} )
self . present ( savePassphraseAlert , animated : true , completion : nil )
2017-02-24 17:59:04 +03:00
}
2017-06-07 16:54:54 +08:00
optionMenu . addAction ( fileAction )
} else {
2017-06-14 20:22:15 +08:00
fileActionTitle . append ( " (Tips) " )
let fileAction = UIAlertAction ( title : fileActionTitle , style : . default ) { _ in
let title = " Tips "
let message = " Copy your public and private keys to Pass with names \" gpg_key.pub \" and \" gpg_key \" (without quotes) via iTunes. Then come back and click \" iTunes File Sharing \" to finish. "
2017-06-07 16:54:54 +08:00
Utils . alert ( title : title , message : message , controller : self )
}
2017-02-24 17:59:04 +03:00
optionMenu . addAction ( fileAction )
}
2017-02-17 13:44:25 +08:00
2017-06-07 16:54:54 +08:00
2017-06-13 11:42:49 +08:00
if SharedDefaults [ . pgpKeySource ] != nil {
2017-02-17 13:44:25 +08:00
let deleteAction = UIAlertAction ( title : " Remove PGP Keys " , style : . destructive ) { _ in
2017-06-03 18:12:33 -07:00
self . passwordStore . removePGPKeys ( )
2017-02-17 13:44:25 +08:00
self . pgpKeyTableViewCell . detailTextLabel ? . text = " Not Set "
}
optionMenu . addAction ( deleteAction )
}
optionMenu . addAction ( cancelAction )
2017-02-22 18:18:59 +08:00
optionMenu . popoverPresentationController ? . sourceView = pgpKeyTableViewCell
optionMenu . popoverPresentationController ? . sourceRect = pgpKeyTableViewCell . bounds
2017-02-17 13:44:25 +08:00
self . present ( optionMenu , animated : true , completion : nil )
}
2017-02-07 17:56:31 +08:00
func showPasscodeActionSheet ( ) {
2017-06-13 11:42:49 +08:00
let passcodeChangeViewController = PasscodeLockViewController ( state : . change , configuration : passcodeLockConfig )
let passcodeRemoveViewController = PasscodeLockViewController ( state : . remove , configuration : passcodeLockConfig )
2017-02-07 20:24:58 +08:00
2017-02-07 17:56:31 +08:00
let optionMenu = UIAlertController ( title : nil , message : nil , preferredStyle : . actionSheet )
2017-02-10 00:56:12 +08:00
let removePasscodeAction = UIAlertAction ( title : " Remove Passcode " , style : . destructive ) { [ weak self ] _ in
2017-02-07 20:24:58 +08:00
passcodeRemoveViewController . successCallback = { _ in
2017-05-14 20:52:24 +08:00
self ? . setPasscodeLockTouchIDCells ( )
2017-02-08 16:29:03 +08:00
let appDelegate = UIApplication . shared . delegate as ! AppDelegate
2017-06-13 11:42:49 +08:00
appDelegate . passcodeLockPresenter = PasscodeLockPresenter ( mainWindow : appDelegate . window , configuration : ( self ? . passcodeLockConfig ) ! )
2017-02-07 20:24:58 +08:00
}
2017-02-10 00:56:12 +08:00
self ? . present ( passcodeRemoveViewController , animated : true , completion : nil )
2017-02-07 20:24:58 +08:00
}
2017-02-10 00:56:12 +08:00
let changePasscodeAction = UIAlertAction ( title : " Change Passcode " , style : . default ) { [ weak self ] _ in
self ? . present ( passcodeChangeViewController , animated : true , completion : nil )
2017-02-07 20:24:58 +08:00
}
2017-02-07 17:56:31 +08:00
let cancelAction = UIAlertAction ( title : " Cancel " , style : . cancel , handler : nil )
optionMenu . addAction ( removePasscodeAction )
optionMenu . addAction ( changePasscodeAction )
optionMenu . addAction ( cancelAction )
2017-02-22 18:18:59 +08:00
optionMenu . popoverPresentationController ? . sourceView = passcodeTableViewCell
optionMenu . popoverPresentationController ? . sourceRect = passcodeTableViewCell . bounds
2017-02-07 17:56:31 +08:00
self . present ( optionMenu , animated : true , completion : nil )
}
2017-02-07 20:24:58 +08:00
func setPasscodeLock ( ) {
2017-06-13 11:42:49 +08:00
let passcodeSetViewController = PasscodeLockViewController ( state : . set , configuration : passcodeLockConfig )
2017-02-07 20:24:58 +08:00
passcodeSetViewController . successCallback = { _ in
2017-05-14 20:52:24 +08:00
self . setPasscodeLockTouchIDCells ( )
2017-02-07 20:24:58 +08:00
}
present ( passcodeSetViewController , animated : true , completion : nil )
}
2017-01-19 21:15:47 +08:00
}