Add switch to turn on/off remembering passphrase
If the switch is on, users need to type passphrase of secret key once. The key will be stored in the Keychain. If the switch is off, users have to fill in passphrase for each decryption including show password detail and long press to copy.
This commit is contained in:
parent
1c45766b96
commit
fa512e6c86
10 changed files with 138 additions and 37 deletions
|
|
@ -11,7 +11,21 @@ import SwiftyUserDefaults
|
|||
|
||||
class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||
|
||||
let hideUnknownSwitch = UISwitch()
|
||||
let hideUnknownSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
uiSwitch.sizeToFit()
|
||||
uiSwitch.addTarget(self, action: #selector(hideUnknownSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||
return uiSwitch
|
||||
}()
|
||||
let rememberPassphraseSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
uiSwitch.sizeToFit()
|
||||
uiSwitch.addTarget(self, action: #selector(rememberPassphraseSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||
uiSwitch.isOn = Defaults[.isRememberPassphraseOn]
|
||||
return uiSwitch
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
navigationItemTitle = "General"
|
||||
|
|
@ -20,7 +34,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
[[.title: "About Repository", .action: "segue", .link: "showAboutRepositorySegue"],],
|
||||
|
||||
// section 1
|
||||
[[.title: "Hide Unknown Fields", .action: "none",],],
|
||||
[
|
||||
[.title: "Remember Phassphrase", .action: "none",],
|
||||
[.title: "Hide Unknown Fields", .action: "none",],
|
||||
],
|
||||
|
||||
]
|
||||
super.viewDidLoad()
|
||||
|
|
@ -31,8 +48,6 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||
if cell.textLabel?.text == "Hide Unknown Fields" {
|
||||
cell.accessoryType = .none
|
||||
hideUnknownSwitch.onTintColor = UIColor(displayP3Red: 0, green: 122.0/255, blue: 1, alpha: 1)
|
||||
hideUnknownSwitch.sizeToFit()
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
|
|
@ -42,8 +57,11 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
accessoryView.addSubview(hideUnknownSwitch)
|
||||
cell.accessoryView = accessoryView
|
||||
cell.selectionStyle = .none
|
||||
hideUnknownSwitch.addTarget(self, action: #selector(hideUnknownSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||
hideUnknownSwitch.isOn = Defaults[.isHideUnknownOn]
|
||||
} else if cell.textLabel?.text == "Remember Phassphrase" {
|
||||
cell.accessoryType = .none
|
||||
cell.selectionStyle = .none
|
||||
cell.accessoryView = rememberPassphraseSwitch
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
|
@ -58,4 +76,11 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
Defaults[.isHideUnknownOn] = hideUnknownSwitch.isOn
|
||||
}
|
||||
|
||||
func rememberPassphraseSwitchAction(_ sender: Any?) {
|
||||
Defaults[.isRememberPassphraseOn] = rememberPassphraseSwitch.isOn
|
||||
if rememberPassphraseSwitch.isOn == false {
|
||||
PasswordStore.shared.pgpKeyPassphrase = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,25 @@ class PGPKeyArmorSettingTableViewController: UITableViewController {
|
|||
pgpPassphrase = PasswordStore.shared.pgpKeyPassphrase
|
||||
}
|
||||
|
||||
private func createSavePassphraseAlert() -> UIAlertController {
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.destructive) {_ in
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
return savePassphraseAlert
|
||||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
let alert = UIAlertController(title: "Phassphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
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.pgpPassphrase = alert.textFields?.first?.text
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
let savePassphraseAlert = self.createSavePassphraseAlert()
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
let alert = UIAlertController(title: "Phassphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
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.pgpPassphrase = alert.textFields?.first?.text
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,26 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
var passwordCategoryText = ""
|
||||
var password: Password?
|
||||
var passwordImage: UIImage?
|
||||
|
||||
let indicatorLable: UILabel = {
|
||||
let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 21))
|
||||
label.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height * 0.382 + 22)
|
||||
label.backgroundColor = UIColor.clear
|
||||
label.textColor = UIColor.gray
|
||||
label.text = "decrypting password"
|
||||
label.textAlignment = .center
|
||||
label.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||
return label
|
||||
}()
|
||||
|
||||
let indicator: UIActivityIndicatorView = {
|
||||
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
|
||||
indicator.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height * 0.382)
|
||||
return indicator
|
||||
}()
|
||||
|
||||
let editUIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(pressEdit(_:)))
|
||||
|
||||
|
||||
struct TableCell {
|
||||
var title: String
|
||||
|
|
@ -54,19 +74,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
tableView.contentInset = UIEdgeInsetsMake(-36, 0, 0, 0);
|
||||
tableView.rowHeight = UITableViewAutomaticDimension
|
||||
tableView.estimatedRowHeight = 52
|
||||
let indicatorLable = UILabel(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 21))
|
||||
indicatorLable.center = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height * 0.382 + 22)
|
||||
indicatorLable.backgroundColor = UIColor.clear
|
||||
indicatorLable.textColor = UIColor.gray
|
||||
indicatorLable.text = "decrypting password"
|
||||
indicatorLable.textAlignment = .center
|
||||
indicatorLable.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
|
||||
indicator.center = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height * 0.382)
|
||||
|
||||
|
||||
indicator.startAnimating()
|
||||
tableView.addSubview(indicator)
|
||||
tableView.addSubview(indicatorLable)
|
||||
let editUIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(pressEdit(_:)))
|
||||
editUIBarButtonItem.isEnabled = false
|
||||
navigationItem.rightBarButtonItem = editUIBarButtonItem
|
||||
|
||||
|
|
@ -75,10 +87,33 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
passwordImage = image
|
||||
}
|
||||
|
||||
var passphrase = ""
|
||||
if Defaults[.isRememberPassphraseOn] && PasswordStore.shared.pgpKeyPassphrase != nil {
|
||||
passphrase = PasswordStore.shared.pgpKeyPassphrase!
|
||||
self.decryptThenShowPassword(passphrase: passphrase)
|
||||
} else {
|
||||
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
|
||||
passphrase = alert.textFields!.first!.text!
|
||||
self.decryptThenShowPassword(passphrase: passphrase)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = ""
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func decryptThenShowPassword(passphrase: String) {
|
||||
if Defaults[.isRememberPassphraseOn] {
|
||||
PasswordStore.shared.pgpKeyPassphrase = passphrase
|
||||
}
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
self.password = try self.passwordEntity!.decrypt()!
|
||||
self.password = try self.passwordEntity!.decrypt(passphrase: passphrase)!
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
let alert = UIAlertController(title: "Cannot Show Password", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
|
||||
|
|
@ -89,19 +124,23 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let password = self.password!
|
||||
self.setTableData()
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.tableView.reloadData()
|
||||
indicator.stopAnimating()
|
||||
indicatorLable.isHidden = true
|
||||
editUIBarButtonItem.isEnabled = true
|
||||
if let url = password.getURL() {
|
||||
if self?.passwordEntity?.image == nil{
|
||||
self?.updatePasswordImage(url: url)
|
||||
}
|
||||
}
|
||||
self?.showPassword(password: password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showPassword(password: Password) {
|
||||
setTableData()
|
||||
self.tableView.reloadData()
|
||||
indicator.stopAnimating()
|
||||
indicatorLable.isHidden = true
|
||||
editUIBarButtonItem.isEnabled = true
|
||||
if let url = password.getURL() {
|
||||
if self.passwordEntity?.image == nil{
|
||||
self.updatePasswordImage(url: url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,13 +190,33 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
password = passwordEntities![index]
|
||||
}
|
||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
||||
var passphrase = ""
|
||||
if Defaults[.isRememberPassphraseOn] && PasswordStore.shared.pgpKeyPassphrase != nil {
|
||||
passphrase = PasswordStore.shared.pgpKeyPassphrase!
|
||||
self.decryptThenCopyPassword(passwordEntity: password, passphrase: passphrase)
|
||||
} else {
|
||||
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
|
||||
passphrase = alert.textFields!.first!.text!
|
||||
self.decryptThenCopyPassword(passwordEntity: password, passphrase: passphrase)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = ""
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func decryptThenCopyPassword(passwordEntity: PasswordEntity, passphrase: String) {
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.dark)
|
||||
SVProgressHUD.show(withStatus: "Decrypting")
|
||||
DispatchQueue.global(qos: .userInteractive).async {
|
||||
var decryptedPassword: Password?
|
||||
do {
|
||||
decryptedPassword = try password.decrypt()!
|
||||
decryptedPassword = try passwordEntity.decrypt(passphrase: passphrase)!
|
||||
DispatchQueue.main.async {
|
||||
Utils.copyToPasteboard(textToCopy: decryptedPassword?.password)
|
||||
SVProgressHUD.showSuccess(withStatus: "Password Copied")
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ class SettingsTableViewController: UITableViewController {
|
|||
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
|
||||
Defaults[.pgpKeySource] = "armor"
|
||||
PasswordStore.shared.pgpKeyPassphrase = controller.pgpPassphrase
|
||||
Utils.addPasswrodToKeychain(name: "pgpKeyPassphrase", password: controller.pgpPassphrase!)
|
||||
if Defaults[.isRememberPassphraseOn] {
|
||||
Utils.addPasswrodToKeychain(name: "pgpKeyPassphrase", password: controller.pgpPassphrase!)
|
||||
}
|
||||
|
||||
Defaults[.pgpPublicKeyArmor] = controller.armorPublicKeyTextView.text!
|
||||
Defaults[.pgpPrivateKeyArmor] = controller.armorPrivateKeyTextView.text!
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ extension DefaultsKeys {
|
|||
static let passcodeKey = DefaultsKey<String?>("passcodeKey")
|
||||
|
||||
static let isHideUnknownOn = DefaultsKey<Bool>("isHideUnknownOn")
|
||||
static let isRememberPassphraseOn = DefaultsKey<Bool>("isRememberPassphraseOn")
|
||||
|
||||
static let passwordGenerationMethod = DefaultsKey<String>("passwordGenerationMethod")
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class Utils {
|
|||
return nil
|
||||
}
|
||||
|
||||
static func addPasswrodToKeychain(name: String, password: String) {
|
||||
static func addPasswrodToKeychain(name: String, password: String?) {
|
||||
let keychain = Keychain(service: "me.mssun.passforios")
|
||||
keychain[name] = password
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import Foundation
|
|||
import SwiftyUserDefaults
|
||||
|
||||
extension PasswordEntity {
|
||||
func decrypt() throws -> Password? {
|
||||
func decrypt(passphrase: String) throws -> Password? {
|
||||
var password: Password?
|
||||
let encryptedDataPath = URL(fileURLWithPath: "\(Globals.repositoryPath)/\(rawPath!)")
|
||||
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
||||
let decryptedData = try PasswordStore.shared.pgp.decryptData(encryptedData, passphrase: PasswordStore.shared.pgpKeyPassphrase!)
|
||||
let decryptedData = try PasswordStore.shared.pgp.decryptData(encryptedData, passphrase: passphrase)
|
||||
let plainText = String(data: decryptedData, encoding: .ascii) ?? ""
|
||||
password = Password(name: name!, plainText: plainText)
|
||||
return password
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class PasswordStore {
|
|||
|
||||
var pgpKeyPassphrase: String? {
|
||||
set {
|
||||
Utils.addPasswrodToKeychain(name: "pgpKeyPassphrase", password: newValue!)
|
||||
Utils.addPasswrodToKeychain(name: "pgpKeyPassphrase", password: newValue)
|
||||
}
|
||||
get {
|
||||
return Utils.getPasswordFromKeychain(name: "pgpKeyPassphrase")
|
||||
|
|
@ -111,7 +111,7 @@ class PasswordStore {
|
|||
}
|
||||
var gitRepositoryPassword: String? {
|
||||
set {
|
||||
Utils.addPasswrodToKeychain(name: "gitRepositoryPassword", password: newValue!)
|
||||
Utils.addPasswrodToKeychain(name: "gitRepositoryPassword", password: newValue)
|
||||
}
|
||||
get {
|
||||
return Utils.getPasswordFromKeychain(name: "gitRepositoryPassword")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue