Improve edit password to make it consistent with Pass

This commit is contained in:
Bob Sun 2017-04-25 13:01:17 -07:00
parent 86cb8a84cd
commit 055ea243a3
No known key found for this signature in database
GPG key ID: 1F86BA2052FED3B4
6 changed files with 136 additions and 103 deletions

View file

@ -53,7 +53,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController {
if cellContents["additions"]! != "" { if cellContents["additions"]! != "" {
plainText = "\(cellContents["password"]!)\n\(cellContents["additions"]!)" plainText = "\(cellContents["password"]!)\n\(cellContents["additions"]!)"
} else { } else {
plainText = "\(cellContents["password"]!)\n" plainText = "\(cellContents["password"]!)"
} }
let name = URL(string: cellContents["name"]!)!.lastPathComponent let name = URL(string: cellContents["name"]!)!.lastPathComponent
let url = URL(string: cellContents["name"]!)!.appendingPathExtension("gpg") let url = URL(string: cellContents["name"]!)!.appendingPathExtension("gpg")

View file

@ -22,7 +22,6 @@ class GitConfigSettingTableViewController: UITableViewController {
} }
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
print("test should perform \(identifier)")
if identifier == "saveGitConfigSettingSegue" { if identifier == "saveGitConfigSettingSegue" {
guard let name = nameTextField.text, !name.isEmpty else { guard let name = nameTextField.text, !name.isEmpty else {
Utils.alert(title: "Cannot Save", message: "Please set name first.", controller: self, completion: nil) Utils.alert(title: "Cannot Save", message: "Please set name first.", controller: self, completion: nil)

View file

@ -212,28 +212,26 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
@IBAction private func saveEditPassword(segue: UIStoryboardSegue) { @IBAction private func saveEditPassword(segue: UIStoryboardSegue) {
if self.password!.changed { if self.password!.changed != 0 {
SVProgressHUD.show(withStatus: "Saving") SVProgressHUD.show(withStatus: "Saving")
DispatchQueue.global(qos: .userInitiated).async {
do { do {
self.passwordEntity = try self.passwordStore.update(passwordEntity: self.passwordEntity!, password: self.password!) self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
} catch { } catch {
DispatchQueue.main.async {
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
} }
}
DispatchQueue.main.async {
self.setTableData() self.setTableData()
self.tableView.reloadData() self.tableView.reloadData()
SVProgressHUD.showSuccess(withStatus: "Success") SVProgressHUD.showSuccess(withStatus: "Success")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} }
} }
}
}
@IBAction private func deletePassword(segue: UIStoryboardSegue) { @IBAction private func deletePassword(segue: UIStoryboardSegue) {
passwordStore.delete(passwordEntity: passwordEntity!) do {
try passwordStore.delete(passwordEntity: passwordEntity!)
} catch {
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
}
let _ = navigationController?.popViewController(animated: true) let _ = navigationController?.popViewController(animated: true)
} }
@ -387,22 +385,16 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
// commit the change of HOTP counter // commit the change of HOTP counter
if password!.changed { if password!.changed != 0 {
DispatchQueue.global(qos: .userInitiated).async {
do { do {
self.passwordEntity = try self.passwordStore.update(passwordEntity: self.passwordEntity!, password: self.password!) self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
} catch { } catch {
DispatchQueue.main.async {
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
} }
}
DispatchQueue.main.async {
SVProgressHUD.showSuccess(withStatus: "Password Copied\nCounter Updated") SVProgressHUD.showSuccess(withStatus: "Password Copied\nCounter Updated")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} }
} }
}
}
func openLink() { func openLink() {
guard let urlString = self.password?.getURLString(), let url = URL(string: urlString) else { guard let urlString = self.password?.getURLString(), let url = URL(string: urlString) else {

View file

@ -16,6 +16,12 @@ struct AdditionField {
var content: String var content: String
} }
enum PasswordChange: Int {
case path = 0x01
case content = 0x02
case none = 0x00
}
class Password { class Password {
static let otpKeywords = ["otp_secret", "otp_type", "otp_algorithm", "otp_period", "otp_digits", "otp_counter", "otpauth"] static let otpKeywords = ["otp_secret", "otp_type", "otp_algorithm", "otp_period", "otp_digits", "otp_counter", "otpauth"]
@ -32,7 +38,7 @@ class Password {
var password = "" var password = ""
var additions = [String: String]() var additions = [String: String]()
var additionKeys = [String]() var additionKeys = [String]()
var changed = false var changed: Int = 0
var plainText = "" var plainText = ""
private var firstLineIsOTPField = false private var firstLineIsOTPField = false
@ -62,8 +68,13 @@ class Password {
func updatePassword(name: String, url: URL?, plainText: String) { func updatePassword(name: String, url: URL?, plainText: String) {
if self.plainText != plainText || self.url != url { if self.plainText != plainText || self.url != url {
if self.plainText != plainText {
changed = changed|PasswordChange.content.rawValue
}
if self.url != url {
changed = changed|PasswordChange.path.rawValue
}
self.initEverything(name: name, url: url, plainText: plainText) self.initEverything(name: name, url: url, plainText: plainText)
changed = true
} }
} }

View file

@ -31,4 +31,11 @@ extension PasswordEntity {
passwordCategoryArray.reverse() passwordCategoryArray.reverse()
return passwordCategoryArray.joined(separator: " > ") return passwordCategoryArray.joined(separator: " > ")
} }
func getURL() -> URL? {
if let p = path {
return URL(string: p)
}
return nil
}
} }

View file

@ -509,43 +509,51 @@ class PasswordStore {
func updateRemoteRepo() { func updateRemoteRepo() {
} }
func createAddCommitInRepository(message: String, path: String) -> GTCommit? { private func gitAdd(path: String) throws {
do { if let repo = storeRepository {
try storeRepository?.index().addFile(path) try repo.index().addFile(path)
try storeRepository?.index().write() try repo.index().write()
let newTree = try storeRepository!.index().writeTree() }
let headReference = try storeRepository!.headReference() }
let commitEnum = try GTEnumerator(repository: storeRepository!)
private func gitRm(path: String) throws {
if let repo = storeRepository {
var url = storeURL.appendingPathComponent(path)
Utils.removeFileIfExists(at: url)
let fm = FileManager.default
url.deleteLastPathComponent()
var count = try fm.contentsOfDirectory(atPath: url.path).count
while count == 0 {
Utils.removeFileIfExists(atPath: url.path)
url.deleteLastPathComponent()
count = try fm.contentsOfDirectory(atPath: url.path).count
}
try repo.index().removeFile(path)
try repo.index().write()
}
}
private func gitMv(from: String, to: String) throws {
let fm = FileManager.default
try fm.moveItem(at: storeURL.appendingPathComponent(from), to: storeURL.appendingPathComponent(to))
try gitAdd(path: to)
try gitRm(path: from)
}
private func gitCommit(message: String) throws -> GTCommit? {
if let repo = storeRepository {
let newTree = try repo.index().writeTree()
let headReference = try repo.headReference()
let commitEnum = try GTEnumerator(repository: repo)
try commitEnum.pushSHA(headReference.targetOID.sha!) try commitEnum.pushSHA(headReference.targetOID.sha!)
let parent = commitEnum.nextObject() as! GTCommit let parent = commitEnum.nextObject() as! GTCommit
let signature = gitSignatureForNow let signature = gitSignatureForNow
let commit = try storeRepository!.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name) let commit = try repo.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
return commit return commit
} catch {
print(error)
} }
return nil return nil
} }
func createRemoveCommitInRepository(message: String, path: String) -> GTCommit? {
do {
try storeRepository?.index().removeFile(path)
try storeRepository?.index().write()
let newTree = try storeRepository!.index().writeTree()
let headReference = try storeRepository!.headReference()
let commitEnum = try GTEnumerator(repository: storeRepository!)
try commitEnum.pushSHA(headReference.targetOID.sha!)
let parent = commitEnum.nextObject() as! GTCommit
let signature = gitSignatureForNow
let commit = try storeRepository!.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
return commit
} catch {
print(error)
}
return nil
}
private func getLocalBranch(withName branchName: String) -> GTBranch? { private func getLocalBranch(withName branchName: String) -> GTBranch? {
do { do {
let reference = GTBranch.localNamePrefix().appending(branchName) let reference = GTBranch.localNamePrefix().appending(branchName)
@ -567,7 +575,11 @@ class PasswordStore {
try storeRepository?.push(masterBranch, to: remote, withOptions: options, progress: transferProgressBlock) try storeRepository?.push(masterBranch, to: remote, withOptions: options, progress: transferProgressBlock)
} }
private func addPasswordEntities(password: Password) -> PasswordEntity? { private func addPasswordEntities(password: Password) throws -> PasswordEntity? {
guard !passwordExisted(password: password) else {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot add password: password duplicated."])
}
var passwordURL = password.url! var passwordURL = password.url!
var paths: [String] = [] var paths: [String] = []
while passwordURL.path != "." { while passwordURL.path != "." {
@ -599,7 +611,6 @@ class PasswordStore {
private func insertPasswordEntity(name: String, path: String, parent: PasswordEntity?, synced: Bool = false, isDir: Bool = false) -> PasswordEntity? { private func insertPasswordEntity(name: String, path: String, parent: PasswordEntity?, synced: Bool = false, isDir: Bool = false) -> PasswordEntity? {
var ret: PasswordEntity? = nil var ret: PasswordEntity? = nil
DispatchQueue.main.sync {
if let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: self.context) as? PasswordEntity { if let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: self.context) as? PasswordEntity {
passwordEntity.name = name passwordEntity.name = name
passwordEntity.path = path passwordEntity.path = path
@ -613,35 +624,44 @@ class PasswordStore {
fatalError("Failed to insert a PasswordEntity: \(error)") fatalError("Failed to insert a PasswordEntity: \(error)")
} }
} }
}
return ret return ret
} }
func add(password: Password) throws -> PasswordEntity? { func add(password: Password) throws -> PasswordEntity? {
guard !passwordExisted(password: password) else { let newPasswordEntity = try addPasswordEntities(password: password)
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot add password: password duplicated."])
}
let newPasswordEntity = addPasswordEntities(password: password)
print("new: \(newPasswordEntity!.path!)")
let saveURL = storeURL.appendingPathComponent(password.url!.path) let saveURL = storeURL.appendingPathComponent(password.url!.path)
try self.encrypt(password: password).write(to: saveURL) try self.encrypt(password: password).write(to: saveURL)
let _ = createAddCommitInRepository(message: "Add password for \(password.url!.deletingPathExtension().path) to store using Pass for iOS.", path: password.url!.path) try gitAdd(path: password.url!.path)
let _ = try gitCommit(message: "Add password for \(password.url!.deletingPathExtension().path) to store using Pass for iOS.")
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
return newPasswordEntity return newPasswordEntity
} }
func update(passwordEntity: PasswordEntity, password: Password) throws -> PasswordEntity? { func edit(passwordEntity: PasswordEntity, password: Password) throws -> PasswordEntity? {
delete(passwordEntity: passwordEntity) var newPasswordEntity: PasswordEntity? = passwordEntity
return try add(password: password)
if password.changed&PasswordChange.content.rawValue != 0 {
let saveURL = storeURL.appendingPathComponent(password.url!.path)
try self.encrypt(password: password).write(to: saveURL)
try gitAdd(path: password.url!.path)
let _ = try gitCommit(message: "Edit password for \(password.url!.deletingPathExtension().path) to store using Pass for iOS.")
}
guard newPasswordEntity != nil else {
return nil
}
if password.changed&PasswordChange.path.rawValue != 0 {
let oldPasswordURL = newPasswordEntity!.getURL()
try self.deletePasswordEntities(passwordEntity: newPasswordEntity!)
newPasswordEntity = try self.addPasswordEntities(password: password)
try gitMv(from: oldPasswordURL!.path, to: password.url!.path)
let _ = try gitCommit(message: "Rename \(oldPasswordURL!.deletingPathExtension().path) to \(password.url!.deletingPathExtension().path) using Pass for iOS.")
}
return newPasswordEntity
} }
private func deletePasswordEntities(passwordEntity: PasswordEntity) throws {
public func delete(passwordEntity: PasswordEntity) {
DispatchQueue.main.async {
let _ = self.createRemoveCommitInRepository(message: "Remove \(passwordEntity.nameWithCategory) from store using Pass for iOS", path: passwordEntity.path!)
var current: PasswordEntity? = passwordEntity var current: PasswordEntity? = passwordEntity
while current != nil && (current!.children!.count == 0 || !current!.isDir) { while current != nil && (current!.children!.count == 0 || !current!.isDir) {
Utils.removeFileIfExists(at: self.storeURL.appendingPathComponent(current!.path!))
let parent = current!.parent let parent = current!.parent
self.context.delete(current!) self.context.delete(current!)
current = parent current = parent
@ -651,9 +671,13 @@ class PasswordStore {
fatalError("Failed to delete a PasswordEntity: \(error)") fatalError("Failed to delete a PasswordEntity: \(error)")
} }
} }
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} }
public func delete(passwordEntity: PasswordEntity) throws {
try gitRm(path: passwordEntity.path!)
let _ = try gitCommit(message: "Remove \(passwordEntity.nameWithCategory) from store using Pass for iOS.")
try deletePasswordEntities(passwordEntity: passwordEntity)
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} }
func saveUpdated(passwordEntity: PasswordEntity) { func saveUpdated(passwordEntity: PasswordEntity) {