Merge branch 'release/0.2.1'

This commit is contained in:
Bob Sun 2017-03-17 10:42:24 -07:00
commit 852a0b8ca1
No known key found for this signature in database
GPG key ID: 1F86BA2052FED3B4
21 changed files with 204 additions and 171 deletions

View file

@ -1,3 +1,3 @@
target 'pass' do target 'pass' do
pod 'ObjectivePGP' pod 'ObjectivePGP', :git => 'https://github.com/mssun/ObjectivePGP.git'
end end

View file

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
94BA784B85E071D25EE89B59 /* libPods-pass.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */; }; 94BA784B85E071D25EE89B59 /* libPods-pass.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */; };
A262A58D1E68749C006B0890 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; }; A262A58D1E68749C006B0890 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; };
A27424D91E7C35960093F436 /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = A27424D81E7C35960093F436 /* NotificationNames.swift */; };
A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2802BF71E70813A00879216 /* SliderTableViewCell.swift */; }; A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2802BF71E70813A00879216 /* SliderTableViewCell.swift */; };
A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A2802BF81E70813A00879216 /* SliderTableViewCell.xib */; }; A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A2802BF81E70813A00879216 /* SliderTableViewCell.xib */; };
DC037CA61E4B883900609409 /* OpenSourceComponentsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */; }; DC037CA61E4B883900609409 /* OpenSourceComponentsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */; };
@ -69,6 +70,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
274CCFCF32444A2FF46BE7F4 /* Pods-pass.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-pass.debug.xcconfig"; path = "Pods/Target Support Files/Pods-pass/Pods-pass.debug.xcconfig"; sourceTree = "<group>"; }; 274CCFCF32444A2FF46BE7F4 /* Pods-pass.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-pass.debug.xcconfig"; path = "Pods/Target Support Files/Pods-pass/Pods-pass.debug.xcconfig"; sourceTree = "<group>"; };
A262A58C1E68749C006B0890 /* Base32.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Base32.framework; path = Carthage/Build/iOS/Base32.framework; sourceTree = "<group>"; }; A262A58C1E68749C006B0890 /* Base32.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Base32.framework; path = Carthage/Build/iOS/Base32.framework; sourceTree = "<group>"; };
A27424D81E7C35960093F436 /* NotificationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationNames.swift; sourceTree = "<group>"; };
A2802BF71E70813A00879216 /* SliderTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderTableViewCell.swift; sourceTree = "<group>"; }; A2802BF71E70813A00879216 /* SliderTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderTableViewCell.swift; sourceTree = "<group>"; };
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SliderTableViewCell.xib; sourceTree = "<group>"; }; A2802BF81E70813A00879216 /* SliderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SliderTableViewCell.xib; sourceTree = "<group>"; };
ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-pass.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-pass.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@ -204,6 +206,7 @@
DC4A746D1E30FBDE00E8EB18 /* Objective-CBridgingHeader.h */, DC4A746D1E30FBDE00E8EB18 /* Objective-CBridgingHeader.h */,
DCA049971E33586A00522E8F /* DefaultsKeys.swift */, DCA049971E33586A00522E8F /* DefaultsKeys.swift */,
DC19400A1E4B36B60077E0A3 /* Utils.swift */, DC19400A1E4B36B60077E0A3 /* Utils.swift */,
A27424D81E7C35960093F436 /* NotificationNames.swift */,
); );
path = Helpers; path = Helpers;
sourceTree = "<group>"; sourceTree = "<group>";
@ -447,6 +450,7 @@
DC7E6EEA1E432E48006C2443 /* Password.swift in Sources */, DC7E6EEA1E432E48006C2443 /* Password.swift in Sources */,
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */, DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */,
DC5F385B1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift in Sources */, DC5F385B1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift in Sources */,
A27424D91E7C35960093F436 /* NotificationNames.swift in Sources */,
DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */, DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */,
DCE6C2671E71261C003038C6 /* PasswordWithFolderTableViewCell.swift in Sources */, DCE6C2671E71261C003038C6 /* PasswordWithFolderTableViewCell.swift in Sources */,
DCFB77A71E502DF9008DE471 /* EditPasswordTableViewController.swift in Sources */, DCFB77A71E502DF9008DE471 /* EditPasswordTableViewController.swift in Sources */,

View file

@ -38,7 +38,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
} }
func postSearchNotification() { func postSearchNotification() {
NotificationCenter.default.post(Notification(name: Notification.Name("search"))) NotificationCenter.default.post(name: .passwordSearch, object: nil)
} }
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {

View file

@ -13,6 +13,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
var needRefresh = false var needRefresh = false
var indicatorLabel: UILabel! var indicatorLabel: UILabel!
var indicator: UIActivityIndicatorView! var indicator: UIActivityIndicatorView!
let passwordStore = PasswordStore.shared
override func viewDidLoad() { override func viewDidLoad() {
navigationItemTitle = "About Repository" navigationItemTitle = "About Repository"
@ -31,7 +32,9 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
tableView.addSubview(indicatorLabel) tableView.addSubview(indicatorLabel)
setTableData() setTableData()
addNotificationObservers()
// all password store updates (including erase, discard) will trigger the refresh
NotificationCenter.default.addObserver(self, selector: #selector(setNeedRefresh), name: .passwordStoreUpdated, object: nil)
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
@ -57,20 +60,20 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
numberFormatter.numberStyle = NumberFormatter.Style.decimal numberFormatter.numberStyle = NumberFormatter.Style.decimal
let fm = FileManager.default let fm = FileManager.default
let passwordEntities = PasswordStore.shared.fetchPasswordEntityCoreData(withDir: false) let passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
let numberOfPasswords = numberFormatter.string(from: NSNumber(value: passwordEntities.count))! let numberOfPasswords = numberFormatter.string(from: NSNumber(value: passwordEntities.count))!
var size = UInt64(0) var size = UInt64(0)
do { do {
if fm.fileExists(atPath: PasswordStore.shared.storeURL.path) { if fm.fileExists(atPath: self.passwordStore.storeURL.path) {
size = try fm.allocatedSizeOfDirectoryAtURL(directoryURL: PasswordStore.shared.storeURL) size = try fm.allocatedSizeOfDirectoryAtURL(directoryURL: self.passwordStore.storeURL)
} }
} catch { } catch {
print(error) print(error)
} }
let sizeOfRepository = ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: ByteCountFormatter.CountStyle.file) let sizeOfRepository = ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: ByteCountFormatter.CountStyle.file)
let numberOfCommits = PasswordStore.shared.storeRepository?.numberOfCommits(inCurrentBranch: NSErrorPointer(nilLiteral: ())) ?? 0 let numberOfCommits = self.passwordStore.storeRepository?.numberOfCommits(inCurrentBranch: NSErrorPointer(nilLiteral: ())) ?? 0
let numberOfCommitsString = numberFormatter.string(from: NSNumber(value: numberOfCommits))! let numberOfCommitsString = numberFormatter.string(from: NSNumber(value: numberOfCommits))!
@ -79,7 +82,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
self?.tableData = [ self?.tableData = [
// section 0 // section 0
[[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: numberOfPasswords], [[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: numberOfPasswords],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: sizeOfRepository], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Unsynced", .detailText: String(PasswordStore.shared.getNumberOfUnsyncedPasswords())], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: sizeOfRepository], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Unsynced", .detailText: String(self?.passwordStore.getNumberOfUnsyncedPasswords() ?? 0)],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: Utils.getLastUpdatedTimeString()], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: Utils.getLastUpdatedTimeString()],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: numberOfCommitsString], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: numberOfCommitsString],
[.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"], [.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"],
@ -92,11 +95,6 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
} }
} }
private func addNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(setNeedRefresh), name: NSNotification.Name(rawValue: "passwordUpdated"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(setNeedRefresh), name: NSNotification.Name(rawValue: "passwordStoreErased"), object: nil)
}
func setNeedRefresh() { func setNeedRefresh() {
needRefresh = true needRefresh = true
} }

View file

@ -13,6 +13,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
var password: Password? var password: Password?
var tempContent: String = "" var tempContent: String = ""
let passwordStore = PasswordStore.shared
override func viewDidLoad() { override func viewDidLoad() {
tableData = [ tableData = [
@ -27,7 +28,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "saveAddPasswordSegue" { if identifier == "saveAddPasswordSegue" {
// check PGP key // check PGP key
if Defaults[.pgpKeyID] == nil { if passwordStore.privateKey == nil {
let alertTitle = "Cannot Add Password" let alertTitle = "Cannot Add Password"
let alertMessage = "PGP Key is not set. Please set your PGP Key first." let alertMessage = "PGP Key is not set. Please set your PGP Key first."
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)

View file

@ -13,6 +13,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
@IBOutlet weak var eraseDataTableViewCell: UITableViewCell! @IBOutlet weak var eraseDataTableViewCell: UITableViewCell!
@IBOutlet weak var discardChangesTableViewCell: UITableViewCell! @IBOutlet weak var discardChangesTableViewCell: UITableViewCell!
let passwordStore = PasswordStore.shared
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -24,8 +25,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
let alert = UIAlertController(title: "Erase Password Store Data?", message: "This will delete all local data and settings. Password store data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert) let alert = UIAlertController(title: "Erase Password Store Data?", message: "This will delete all local data and settings. Password store data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Erase Password Data", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in alert.addAction(UIAlertAction(title: "Erase Password Data", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
SVProgressHUD.show(withStatus: "Erasing ...") SVProgressHUD.show(withStatus: "Erasing ...")
PasswordStore.shared.erase() self.passwordStore.erase()
NotificationCenter.default.post(Notification(name: Notification.Name("passwordStoreErased")))
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
SVProgressHUD.showSuccess(withStatus: "Done") SVProgressHUD.showSuccess(withStatus: "Done")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
@ -40,10 +40,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
SVProgressHUD.show(withStatus: "Resetting ...") SVProgressHUD.show(withStatus: "Resetting ...")
DispatchQueue.main.async { DispatchQueue.main.async {
do { do {
let numberDiscarded = try PasswordStore.shared.reset() let numberDiscarded = try self.passwordStore.reset()
if numberDiscarded > 0 {
NotificationCenter.default.post(Notification(name: Notification.Name("passwordStoreChangeDiscarded")))
}
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
switch numberDiscarded { switch numberDiscarded {
case 0: case 0:
@ -56,8 +53,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} catch { } catch {
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showError(withStatus: error.localizedDescription) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
} }

View file

@ -11,10 +11,11 @@ import ObjectiveGit
class CommitLogsTableViewController: UITableViewController { class CommitLogsTableViewController: UITableViewController {
var commits: [GTCommit] = [] var commits: [GTCommit] = []
let passwordStore = PasswordStore.shared
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
commits = PasswordStore.shared.getRecentCommits(count: 20) commits = passwordStore.getRecentCommits(count: 20)
navigationItem.title = "Recent Commit Logs" navigationItem.title = "Recent Commit Logs"
navigationController!.navigationBar.topItem!.title = "About" navigationController!.navigationBar.topItem!.title = "About"
} }

View file

@ -10,6 +10,7 @@ import UIKit
import SwiftyUserDefaults import SwiftyUserDefaults
class GeneralSettingsTableViewController: BasicStaticTableViewController { class GeneralSettingsTableViewController: BasicStaticTableViewController {
let passwordStore = PasswordStore.shared
let hideUnknownSwitch: UISwitch = { let hideUnknownSwitch: UISwitch = {
let uiSwitch = UISwitch() let uiSwitch = UISwitch()
@ -177,13 +178,13 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
func rememberPassphraseSwitchAction(_ sender: Any?) { func rememberPassphraseSwitchAction(_ sender: Any?) {
Defaults[.isRememberPassphraseOn] = rememberPassphraseSwitch.isOn Defaults[.isRememberPassphraseOn] = rememberPassphraseSwitch.isOn
if rememberPassphraseSwitch.isOn == false { if rememberPassphraseSwitch.isOn == false {
PasswordStore.shared.pgpKeyPassphrase = nil passwordStore.pgpKeyPassphrase = nil
} }
} }
func showFolderSwitchAction(_ sender: Any?) { func showFolderSwitchAction(_ sender: Any?) {
Defaults[.isShowFolderOn] = showFolderSwitch.isOn Defaults[.isShowFolderOn] = showFolderSwitch.isOn
NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated"))) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} }
} }

View file

@ -15,6 +15,7 @@ class GitServerSettingTableViewController: UITableViewController {
@IBOutlet weak var usernameTextField: UITextField! @IBOutlet weak var usernameTextField: UITextField!
@IBOutlet weak var authSSHKeyCell: UITableViewCell! @IBOutlet weak var authSSHKeyCell: UITableViewCell!
@IBOutlet weak var authPasswordCell: UITableViewCell! @IBOutlet weak var authPasswordCell: UITableViewCell!
let passwordStore = PasswordStore.shared
var password: String? var password: String?
var authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod] var authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod]
@ -41,7 +42,7 @@ class GitServerSettingTableViewController: UITableViewController {
gitRepositoryURLTextField.text = url.absoluteString gitRepositoryURLTextField.text = url.absoluteString
} }
usernameTextField.text = Defaults[.gitRepositoryUsername] usernameTextField.text = Defaults[.gitRepositoryUsername]
password = PasswordStore.shared.gitRepositoryPassword password = passwordStore.gitRepositoryPassword
authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod] authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod]
// Grey out ssh option if ssh_key and ssh_key.pub are not present // Grey out ssh option if ssh_key and ssh_key.pub are not present

View file

@ -13,12 +13,13 @@ class PGPKeyArmorSettingTableViewController: UITableViewController {
@IBOutlet weak var armorPublicKeyTextView: UITextView! @IBOutlet weak var armorPublicKeyTextView: UITextView!
@IBOutlet weak var armorPrivateKeyTextView: UITextView! @IBOutlet weak var armorPrivateKeyTextView: UITextView!
var pgpPassphrase: String? var pgpPassphrase: String?
let passwordStore = PasswordStore.shared
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
armorPublicKeyTextView.text = Defaults[.pgpPublicKeyArmor] armorPublicKeyTextView.text = Defaults[.pgpPublicKeyArmor]
armorPrivateKeyTextView.text = Defaults[.pgpPrivateKeyArmor] armorPrivateKeyTextView.text = Defaults[.pgpPrivateKeyArmor]
pgpPassphrase = PasswordStore.shared.pgpKeyPassphrase pgpPassphrase = passwordStore.pgpKeyPassphrase
} }
private func createSavePassphraseAlert() -> UIAlertController { private func createSavePassphraseAlert() -> UIAlertController {

View file

@ -14,13 +14,14 @@ class PGPKeySettingTableViewController: UITableViewController {
@IBOutlet weak var pgpPublicKeyURLTextField: UITextField! @IBOutlet weak var pgpPublicKeyURLTextField: UITextField!
@IBOutlet weak var pgpPrivateKeyURLTextField: UITextField! @IBOutlet weak var pgpPrivateKeyURLTextField: UITextField!
var pgpPassphrase: String? var pgpPassphrase: String?
let passwordStore = PasswordStore.shared
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension tableView.rowHeight = UITableViewAutomaticDimension
pgpPublicKeyURLTextField.text = Defaults[.pgpPublicKeyURL]?.absoluteString pgpPublicKeyURLTextField.text = Defaults[.pgpPublicKeyURL]?.absoluteString
pgpPrivateKeyURLTextField.text = Defaults[.pgpPrivateKeyURL]?.absoluteString pgpPrivateKeyURLTextField.text = Defaults[.pgpPrivateKeyURL]?.absoluteString
pgpPassphrase = PasswordStore.shared.pgpKeyPassphrase pgpPassphrase = passwordStore.pgpKeyPassphrase
} }
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {

View file

@ -18,17 +18,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
var passwordImage: UIImage? var passwordImage: UIImage?
var oneTimePasswordIndexPath : IndexPath? var oneTimePasswordIndexPath : IndexPath?
var shouldPopCurrentView = false var shouldPopCurrentView = false
let passwordStore = PasswordStore.shared
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 = {
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
@ -81,7 +71,6 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
indicator.startAnimating() indicator.startAnimating()
tableView.addSubview(indicator) tableView.addSubview(indicator)
tableView.addSubview(indicatorLable)
editUIBarButtonItem.isEnabled = false editUIBarButtonItem.isEnabled = false
navigationItem.rightBarButtonItem = editUIBarButtonItem navigationItem.rightBarButtonItem = editUIBarButtonItem
@ -91,8 +80,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
var passphrase = "" var passphrase = ""
if Defaults[.isRememberPassphraseOn] && PasswordStore.shared.pgpKeyPassphrase != nil { if Defaults[.isRememberPassphraseOn] && self.passwordStore.pgpKeyPassphrase != nil {
passphrase = PasswordStore.shared.pgpKeyPassphrase! passphrase = self.passwordStore.pgpKeyPassphrase!
self.decryptThenShowPassword(passphrase: passphrase) self.decryptThenShowPassword(passphrase: passphrase)
} else { } else {
let alert = UIAlertController(title: "Passphrase", 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)
@ -114,7 +103,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
func decryptThenShowPassword(passphrase: String) { func decryptThenShowPassword(passphrase: String) {
if Defaults[.isRememberPassphraseOn] { if Defaults[.isRememberPassphraseOn] {
PasswordStore.shared.pgpKeyPassphrase = passphrase self.passwordStore.pgpKeyPassphrase = passphrase
} }
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
do { do {
@ -141,7 +130,6 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
setTableData() setTableData()
self.tableView.reloadData() self.tableView.reloadData()
indicator.stopAnimating() indicator.stopAnimating()
indicatorLable.isHidden = true
editUIBarButtonItem.isEnabled = true editUIBarButtonItem.isEnabled = true
if let urlString = password.getURLString() { if let urlString = password.getURLString() {
if self.passwordEntity?.image == nil{ if self.passwordEntity?.image == nil{
@ -188,15 +176,14 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
if self.password!.changed { if self.password!.changed {
SVProgressHUD.show(withStatus: "Saving") SVProgressHUD.show(withStatus: "Saving")
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
PasswordStore.shared.update(passwordEntity: self.passwordEntity!, password: self.password!, progressBlock: { progress in self.passwordStore.update(passwordEntity: self.passwordEntity!, password: self.password!, progressBlock: { progress in
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showProgress(progress, status: "Encrypting") SVProgressHUD.showProgress(progress, status: "Encrypting")
} }
}) })
DispatchQueue.main.async { DispatchQueue.main.async {
self.passwordEntity!.synced = false self.passwordEntity!.synced = false
PasswordStore.shared.saveUpdated(passwordEntity: self.passwordEntity!) self.passwordStore.saveUpdated(passwordEntity: self.passwordEntity!)
NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated")))
self.setTableData() self.setTableData()
self.tableView.reloadData() self.tableView.reloadData()
SVProgressHUD.showSuccess(withStatus: "Success") SVProgressHUD.showSuccess(withStatus: "Success")
@ -296,7 +283,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
self?.tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic) self?.tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
let imageData = UIImageJPEGRepresentation(image, 1) let imageData = UIImageJPEGRepresentation(image, 1)
if let entity = self?.passwordEntity { if let entity = self?.passwordEntity {
PasswordStore.shared.updateImage(passwordEntity: entity, image: imageData) self?.passwordStore.updateImage(passwordEntity: entity, image: imageData)
} }
case .failure(let error): case .failure(let error):
print(error) print(error)
@ -373,7 +360,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
footerLabel.numberOfLines = 0 footerLabel.numberOfLines = 0
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote) footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
footerLabel.textColor = UIColor.gray footerLabel.textColor = UIColor.gray
let dateString = PasswordStore.shared.getLatestUpdateInfo(filename: (passwordEntity?.path)!) let dateString = self.passwordStore.getLatestUpdateInfo(filename: (passwordEntity?.path)!)
footerLabel.text = "Last Updated: \(dateString)" footerLabel.text = "Last Updated: \(dateString)"
view.addSubview(footerLabel) view.addSubview(footerLabel)
return view return view
@ -396,7 +383,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
private func addNotificationObservers() { private func addNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: NSNotification.Name(rawValue: "passwordStoreChangeDiscarded"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil)
} }
func setShouldPopCurrentView() { func setShouldPopCurrentView() {

View file

@ -25,6 +25,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
private var passwordsTableEntries: [PasswordsTableEntry] = [] private var passwordsTableEntries: [PasswordsTableEntry] = []
private var filteredPasswordsTableEntries: [PasswordsTableEntry] = [] private var filteredPasswordsTableEntries: [PasswordsTableEntry] = []
private var parentPasswordEntity: PasswordEntity? = nil private var parentPasswordEntity: PasswordEntity? = nil
let passwordStore = PasswordStore.shared
private var tapTabBarTime: TimeInterval = 0 private var tapTabBarTime: TimeInterval = 0
@ -61,9 +62,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
filteredPasswordsTableEntries.removeAll() filteredPasswordsTableEntries.removeAll()
var passwordEntities = [PasswordEntity]() var passwordEntities = [PasswordEntity]()
if Defaults[.isShowFolderOn] { if Defaults[.isShowFolderOn] {
passwordEntities = PasswordStore.shared.fetchPasswordEntityCoreData(parent: parent) passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(parent: parent)
} else { } else {
passwordEntities = PasswordStore.shared.fetchPasswordEntityCoreData(withDir: false) passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
} }
passwordsTableEntries = passwordEntities.map { passwordsTableEntries = passwordEntities.map {
@ -82,7 +83,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
SVProgressHUD.show(withStatus: "Saving") SVProgressHUD.show(withStatus: "Saving")
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
do { do {
try PasswordStore.shared.add(password: controller.password!, progressBlock: { progress in try self.passwordStore.add(password: controller.password!, progressBlock: { progress in
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showProgress(progress, status: "Encrypting") SVProgressHUD.showProgress(progress, status: "Encrypting")
} }
@ -91,12 +92,10 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showSuccess(withStatus: "Done") SVProgressHUD.showSuccess(withStatus: "Done")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated")))
} }
} catch { } catch {
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showError(withStatus: error.localizedDescription) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
} }
@ -107,26 +106,26 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultMaskType(.black)
SVProgressHUD.setDefaultStyle(.light) SVProgressHUD.setDefaultStyle(.light)
SVProgressHUD.show(withStatus: "Sync Password Store") SVProgressHUD.show(withStatus: "Sync Password Store")
let numberOfUnsyncedPasswords = PasswordStore.shared.getNumberOfUnsyncedPasswords() let numberOfUnsyncedPasswords = self.passwordStore.getNumberOfUnsyncedPasswords()
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
do { do {
try PasswordStore.shared.pullRepository(transferProgressBlock: {(git_transfer_progress, stop) in try self.passwordStore.pullRepository(transferProgressBlock: {(git_transfer_progress, stop) in
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "Pull Remote Repository") SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "Pull Remote Repository")
} }
}) })
if numberOfUnsyncedPasswords > 0 { if numberOfUnsyncedPasswords > 0 {
try PasswordStore.shared.pushRepository(transferProgressBlock: {(current, total, bytes, stop) in try self.passwordStore.pushRepository(transferProgressBlock: {(current, total, bytes, stop) in
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(current)/Float(total), status: "Push Remote Repository") SVProgressHUD.showProgress(Float(current)/Float(total), status: "Push Remote Repository")
} }
}) })
} }
DispatchQueue.main.async { DispatchQueue.main.async {
PasswordStore.shared.updatePasswordEntityCoreData() self.passwordStore.updatePasswordEntityCoreData()
self.initPasswordsTableEntries(parent: nil) self.initPasswordsTableEntries(parent: nil)
self.reloadTableView(data: self.passwordsTableEntries) self.reloadTableView(data: self.passwordsTableEntries)
PasswordStore.shared.setAllSynced() self.passwordStore.setAllSynced()
self.setNavigationItemTitle() self.setNavigationItemTitle()
Defaults[.lastUpdatedTime] = Date() Defaults[.lastUpdatedTime] = Date()
Defaults[.gitRepositoryPasswordAttempts] = 0 Defaults[.gitRepositoryPasswordAttempts] = 0
@ -135,17 +134,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} }
} catch { } catch {
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showError(withStatus: error.localizedDescription) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
} }
} }
private func addNotificationObservers() { private func addNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(PasswordsViewController.actOnPasswordUpdatedNotification), name: NSNotification.Name(rawValue: "passwordUpdated"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(PasswordsViewController.actOnPasswordStoreUpdatedNotification), name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(PasswordsViewController.actOnPasswordStoreErasedNotification), name: NSNotification.Name(rawValue: "passwordStoreErased"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(PasswordsViewController.actOnSearchNotification), name: .passwordSearch, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(PasswordsViewController.actOnSearchNotification), name: NSNotification.Name(rawValue: "search"), object: nil)
} }
override func viewDidLoad() { override func viewDidLoad() {
@ -283,15 +280,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} }
func copyToPasteboard(from indexPath: IndexPath) { func copyToPasteboard(from indexPath: IndexPath) {
guard Defaults[.pgpKeyID] != nil else { guard self.passwordStore.privateKey != nil else {
Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil)
return return
} }
let password = getPasswordEntry(by: indexPath).passwordEntity! let password = getPasswordEntry(by: indexPath).passwordEntity!
UIImpactFeedbackGenerator(style: .medium).impactOccurred() UIImpactFeedbackGenerator(style: .medium).impactOccurred()
var passphrase = "" var passphrase = ""
if Defaults[.isRememberPassphraseOn] && PasswordStore.shared.pgpKeyPassphrase != nil { if Defaults[.isRememberPassphraseOn] && self.passwordStore.pgpKeyPassphrase != nil {
passphrase = PasswordStore.shared.pgpKeyPassphrase! passphrase = self.passwordStore.pgpKeyPassphrase!
self.decryptThenCopyPassword(passwordEntity: password, passphrase: passphrase) self.decryptThenCopyPassword(passwordEntity: password, passphrase: passphrase)
} else { } else {
let alert = UIAlertController(title: "Passphrase", 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)
@ -324,8 +321,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} catch { } catch {
print(error) print(error)
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showError(withStatus: error.localizedDescription) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
} }
@ -353,7 +349,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
sections.append(newSection) sections.append(newSection)
} }
func actOnPasswordUpdatedNotification() { func actOnPasswordStoreUpdatedNotification() {
initPasswordsTableEntries(parent: nil) initPasswordsTableEntries(parent: nil)
reloadTableView(data: passwordsTableEntries) reloadTableView(data: passwordsTableEntries)
setNavigationItemTitle() setNavigationItemTitle()
@ -366,7 +362,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} else { } else {
title = "Password Store" title = "Password Store"
} }
let numberOfUnsynced = PasswordStore.shared.getNumberOfUnsyncedPasswords() let numberOfUnsynced = self.passwordStore.getNumberOfUnsyncedPasswords()
if numberOfUnsynced == 0 { if numberOfUnsynced == 0 {
navigationItem.title = "\(title)" navigationItem.title = "\(title)"
} else { } else {
@ -374,12 +370,6 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} }
} }
func actOnPasswordStoreErasedNotification() {
initPasswordsTableEntries(parent: nil)
reloadTableView(data: passwordsTableEntries)
setNavigationItemTitle()
}
func actOnSearchNotification() { func actOnSearchNotification() {
searchController.searchBar.becomeFirstResponder() searchController.searchBar.becomeFirstResponder()
} }
@ -387,7 +377,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "showPasswordDetail" { if identifier == "showPasswordDetail" {
if Defaults[.pgpKeyID] == nil { guard self.passwordStore.privateKey != nil else {
Utils.alert(title: "Cannot Show Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) Utils.alert(title: "Cannot Show Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil)
if let s = sender as? UITableViewCell { if let s = sender as? UITableViewCell {
let selectedIndexPath = tableView.indexPath(for: s)! let selectedIndexPath = tableView.indexPath(for: s)!

View file

@ -49,9 +49,7 @@ class SSHKeySettingTableViewController: UITableViewController {
try Data(contentsOf: Defaults[.gitRepositorySSHPublicKeyURL]!).write(to: Globals.sshPublicKeyURL, options: .atomic) try Data(contentsOf: Defaults[.gitRepositorySSHPublicKeyURL]!).write(to: Globals.sshPublicKeyURL, options: .atomic)
try Data(contentsOf: Defaults[.gitRepositorySSHPrivateKeyURL]!).write(to: Globals.sshPrivateKeyURL, options: .atomic) try Data(contentsOf: Defaults[.gitRepositorySSHPrivateKeyURL]!).write(to: Globals.sshPrivateKeyURL, options: .atomic)
} catch { } catch {
SVProgressHUD.showError(withStatus: error.localizedDescription) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.dismiss(withDelay: 1)
print(error)
} }
navigationController!.popViewController(animated: true) navigationController!.popViewController(animated: true)

View file

@ -25,6 +25,7 @@ class SettingsTableViewController: UITableViewController {
@IBOutlet weak var touchIDTableViewCell: UITableViewCell! @IBOutlet weak var touchIDTableViewCell: UITableViewCell!
@IBOutlet weak var passcodeTableViewCell: UITableViewCell! @IBOutlet weak var passcodeTableViewCell: UITableViewCell!
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell! @IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
let passwordStore = PasswordStore.shared
@IBAction func cancelPGPKey(segue: UIStoryboardSegue) { @IBAction func cancelPGPKey(segue: UIStoryboardSegue) {
} }
@ -33,7 +34,7 @@ class SettingsTableViewController: UITableViewController {
if let controller = segue.source as? PGPKeySettingTableViewController { if let controller = segue.source as? PGPKeySettingTableViewController {
Defaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!) Defaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!)
Defaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!) Defaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!)
PasswordStore.shared.pgpKeyPassphrase = controller.pgpPassphrase self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
Defaults[.pgpKeySource] = "url" Defaults[.pgpKeySource] = "url"
SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultMaskType(.black)
@ -41,12 +42,10 @@ class SettingsTableViewController: UITableViewController {
SVProgressHUD.show(withStatus: "Fetching PGP Key") SVProgressHUD.show(withStatus: "Fetching PGP Key")
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
do { do {
try PasswordStore.shared.initPGP(pgpPublicKeyURL: Defaults[.pgpPublicKeyURL]!, try self.passwordStore.initPGPKey(from: Defaults[.pgpPublicKeyURL]!, keyType: .public)
pgpPublicKeyLocalPath: Globals.pgpPublicKeyPath, try self.passwordStore.initPGPKey(from: Defaults[.pgpPrivateKeyURL]!, keyType: .secret)
pgpPrivateKeyURL: Defaults[.pgpPrivateKeyURL]!,
pgpPrivateKeyLocalPath: Globals.pgpPrivateKeyPath)
DispatchQueue.main.async { DispatchQueue.main.async {
self.pgpKeyTableViewCell.detailTextLabel?.text = Defaults[.pgpKeyID] self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
SVProgressHUD.showSuccess(withStatus: "Success") SVProgressHUD.showSuccess(withStatus: "Success")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
Utils.alert(title: "Rememver to Remove the Key", message: "Remember to remove the key from the server.", controller: self, completion: nil) Utils.alert(title: "Rememver to Remove the Key", message: "Remember to remove the key from the server.", controller: self, completion: nil)
@ -54,16 +53,14 @@ class SettingsTableViewController: UITableViewController {
} catch { } catch {
DispatchQueue.main.async { DispatchQueue.main.async {
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
Defaults[.pgpKeyID] = nil Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.showError(withStatus: error.localizedDescription)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
} }
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController { } else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
Defaults[.pgpKeySource] = "armor" Defaults[.pgpKeySource] = "armor"
PasswordStore.shared.pgpKeyPassphrase = controller.pgpPassphrase self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
if Defaults[.isRememberPassphraseOn] { if Defaults[.isRememberPassphraseOn] {
Utils.addPasswordToKeychain(name: "pgpKeyPassphrase", password: controller.pgpPassphrase!) Utils.addPasswordToKeychain(name: "pgpKeyPassphrase", password: controller.pgpPassphrase!)
} }
@ -76,21 +73,17 @@ class SettingsTableViewController: UITableViewController {
SVProgressHUD.show(withStatus: "Fetching PGP Key") SVProgressHUD.show(withStatus: "Fetching PGP Key")
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
do { do {
try PasswordStore.shared.initPGP(pgpPublicKeyArmor: controller.armorPublicKeyTextView.text!, try self.passwordStore.initPGPKey(with: controller.armorPublicKeyTextView.text, keyType: .public)
pgpPublicKeyLocalPath: Globals.pgpPublicKeyPath, try self.passwordStore.initPGPKey(with: controller.armorPrivateKeyTextView.text, keyType: .secret)
pgpPrivateKeyArmor: controller.armorPrivateKeyTextView.text!,
pgpPrivateKeyLocalPath: Globals.pgpPrivateKeyPath)
DispatchQueue.main.async { DispatchQueue.main.async {
self.pgpKeyTableViewCell.detailTextLabel?.text = Defaults[.pgpKeyID] self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
SVProgressHUD.showSuccess(withStatus: "Success") SVProgressHUD.showSuccess(withStatus: "Success")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} }
} catch { } catch {
DispatchQueue.main.async { DispatchQueue.main.async {
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
Defaults[.pgpKeyID] = nil Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.showError(withStatus: error.localizedDescription)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
} }
@ -111,8 +104,8 @@ class SettingsTableViewController: UITableViewController {
Defaults[.gitRepositoryURL]!.absoluteString != gitRepostiroyURL || Defaults[.gitRepositoryURL]!.absoluteString != gitRepostiroyURL ||
auth != Defaults[.gitRepositoryAuthenticationMethod] || auth != Defaults[.gitRepositoryAuthenticationMethod] ||
username != Defaults[.gitRepositoryUsername] || username != Defaults[.gitRepositoryUsername] ||
password != PasswordStore.shared.gitRepositoryPassword || password != self.passwordStore.gitRepositoryPassword ||
PasswordStore.shared.repositoryExisted() == false { self.passwordStore.repositoryExisted() == false {
SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultMaskType(.black)
SVProgressHUD.setDefaultStyle(.light) SVProgressHUD.setDefaultStyle(.light)
@ -134,7 +127,7 @@ class SettingsTableViewController: UITableViewController {
let dispatchQueue = DispatchQueue.global(qos: .userInitiated) let dispatchQueue = DispatchQueue.global(qos: .userInitiated)
dispatchQueue.async { dispatchQueue.async {
do { do {
try PasswordStore.shared.cloneRepository(remoteRepoURL: URL(string: gitRepostiroyURL)!, try self.passwordStore.cloneRepository(remoteRepoURL: URL(string: gitRepostiroyURL)!,
credential: gitCredential, credential: gitCredential,
transferProgressBlock:{ (git_transfer_progress, stop) in transferProgressBlock:{ (git_transfer_progress, stop) in
DispatchQueue.main.async { DispatchQueue.main.async {
@ -147,9 +140,8 @@ class SettingsTableViewController: UITableViewController {
} }
}) })
DispatchQueue.main.async { DispatchQueue.main.async {
PasswordStore.shared.updatePasswordEntityCoreData() self.passwordStore.updatePasswordEntityCoreData()
Defaults[.lastUpdatedTime] = Date() Defaults[.lastUpdatedTime] = Date()
NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated")))
Defaults[.gitRepositoryURL] = URL(string: gitRepostiroyURL) Defaults[.gitRepositoryURL] = URL(string: gitRepostiroyURL)
Defaults[.gitRepositoryUsername] = username Defaults[.gitRepositoryUsername] = username
Defaults[.gitRepositoryAuthenticationMethod] = auth Defaults[.gitRepositoryAuthenticationMethod] = auth
@ -160,9 +152,7 @@ class SettingsTableViewController: UITableViewController {
} }
} catch { } catch {
DispatchQueue.main.async { DispatchQueue.main.async {
print(error) Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
SVProgressHUD.showError(withStatus: error.localizedDescription)
SVProgressHUD.dismiss(withDelay: 1)
} }
} }
@ -173,7 +163,7 @@ class SettingsTableViewController: UITableViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: NSNotification.Name(rawValue: "passwordStoreErased"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]?.host self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]?.host
touchIDTableViewCell.accessoryView = touchIDSwitch touchIDTableViewCell.accessoryView = touchIDSwitch
setPGPKeyTableViewCellDetailText() setPGPKeyTableViewCellDetailText()
@ -193,10 +183,10 @@ class SettingsTableViewController: UITableViewController {
} }
private func setPGPKeyTableViewCellDetailText() { private func setPGPKeyTableViewCellDetailText() {
if Defaults[.pgpKeyID] == nil { if let pgpKeyID = self.passwordStore.pgpKeyID {
pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID
} else { } else {
pgpKeyTableViewCell.detailTextLabel?.text = Defaults[.pgpKeyID] pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
} }
} }
@ -230,7 +220,7 @@ class SettingsTableViewController: UITableViewController {
})) }))
alert.addTextField(configurationHandler: {(textField: UITextField!) in alert.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = PasswordStore.shared.gitRepositoryPassword textField.text = self.passwordStore.gitRepositoryPassword
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
}) })
@ -343,12 +333,9 @@ class SettingsTableViewController: UITableViewController {
DispatchQueue.main.async { DispatchQueue.main.async {
try? PasswordStore.shared.initPGP( self.passwordStore.initPGPKeys()
pgpPublicKeyLocalPath: Globals.pgpPublicKeyPath,
pgpPrivateKeyLocalPath: Globals.pgpPrivateKeyPath
)
let key: PGPKey = PasswordStore.shared.getPgpPrivateKey() let key: PGPKey = self.passwordStore.getPgpPrivateKey()
Defaults[.pgpKeySource] = "file" Defaults[.pgpKeySource] = "file"
if (key.isEncrypted) { if (key.isEncrypted) {
@ -357,7 +344,7 @@ class SettingsTableViewController: UITableViewController {
} }
SVProgressHUD.dismiss() SVProgressHUD.dismiss()
self.pgpKeyTableViewCell.detailTextLabel?.text = Defaults[.pgpKeyID] self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
} }
} }

View file

@ -17,8 +17,6 @@ extension DefaultsKeys {
static let pgpPublicKeyArmor = DefaultsKey<String?>("pgpPublicKeyArmor") static let pgpPublicKeyArmor = DefaultsKey<String?>("pgpPublicKeyArmor")
static let pgpPrivateKeyArmor = DefaultsKey<String?>("pgpPrivateKeyArmor") static let pgpPrivateKeyArmor = DefaultsKey<String?>("pgpPrivateKeyArmor")
static let pgpKeyID = DefaultsKey<String?>("pgpKeyID")
static let pgpKeyUserID = DefaultsKey<String?>("pgpKeyUserID")
static let gitRepositoryURL = DefaultsKey<URL?>("gitRepositoryURL") static let gitRepositoryURL = DefaultsKey<URL?>("gitRepositoryURL")
static let gitRepositoryAuthenticationMethod = DefaultsKey<String?>("gitRepositoryAuthenticationMethod") static let gitRepositoryAuthenticationMethod = DefaultsKey<String?>("gitRepositoryAuthenticationMethod")

View file

@ -0,0 +1,16 @@
//
// NotificationNames.swift
// pass
//
// Created by Yishi Lin on 17/3/17.
// Copyright © 2017 Yishi Lin, Bob Sun. All rights reserved.
//
import Foundation
extension Notification.Name {
static let passwordStoreUpdated = Notification.Name("passwordStoreUpdated")
static let passwordStoreErased = Notification.Name("passwordStoreErased")
static let passwordStoreChangeDiscarded = Notification.Name("passwordStoreChangeDiscarded")
static let passwordSearch = Notification.Name("passwordSearch")
}

View file

@ -10,6 +10,7 @@ import Foundation
import SwiftyUserDefaults import SwiftyUserDefaults
import KeychainAccess import KeychainAccess
import UIKit import UIKit
import SVProgressHUD
class Utils { class Utils {
static func removeFileIfExists(atPath path: String) { static func removeFileIfExists(atPath path: String) {
@ -65,6 +66,7 @@ class Utils {
} }
static func alert(title: String, message: String, controller: UIViewController, completion: (() -> Void)?) { static func alert(title: String, message: String, controller: UIViewController, completion: (() -> Void)?) {
SVProgressHUD.dismiss()
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert) let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
controller.present(alert, animated: true, completion: completion) controller.present(alert, animated: true, completion: completion)
@ -79,7 +81,6 @@ class Utils {
Defaults.remove(.pgpPrivateKeyArmor) Defaults.remove(.pgpPrivateKeyArmor)
Defaults.remove(.pgpPrivateKeyURL) Defaults.remove(.pgpPrivateKeyURL)
Defaults.remove(.pgpPublicKeyURL) Defaults.remove(.pgpPublicKeyURL)
Defaults.remove(.pgpKeyID)
Utils.removeKeychain(name: ".pgpKeyPassphrase") Utils.removeKeychain(name: ".pgpKeyPassphrase")
} }

View file

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.2</string> <string>0.2.1</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>24</string> <string>1</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
@ -35,6 +35,8 @@
<string>$(PRODUCT_BUNDLE_IDENTIFIER).search</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER).search</string>
</dict> </dict>
</array> </array>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>Main</string> <string>Main</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
@ -43,8 +45,6 @@
<array> <array>
<string>armv7</string> <string>armv7</string>
</array> </array>
<key>UIFileSharingEnabled</key>
<true/>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>

View file

@ -93,11 +93,23 @@ struct GitCredential {
class PasswordStore { class PasswordStore {
static let shared = PasswordStore() static let shared = PasswordStore()
let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)") let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)")
let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp") let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp")
var storeRepository: GTRepository? var storeRepository: GTRepository?
var gitCredential: GitCredential? var gitCredential: GitCredential?
var pgpKeyID: String?
var publicKey: PGPKey? {
didSet {
if publicKey != nil {
pgpKeyID = publicKey!.keyID!.shortKeyString
} else {
pgpKeyID = nil
}
}
}
var privateKey: PGPKey?
var gitSignatureForNow: GTSignature { var gitSignatureForNow: GTSignature {
get { get {
return GTSignature(name: Defaults[.gitRepositoryUsername]!, email: Defaults[.gitRepositoryUsername]!+"@passforios", time: Date())! return GTSignature(name: Defaults[.gitRepositoryUsername]!, email: Defaults[.gitRepositoryUsername]!+"@passforios", time: Date())!
@ -134,11 +146,7 @@ class PasswordStore {
} catch { } catch {
print(error) print(error)
} }
if Defaults[.pgpKeyID] != nil { initPGPKeys()
pgp.importKeys(fromFile: Globals.pgpPublicKeyPath, allowDuplicates: false)
pgp.importKeys(fromFile: Globals.pgpPrivateKeyPath, allowDuplicates: false)
}
if Defaults[.gitRepositoryAuthenticationMethod] == "Password" { if Defaults[.gitRepositoryAuthenticationMethod] == "Password" {
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitRepositoryUsername]!, password: Utils.getPasswordFromKeychain(name: "gitRepositoryPassword") ?? "")) gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitRepositoryUsername]!, password: Utils.getPasswordFromKeychain(name: "gitRepositoryPassword") ?? ""))
} else if Defaults[.gitRepositoryAuthenticationMethod] == "SSH Key"{ } else if Defaults[.gitRepositoryAuthenticationMethod] == "SSH Key"{
@ -157,28 +165,74 @@ class PasswordStore {
} }
func initPGP(pgpPublicKeyLocalPath: String, pgpPrivateKeyLocalPath: String) throws { public func initPGPKeys() {
let pgpPublicKeyData = NSData(contentsOfFile: pgpPublicKeyLocalPath)! as Data do {
if pgpPublicKeyData.count == 0 { try initPGPKey(.public)
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import public key."]) try initPGPKey(.secret)
} catch {
print(error)
} }
pgp.importKeys(from: pgpPublicKeyData, allowDuplicates: false) }
if pgp.getKeysOf(.public).count == 0 {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import public key."]) public func initPGPKey(_ keyType: PGPKeyType) throws {
var keyPath = ""
switch keyType {
case .public:
keyPath = Globals.pgpPublicKeyPath
case .secret:
keyPath = Globals.pgpPrivateKeyPath
default:
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import key."])
} }
let pgpPrivateKeyData = NSData(contentsOfFile: pgpPrivateKeyLocalPath)! as Data
if pgpPrivateKeyData.count == 0 { if let key = importKey(from: keyPath) {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import public key."]) switch keyType {
case .public:
self.publicKey = key
case .secret:
self.privateKey = key
default:
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import key."])
}
} else {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import key."])
} }
pgp.importKeys(from: pgpPrivateKeyData, allowDuplicates: false) }
if pgp.getKeysOf(.secret).count == 0 {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import seceret key."]) public func initPGPKey(from url: URL, keyType: PGPKeyType) throws{
var pgpKeyLocalPath = ""
if keyType == .public {
pgpKeyLocalPath = Globals.pgpPublicKeyPath
} else {
pgpKeyLocalPath = Globals.pgpPrivateKeyPath
} }
let key: PGPKey = getPgpPrivateKey() let pgpKeyData = try Data(contentsOf: url)
Defaults[.pgpKeyID] = key.keyID!.shortKeyString try pgpKeyData.write(to: URL(fileURLWithPath: pgpKeyLocalPath), options: .atomic)
if let gpgUser = key.users[0] as? PGPUser { try initPGPKey(keyType)
Defaults[.pgpKeyUserID] = gpgUser.userID }
public func initPGPKey(with armorKey: String, keyType: PGPKeyType) throws {
var pgpKeyLocalPath = ""
if keyType == .public {
pgpKeyLocalPath = Globals.pgpPublicKeyPath
} else {
pgpKeyLocalPath = Globals.pgpPrivateKeyPath
} }
try armorKey.write(toFile: pgpKeyLocalPath, atomically: true, encoding: .ascii)
try initPGPKey(keyType)
}
private func importKey(from keyPath: String) -> PGPKey? {
let fm = FileManager.default
if fm.fileExists(atPath: keyPath) {
if let keys = pgp.importKeys(fromFile: keyPath, allowDuplicates: false) as? [PGPKey] {
if keys.count > 0 {
return keys[0]
}
}
}
return nil
} }
func getPgpPrivateKey() -> PGPKey { func getPgpPrivateKey() -> PGPKey {
@ -207,20 +261,6 @@ class PasswordStore {
return true return true
} }
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)
try initPGP(pgpPublicKeyLocalPath: pgpPublicKeyLocalPath, pgpPrivateKeyLocalPath: pgpPrivateKeyLocalPath)
}
func initPGP(pgpPublicKeyArmor: String, pgpPublicKeyLocalPath: String, pgpPrivateKeyArmor: String, pgpPrivateKeyLocalPath: String) throws {
try pgpPublicKeyArmor.write(toFile: pgpPublicKeyLocalPath, atomically: true, encoding: .ascii)
try pgpPrivateKeyArmor.write(toFile: pgpPrivateKeyLocalPath, atomically: true, encoding: .ascii)
try initPGP(pgpPublicKeyLocalPath: pgpPublicKeyLocalPath, pgpPrivateKeyLocalPath: pgpPrivateKeyLocalPath)
}
func cloneRepository(remoteRepoURL: URL, func cloneRepository(remoteRepoURL: URL,
credential: GitCredential, credential: GitCredential,
transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void, transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void,
@ -245,6 +285,7 @@ class PasswordStore {
} }
storeRepository = try GTRepository(url: storeURL) storeRepository = try GTRepository(url: storeURL)
gitCredential = credential gitCredential = credential
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} }
func pullRepository(transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws { func pullRepository(transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
@ -257,6 +298,7 @@ class PasswordStore {
] ]
let remote = try GTRemote(name: "origin", in: storeRepository!) let remote = try GTRemote(name: "origin", in: storeRepository!)
try storeRepository?.pull((storeRepository?.currentBranch())!, from: remote, withOptions: options, progress: transferProgressBlock) try storeRepository?.pull((storeRepository?.currentBranch())!, from: remote, withOptions: options, progress: transferProgressBlock)
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} }
@ -502,18 +544,22 @@ class PasswordStore {
print(saveURL.path) print(saveURL.path)
let _ = createAddCommitInRepository(message: "Add password for \(passwordEntity.nameWithCategory) to store using Pass for iOS.", fileData: encryptedData, filename: saveURL.lastPathComponent, progressBlock: progressBlock) let _ = createAddCommitInRepository(message: "Add password for \(passwordEntity.nameWithCategory) to store using Pass for iOS.", fileData: encryptedData, filename: saveURL.lastPathComponent, progressBlock: progressBlock)
progressBlock(1.0) progressBlock(1.0)
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} catch { } catch {
print(error) print(error)
} }
} }
func update(passwordEntity: PasswordEntity, password: Password, progressBlock: (_ progress: Float) -> Void) { func update(passwordEntity: PasswordEntity, password: Password, progressBlock: (_ progress: Float) -> Void) {
progressBlock(0.0)
do { do {
let encryptedData = try passwordEntity.encrypt(password: password) let encryptedData = try passwordEntity.encrypt(password: password)
let saveURL = storeURL.appendingPathComponent(passwordEntity.path!) let saveURL = storeURL.appendingPathComponent(passwordEntity.path!)
try encryptedData.write(to: saveURL) try encryptedData.write(to: saveURL)
progressBlock(0.3) progressBlock(0.3)
let _ = createAddCommitInRepository(message: "Edit password for \(passwordEntity.nameWithCategory) using Pass for iOS.", fileData: encryptedData, filename: saveURL.lastPathComponent, progressBlock: progressBlock) let _ = createAddCommitInRepository(message: "Edit password for \(passwordEntity.nameWithCategory) using Pass for iOS.", fileData: encryptedData, filename: saveURL.lastPathComponent, progressBlock: progressBlock)
progressBlock(1.0)
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
} catch { } catch {
print(error) print(error)
} }
@ -564,6 +610,8 @@ class PasswordStore {
} }
func erase() { func erase() {
publicKey = nil
privateKey = nil
Utils.removeFileIfExists(at: storeURL) Utils.removeFileIfExists(at: storeURL)
Utils.removeFileIfExists(at: tempStoreURL) Utils.removeFileIfExists(at: tempStoreURL)
@ -579,6 +627,9 @@ class PasswordStore {
Defaults.removeAll() Defaults.removeAll()
storeRepository = nil storeRepository = nil
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.post(name: .passwordStoreErased, object: nil)
} }
// return the number of discarded commits // return the number of discarded commits
@ -603,7 +654,8 @@ class PasswordStore {
} }
try self.storeRepository?.reset(to: newHead, resetType: GTRepositoryResetType.hard) try self.storeRepository?.reset(to: newHead, resetType: GTRepositoryResetType.hard)
self.updatePasswordEntityCoreData() self.updatePasswordEntityCoreData()
NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated"))) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil)
self.setAllSynced() self.setAllSynced()
return localCommits.count return localCommits.count
} else { } else {

View file

@ -19,6 +19,7 @@ class LabelTableViewCell: UITableViewCell {
@IBOutlet weak var contentLabel: UILabel! @IBOutlet weak var contentLabel: UILabel!
@IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var titleLabel: UILabel!
let passwordStore = PasswordStore.shared
var isPasswordCell = false var isPasswordCell = false
var isURLCell = false var isURLCell = false
@ -126,11 +127,10 @@ class LabelTableViewCell: UITableViewCell {
// commit // commit
if password.changed { if password.changed {
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
PasswordStore.shared.update(passwordEntity: passwordEntity, password: password, progressBlock: {_ in }) self.passwordStore.update(passwordEntity: passwordEntity, password: password, progressBlock: {_ in })
DispatchQueue.main.async { DispatchQueue.main.async {
passwordEntity.synced = false passwordEntity.synced = false
PasswordStore.shared.saveUpdated(passwordEntity: passwordEntity) self.passwordStore.saveUpdated(passwordEntity: passwordEntity)
NotificationCenter.default.post(Notification(name: Notification.Name("passwordUpdated")))
// reload so that the "unsynced" symbol could be added // reload so that the "unsynced" symbol could be added
self.passwordTableView?.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic) self.passwordTableView?.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
SVProgressHUD.showSuccess(withStatus: "Password Copied\nCounter Updated") SVProgressHUD.showSuccess(withStatus: "Password Copied\nCounter Updated")