From f2edc2ffaac703ed950f6ff82488381ba04c0007 Mon Sep 17 00:00:00 2001 From: Yishi Lin Date: Fri, 3 Mar 2017 17:12:25 +0800 Subject: [PATCH] Support hiding one time password related fields. - Add a switch to turn on/off one time password related fields. - Improve how we show the additional information --- .../GeneralSettingsTableViewController.swift | 32 ++++++++++ .../PasswordDetailTableViewController.swift | 30 +++++----- pass/Helpers/DefaultsKeys.swift | 1 + pass/Models/Password.swift | 58 +++++++++---------- 4 files changed, 76 insertions(+), 45 deletions(-) diff --git a/pass/Controllers/GeneralSettingsTableViewController.swift b/pass/Controllers/GeneralSettingsTableViewController.swift index ff759eb..e851285 100644 --- a/pass/Controllers/GeneralSettingsTableViewController.swift +++ b/pass/Controllers/GeneralSettingsTableViewController.swift @@ -19,6 +19,14 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { return uiSwitch }() + let hideOTPSwitch: UISwitch = { + let uiSwitch = UISwitch() + uiSwitch.onTintColor = Globals.blue + uiSwitch.sizeToFit() + uiSwitch.addTarget(self, action: #selector(hideOTPSwitchAction(_:)), for: UIControlEvents.valueChanged) + return uiSwitch + }() + let rememberPassphraseSwitch: UISwitch = { let uiSwitch = UISwitch() uiSwitch.onTintColor = Globals.blue @@ -50,6 +58,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { [ [.title: "Show Folder", .action: "none",], [.title: "Hide Unknown Fields", .action: "none",], + [.title: "Hide One Time Password Fields", .action: "none",], ], ] @@ -72,6 +81,18 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { cell.accessoryView = accessoryView cell.selectionStyle = .none hideUnknownSwitch.isOn = Defaults[.isHideUnknownOn] + case "Hide One Time Password Fields": + cell.accessoryType = .none + let detailButton = UIButton(type: .detailDisclosure) + hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height) + detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height) + detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideOTPSwitchDetailButton(_:)), for: UIControlEvents.touchDown) + let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width+10, height: hideOTPSwitch.bounds.height)) + accessoryView.addSubview(detailButton) + accessoryView.addSubview(hideOTPSwitch) + cell.accessoryView = accessoryView + cell.selectionStyle = .none + hideOTPSwitch.isOn = Defaults[.isHideOTPOn] case "Remember Phassphrase": cell.accessoryType = .none cell.selectionStyle = .none @@ -91,10 +112,21 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } + func tapHideOTPSwitchDetailButton(_ sender: Any?) { + let keywordsString = Password.otpKeywords.joined(separator: ",") + let alertMessage = "Turn on this switch to hide the fields related to one time passwords (i.e., \(keywordsString))." + let alertTitle = "Hide One Time Password Fields" + Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) + } + func hideUnknownSwitchAction(_ sender: Any?) { Defaults[.isHideUnknownOn] = hideUnknownSwitch.isOn } + func hideOTPSwitchAction(_ sender: Any?) { + Defaults[.isHideOTPOn] = hideOTPSwitch.isOn + } + func rememberPassphraseSwitchAction(_ sender: Any?) { Defaults[.isRememberPassphraseOn] = rememberPassphraseSwitch.isOn if rememberPassphraseSwitch.isOn == false { diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift index b3578b0..93a7be0 100644 --- a/pass/Controllers/PasswordDetailTableViewController.swift +++ b/pass/Controllers/PasswordDetailTableViewController.swift @@ -199,20 +199,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni self.tableData[tableDataIndex].item.append(TableCell(title: "username", content: username)) } self.tableData[tableDataIndex].item.append(TableCell(title: "password", content: password.password)) - // Show additional information - if password.additions.count > 0 { - self.tableData.append(TableSection(title: "additions", item: [])) - tableDataIndex += 1 - for additionKey in password.additionKeys { - if (!additionKey.hasPrefix("unknown") || !Defaults[.isHideUnknownOn]) && - additionKey.lowercased() != "username" && - additionKey.lowercased() != "password" { - self.tableData[tableDataIndex].item.append(TableCell(title: additionKey, content: password.additions[additionKey]!)) - - } - - } - } + // Show one time password if password.otpType == "totp", password.otpToken != nil { self.tableData.append(TableSection(title: "One time password (TOTP)", item: [])) @@ -221,6 +208,21 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni self.tableData[tableDataIndex].item.append(TableCell(title: "current", content: crtPassword)) } } + + // Show additional information + let filteredAdditionKeys = password.additionKeys.filter { + $0.lowercased() != "username" && + $0.lowercased() != "password" && + (!$0.hasPrefix("unknown") || !Defaults[.isHideOTPOn]) && + (!Password.otpKeywords.contains($0) || !Defaults[.isHideOTPOn]) } + + if filteredAdditionKeys.count > 0 { + self.tableData.append(TableSection(title: "additions", item: [])) + tableDataIndex += 1 + for additionKey in filteredAdditionKeys { + self.tableData[tableDataIndex].item.append(TableCell(title: additionKey, content: password.additions[additionKey]!)) + } + } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { diff --git a/pass/Helpers/DefaultsKeys.swift b/pass/Helpers/DefaultsKeys.swift index 29ddfe4..812b111 100644 --- a/pass/Helpers/DefaultsKeys.swift +++ b/pass/Helpers/DefaultsKeys.swift @@ -33,6 +33,7 @@ extension DefaultsKeys { static let passcodeKey = DefaultsKey("passcodeKey") static let isHideUnknownOn = DefaultsKey("isHideUnknownOn") + static let isHideOTPOn = DefaultsKey("isHideOTPOn") static let isRememberPassphraseOn = DefaultsKey("isRememberPassphraseOn") static let isShowFolderOn = DefaultsKey("isShowFolderOn") diff --git a/pass/Models/Password.swift b/pass/Models/Password.swift index fe6cba5..d6a1076 100644 --- a/pass/Models/Password.swift +++ b/pass/Models/Password.swift @@ -25,10 +25,22 @@ class Password { var additionKeys = [String]() var plainText = "" var changed = false + var firstLineIsOTPField = false var otpType: String? var otpToken: Token? init(name: String, plainText: String) { + self.initEverything(name: name, plainText: plainText) + } + + func updatePassword(name: String, plainText: String) { + if self.plainText != plainText { + self.initEverything(name: name, plainText: plainText) + changed = true + } + } + + func initEverything(name: String, plainText: String) { self.name = name self.plainText = plainText @@ -38,12 +50,15 @@ class Password { }.map(String.init) self.password = plainTextSplit[0] (self.additions, self.additionKeys) = Password.getAdditionFields(from: plainTextSplit[1]) - + // check whether the first line of the plainText looks like an otp entry let (key, value) = Password.getKeyValuePair(from: plainTextSplit[0]) if key != nil && Password.otpKeywords.contains(key!) { + firstLineIsOTPField = true self.additions[key!] = value - self.additionKeys.append(key!) + self.additionKeys.insert(key!, at: 0) + } else { + firstLineIsOTPField = false } // construct the otp token @@ -94,39 +109,20 @@ class Password { return (additions, additionKeys) } - func updatePassword(name: String, plainText: String) { - self.name = name - if self.plainText != plainText { - self.name = name - self.plainText = plainText - - // get password and additional fields - let plainTextSplit = plainText.characters.split(maxSplits: 1, omittingEmptySubsequences: false) { - $0 == "\n" || $0 == "\r\n" - }.map(String.init) - self.password = plainTextSplit[0] - (self.additions, self.additionKeys) = Password.getAdditionFields(from: plainTextSplit[1]) - - // construct the otp token - self.updateOtpToken() - - changed = true + func getAdditionsPlainText() -> String { + // lines starting from the second + let plainTextSplit = plainText.characters.split(maxSplits: 1, omittingEmptySubsequences: false) { + $0 == "\n" || $0 == "\r\n" + }.map(String.init) + if plainTextSplit.count == 1 { + return "" + } else { + return plainTextSplit[1] } } - func getAdditionsPlainText() -> String { - let plainAdditionsText = self.additionKeys.map { - if $0.hasPrefix("unknown") { - return "\(self.additions[$0]!)" - } else { - return "\($0): \(self.additions[$0]!)" - } - }.joined(separator: "\n") - return plainAdditionsText - } - func getPlainText() -> String { - return "\(self.password)\n\(getAdditionsPlainText())" + return self.plainText } func getPlainData() -> Data {