From b954a4dcabb7bf966bc596d945cc0c9574204500 Mon Sep 17 00:00:00 2001 From: Bob Sun Date: Fri, 10 Feb 2017 22:15:01 +0800 Subject: [PATCH] finish simple "add password function" --- pass.xcodeproj/project.pbxproj | 12 +++ pass/AppDelegate.swift | 1 - pass/Base.lproj/Main.storyboard | 100 ++++++++++++++++-- .../AddPasswordTableViewController.swift | 51 +++++++++ .../PGPKeySettingTableViewController.swift | 9 +- .../Controllers/PasswordsViewController.swift | 9 ++ .../SettingsTableViewController.swift | 11 +- pass/Helpers/DefaultsKeys.swift | 7 +- pass/Helpers/Globals.swift | 6 +- pass/Models/Password.swift | 13 ++- pass/Models/PasswordStore.swift | 42 ++++++-- pass/Views/TextFieldTableViewCell.swift | 27 +++++ pass/Views/TextFieldTableViewCell.xib | 52 +++++++++ 13 files changed, 314 insertions(+), 26 deletions(-) create mode 100644 pass/Controllers/AddPasswordTableViewController.swift create mode 100644 pass/Views/TextFieldTableViewCell.swift create mode 100644 pass/Views/TextFieldTableViewCell.xib diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 4dd6bc1..08b1447 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -15,6 +15,9 @@ DC037CAE1E4C9B9B00609409 /* PasswordRepositorySettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CAD1E4C9B9B00609409 /* PasswordRepositorySettingsTableViewController.swift */; }; DC037CB01E4CA51F00609409 /* GeneralSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */; }; DC037CB21E4CAB1700609409 /* AboutRepositoryTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */; }; + DC037CB81E4DD1A500609409 /* AddPasswordTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CB71E4DD1A500609409 /* AddPasswordTableViewController.swift */; }; + DC037CBB1E4DD47B00609409 /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */; }; + DC037CBC1E4DD47B00609409 /* TextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */; }; DC1208581E35EBE60042942E /* ObjectiveGit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1208571E35EBE60042942E /* ObjectiveGit.framework */; }; DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */; }; DC193FFC1E49E0340077E0A3 /* PasscodeLock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */; }; @@ -58,6 +61,9 @@ DC037CAD1E4C9B9B00609409 /* PasswordRepositorySettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordRepositorySettingsTableViewController.swift; sourceTree = ""; }; DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralSettingsTableViewController.swift; sourceTree = ""; }; DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutRepositoryTableViewController.swift; sourceTree = ""; }; + DC037CB71E4DD1A500609409 /* AddPasswordTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPasswordTableViewController.swift; sourceTree = ""; }; + DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTableViewCell.swift; sourceTree = ""; }; + DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TextFieldTableViewCell.xib; sourceTree = ""; }; DC1208571E35EBE60042942E /* ObjectiveGit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectiveGit.framework; path = Carthage/Build/iOS/ObjectiveGit.framework; sourceTree = ""; }; DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsTableViewController.swift; sourceTree = ""; }; DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PasscodeLock.framework; path = Carthage/Build/iOS/PasscodeLock.framework; sourceTree = ""; }; @@ -123,6 +129,7 @@ DC19400C1E4B39400077E0A3 /* Controllers */ = { isa = PBXGroup; children = ( + DC037CB71E4DD1A500609409 /* AddPasswordTableViewController.swift */, DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */, DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */, DC962CDE1E4B62C10033B5D8 /* AboutTableViewController.swift */, @@ -168,6 +175,8 @@ isa = PBXGroup; children = ( DC4914941E434301007FF592 /* LabelTableViewCell.swift */, + DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */, + DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */, DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */, ); path = Views; @@ -289,6 +298,7 @@ buildActionMask = 2147483647; files = ( DC917BE11E2E8231000FDF54 /* LaunchScreen.storyboard in Resources */, + DC037CBC1E4DD47B00609409 /* TextFieldTableViewCell.xib in Resources */, DC917BDE1E2E8231000FDF54 /* Assets.xcassets in Resources */, DCDDEAB41E4896BF00F68193 /* PasswordDetailTitleTableViewCell.xib in Resources */, DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */, @@ -390,8 +400,10 @@ DC037CB21E4CAB1700609409 /* AboutRepositoryTableViewController.swift in Sources */, DC037CB01E4CA51F00609409 /* GeneralSettingsTableViewController.swift in Sources */, DC8963BE1E38AD8300828B09 /* GitRepositoryAuthenticationSettingTableViewController.swift in Sources */, + DC037CB81E4DD1A500609409 /* AddPasswordTableViewController.swift in Sources */, DC1940001E49E1A60077E0A3 /* PasscodeLockConfiguration.swift in Sources */, DC917BD71E2E8231000FDF54 /* AppDelegate.swift in Sources */, + DC037CBB1E4DD47B00609409 /* TextFieldTableViewCell.swift in Sources */, DC193FFE1E49E0760077E0A3 /* PasscodeLockRepository.swift in Sources */, DCA049981E33586A00522E8F /* DefaultsKeys.swift in Sources */, DC19400B1E4B36B60077E0A3 /* Utils.swift in Sources */, diff --git a/pass/AppDelegate.swift b/pass/AppDelegate.swift index d91ffab..9fd3f9a 100644 --- a/pass/AppDelegate.swift +++ b/pass/AppDelegate.swift @@ -26,7 +26,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100)) passcodeLockPresenter.present() if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem { - print(shortcutItem.type) if shortcutItem.type == "me.mssun.pass.search" { self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4) } diff --git a/pass/Base.lproj/Main.storyboard b/pass/Base.lproj/Main.storyboard index b4ce481..8b86987 100644 --- a/pass/Base.lproj/Main.storyboard +++ b/pass/Base.lproj/Main.storyboard @@ -55,6 +55,11 @@ + + + + + @@ -507,14 +512,14 @@ - - + @@ -582,7 +617,8 @@ - + + @@ -590,6 +626,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -607,7 +675,7 @@ - + @@ -990,6 +1058,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/pass/Controllers/AddPasswordTableViewController.swift b/pass/Controllers/AddPasswordTableViewController.swift new file mode 100644 index 0000000..e3a2998 --- /dev/null +++ b/pass/Controllers/AddPasswordTableViewController.swift @@ -0,0 +1,51 @@ +// +// AddPasswordTableViewController.swift +// pass +// +// Created by Mingshen Sun on 10/2/2017. +// Copyright © 2017 Bob Sun. All rights reserved. +// + +import UIKit + +class AddPasswordTableViewController: UITableViewController { + let tableTitles = ["name", "password"] + var password: Password? + + override func viewDidLoad() { + super.viewDidLoad() + tableView.register(UINib(nibName: "TextFieldTableViewCell", bundle: nil), forCellReuseIdentifier: "textFieldCell") + tableView.rowHeight = UITableViewAutomaticDimension + tableView.estimatedRowHeight = 52 + tableView.allowsSelection = false + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return tableTitles.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "textFieldCell", for: indexPath) as! TextFieldTableViewCell + cell.titleLabel.text = tableTitles[indexPath.row] + return cell + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + let name = getCellForName(name: "name")!.contentTextField.text ?? "" + let passwordText = getCellForName(name: "password")!.contentTextField.text ?? "" +// let additions = getCellForName(name: "additions")!.contentTextField.text ?? "" +// let additionSplit = additions.characters.split(separator: ":").map(String.init) +// print(additionSplit) +// let additionField = AdditionField(title: additionSplit[0], content: additionSplit[1]) + password = Password(name: name, username: "", password: passwordText, additions: []) + } + + func getCellAt(row: Int) -> TextFieldTableViewCell? { + return tableView.cellForRow(at: IndexPath(row: row, section: 0)) as? TextFieldTableViewCell + } + + func getCellForName(name: String) -> TextFieldTableViewCell? { + let index = tableTitles.index(of: name)! + return getCellAt(row: Int(index)) + } +} diff --git a/pass/Controllers/PGPKeySettingTableViewController.swift b/pass/Controllers/PGPKeySettingTableViewController.swift index ee4bcdb..149c5c5 100644 --- a/pass/Controllers/PGPKeySettingTableViewController.swift +++ b/pass/Controllers/PGPKeySettingTableViewController.swift @@ -11,18 +11,21 @@ import SwiftyUserDefaults class PGPKeySettingTableViewController: UITableViewController { - @IBOutlet weak var pgpKeyURLTextField: UITextField! + @IBOutlet weak var pgpPublicKeyURLTextField: UITextField! + @IBOutlet weak var pgpPrivateKeyURLTextField: UITextField! @IBOutlet weak var pgpKeyPassphraseTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() - pgpKeyURLTextField.text = Defaults[.pgpKeyURL]?.absoluteString + pgpPublicKeyURLTextField.text = Defaults[.pgpPublicKeyURL]?.absoluteString + pgpPrivateKeyURLTextField.text = Defaults[.pgpPrivateKeyURL]?.absoluteString pgpKeyPassphraseTextField.text = Defaults[.pgpKeyPassphrase] } override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "savePGPKeySegue" { - if URL(string: pgpKeyURLTextField.text!)!.scheme! == "http" { + if URL(string: pgpPublicKeyURLTextField.text!)!.scheme! == "http" && + URL(string: pgpPrivateKeyURLTextField.text!)!.scheme! == "http" { let alertMessage = "HTTP connection is not supported." let alert = UIAlertController(title: "Cannot Save Settings", message: alertMessage, preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) diff --git a/pass/Controllers/PasswordsViewController.swift b/pass/Controllers/PasswordsViewController.swift index 6cb0a22..7ec6eb6 100644 --- a/pass/Controllers/PasswordsViewController.swift +++ b/pass/Controllers/PasswordsViewController.swift @@ -27,6 +27,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV @IBOutlet weak var tableView: UITableView! + @IBAction func cancelAddPassword(segue: UIStoryboardSegue) { + + } + @IBAction func saveAddPassword(segue: UIStoryboardSegue) { + if let controller = segue.source as? AddPasswordTableViewController { + PasswordStore.shared.add(password: controller.password!) + NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated"))) + } + } func syncPasswords() { SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index c2d197b..ddb0abb 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -26,9 +26,11 @@ class SettingsTableViewController: UITableViewController { @IBAction func save(segue: UIStoryboardSegue) { if let controller = segue.source as? PGPKeySettingTableViewController { - if Defaults[.pgpKeyURL] != URL(string: controller.pgpKeyURLTextField.text!) || + if Defaults[.pgpPrivateKeyURL] != URL(string: controller.pgpPrivateKeyURLTextField.text!) || + Defaults[.pgpPublicKeyURL] != URL(string: controller.pgpPublicKeyURLTextField.text!) || Defaults[.pgpKeyPassphrase] != controller.pgpKeyPassphraseTextField.text! { - Defaults[.pgpKeyURL] = URL(string: controller.pgpKeyURLTextField.text!) + Defaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!) + Defaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!) Defaults[.pgpKeyPassphrase] = controller.pgpKeyPassphraseTextField.text! SVProgressHUD.setDefaultMaskType(.black) @@ -36,7 +38,10 @@ class SettingsTableViewController: UITableViewController { SVProgressHUD.show(withStatus: "Fetching PGP Key") DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { - try PasswordStore.shared.initPGP(pgpKeyURL: Defaults[.pgpKeyURL]!, pgpKeyLocalPath: Globals.secringPath) + try PasswordStore.shared.initPGP(pgpPublicKeyURL: Defaults[.pgpPublicKeyURL]!, + pgpPublicKeyLocalPath: Globals.pgpPublicKeyPath, + pgpPrivateKeyURL: Defaults[.pgpPrivateKeyURL]!, + pgpPrivateKeyLocalPath: Globals.pgpPrivateKeyPath) DispatchQueue.main.async { self.pgpKeyTableViewCell.detailTextLabel?.text = Defaults[.pgpKeyID] SVProgressHUD.showSuccess(withStatus: "Success. Remember to remove the key from the server.") diff --git a/pass/Helpers/DefaultsKeys.swift b/pass/Helpers/DefaultsKeys.swift index 72282b3..243dacc 100644 --- a/pass/Helpers/DefaultsKeys.swift +++ b/pass/Helpers/DefaultsKeys.swift @@ -10,7 +10,9 @@ import Foundation import SwiftyUserDefaults extension DefaultsKeys { - static let pgpKeyURL = DefaultsKey("pgpKeyURL") +// static let pgpKeyURL = DefaultsKey("pgpKeyURL") + static let pgpPublicKeyURL = DefaultsKey("pgpPublicKeyURL") + static let pgpPrivateKeyURL = DefaultsKey("pgpPrivateKeyURL") static let pgpKeyPassphrase = DefaultsKey("pgpKeyPassphrase") static let pgpKeyID = DefaultsKey("pgpKeyID") @@ -31,7 +33,8 @@ extension DefaultsKeys { extension Utils { static func eraseAllUserDefaults() { - Defaults.remove(.pgpKeyURL) + Defaults.remove(.pgpPublicKeyURL) + Defaults.remove(.pgpPrivateKeyURL) Defaults.remove(.pgpKeyPassphrase) Defaults.remove(.pgpKeyID) diff --git a/pass/Helpers/Globals.swift b/pass/Helpers/Globals.swift index ce263fb..a45b5c0 100644 --- a/pass/Helpers/Globals.swift +++ b/pass/Helpers/Globals.swift @@ -10,9 +10,13 @@ import Foundation class Globals { static let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]; - static let secringPath = "\(documentPath)/secring.gpg" + static let pgpPublicKeyPath = "\(documentPath)/gpg_key.pub" + static let pgpPrivateKeyPath = "\(documentPath)/gpg_key" + static let sshPublicKeyURL = URL(fileURLWithPath: "\(documentPath)/ssh_key.pub") static let sshPrivateKeyURL = URL(fileURLWithPath: "\(documentPath)/ssh_key") + + static let repositoryPath = "\(documentPath)/password-store" static var passcodeConfiguration = PasscodeLockConfiguration() static let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String private init() { } diff --git a/pass/Models/Password.swift b/pass/Models/Password.swift index 19977a5..937a24f 100644 --- a/pass/Models/Password.swift +++ b/pass/Models/Password.swift @@ -49,7 +49,7 @@ class Password { extension PasswordEntity { func decrypt() throws -> Password? { var password: Password? - let encryptedDataPath = URL(fileURLWithPath: "\(Globals.documentPath)/\(rawPath!)") + let encryptedDataPath = URL(fileURLWithPath: "\(Globals.repositoryPath)/\(rawPath!)") let encryptedData = try Data(contentsOf: encryptedDataPath) let decryptedData = try PasswordStore.shared.pgp.decryptData(encryptedData, passphrase: Defaults[.pgpKeyPassphrase]) let plain = String(data: decryptedData, encoding: .ascii) ?? "" @@ -82,4 +82,15 @@ extension PasswordEntity { password = Password(name: name!, username: username, password: decrypted_password, additions: decrypted_addtions) return password } + + func encrypt(password: Password) throws -> Data { + name = password.name + rawPath = "" + let plainPassword = password.password +// let plainAdditions = password.additions.map { "\($0.title): \($0.content)" }.joined(separator: "\n") + let plainData = "\(plainPassword)\n".data(using: .ascii)! + let pgp = PasswordStore.shared.pgp + let encryptedData = try pgp.encryptData(plainData, usingPublicKey: pgp.getKeysOf(.public)[0], armored: false) + return encryptedData + } } diff --git a/pass/Models/PasswordStore.swift b/pass/Models/PasswordStore.swift index d4c4a47..e063c3d 100644 --- a/pass/Models/PasswordStore.swift +++ b/pass/Models/PasswordStore.swift @@ -58,7 +58,9 @@ class PasswordStore { print(error) } if Defaults[.pgpKeyID] != "" { - pgp.importKeys(fromFile: Globals.secringPath, allowDuplicates: false) + pgp.importKeys(fromFile: Globals.pgpPublicKeyPath, allowDuplicates: false) + pgp.importKeys(fromFile: Globals.pgpPrivateKeyPath, allowDuplicates: false) + } if Defaults[.gitRepositoryAuthenticationMethod] == "Password" { gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitRepositoryUsername], password: Defaults[.gitRepositoryPassword])) @@ -70,11 +72,17 @@ class PasswordStore { } - func initPGP(pgpKeyURL: URL, pgpKeyLocalPath: String) throws { - let pgpData = try Data(contentsOf: pgpKeyURL) - try pgpData.write(to: URL(fileURLWithPath: pgpKeyLocalPath), options: .atomic) - pgp.importKeys(fromFile: pgpKeyLocalPath, allowDuplicates: false) - let key = pgp.keys[0] + func initPGP(pgpPublicKeyURL: URL, pgpPublicKeyLocalPath: String, pgpPrivateKeyURL: URL, pgpPrivateKeyLocalPath: String) throws { + let pgpPublicData = try Data(contentsOf: pgpPublicKeyURL) + try pgpPublicData.write(to: URL(fileURLWithPath: pgpPublicKeyLocalPath), options: .atomic) + + let pgpPrivateData = try Data(contentsOf: pgpPrivateKeyURL) + try pgpPrivateData.write(to: URL(fileURLWithPath: pgpPrivateKeyLocalPath), options: .atomic) + + pgp.importKeys(fromFile: pgpPublicKeyLocalPath, allowDuplicates: false) + pgp.importKeys(fromFile: pgpPrivateKeyLocalPath, allowDuplicates: false) + + let key = pgp.getKeysOf(.public)[0] Defaults[.pgpKeyID] = key.keyID!.shortKeyString if let gpgUser = key.users[0] as? PGPUser { Defaults[.pgpKeyUserID] = gpgUser.userID @@ -130,7 +138,7 @@ class PasswordStore { let passwordEntity = PasswordEntity(context: context) let endIndex = url.lastPathComponent.index(url.lastPathComponent.endIndex, offsetBy: -4) passwordEntity.name = url.lastPathComponent.substring(to: endIndex) - passwordEntity.rawPath = "password-store/\(url.path)" + passwordEntity.rawPath = "\(url.path)" let items = url.path.characters.split(separator: "/").map(String.init) for i in 0 ..< items.count - 1 { let passwordCategoryEntity = PasswordCategoryEntity(context: context) @@ -173,6 +181,23 @@ class PasswordStore { func updateRemoteRepo() { } + func commitChange() { + + } + + func add(password: Password) { + let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity + do { + let encryptedData = try passwordEntity.encrypt(password: password) + let saveURL = storeURL.appendingPathComponent("\(password.name).gpg") + try encryptedData.write(to: saveURL) + passwordEntity.rawPath = "\(password.name).gpg" + try context.save() + } catch { + print(error) + } + } + func deleteCoreData(entityName: String) { let deleteFetchRequest = NSFetchRequest(entityName: entityName) let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest) @@ -186,7 +211,8 @@ class PasswordStore { func erase() { Utils.removeFileIfExists(at: storeURL) - Utils.removeFileIfExists(atPath: Globals.secringPath) + Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath) + Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath) Utils.removeFileIfExists(at: Globals.sshPrivateKeyURL) Utils.removeFileIfExists(at: Globals.sshPublicKeyURL) diff --git a/pass/Views/TextFieldTableViewCell.swift b/pass/Views/TextFieldTableViewCell.swift new file mode 100644 index 0000000..c1b0918 --- /dev/null +++ b/pass/Views/TextFieldTableViewCell.swift @@ -0,0 +1,27 @@ +// +// TextFieldTableViewCell.swift +// pass +// +// Created by Mingshen Sun on 10/2/2017. +// Copyright © 2017 Bob Sun. All rights reserved. +// + +import UIKit + +class TextFieldTableViewCell: UITableViewCell { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var contentTextField: UITextField! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/pass/Views/TextFieldTableViewCell.xib b/pass/Views/TextFieldTableViewCell.xib new file mode 100644 index 0000000..480b969 --- /dev/null +++ b/pass/Views/TextFieldTableViewCell.xib @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +