Localize strings in code
This commit is contained in:
parent
2d5ca58bd9
commit
1b4040135e
36 changed files with 626 additions and 334 deletions
|
|
@ -26,6 +26,7 @@
|
||||||
30B04860209A5141001013CA /* PasswordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0485F209A5141001013CA /* PasswordTest.swift */; };
|
30B04860209A5141001013CA /* PasswordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0485F209A5141001013CA /* PasswordTest.swift */; };
|
||||||
30BF5EC821EA8FB5000E4154 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */; };
|
30BF5EC821EA8FB5000E4154 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */; };
|
||||||
30BF5ECF21EA90D1000E4154 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BF5ECE21EA90D1000E4154 /* String.swift */; };
|
30BF5ECF21EA90D1000E4154 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BF5ECE21EA90D1000E4154 /* String.swift */; };
|
||||||
|
30BF5ED721ED2434000E4154 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ED521ED2434000E4154 /* Localizable.stringsdict */; };
|
||||||
30FD2F78214D9E0E005E0A92 /* ParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */; };
|
30FD2F78214D9E0E005E0A92 /* ParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */; };
|
||||||
61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */; };
|
61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */; };
|
||||||
A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; };
|
A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; };
|
||||||
|
|
@ -208,6 +209,7 @@
|
||||||
30B0485F209A5141001013CA /* PasswordTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTest.swift; sourceTree = "<group>"; };
|
30B0485F209A5141001013CA /* PasswordTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTest.swift; sourceTree = "<group>"; };
|
||||||
30BF5EC921EA8FB5000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
30BF5EC921EA8FB5000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
30BF5ECE21EA90D1000E4154 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = String.swift; path = Localization/String.swift; sourceTree = "<group>"; };
|
30BF5ECE21EA90D1000E4154 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = String.swift; path = Localization/String.swift; sourceTree = "<group>"; };
|
||||||
|
30BF5ED621ED2434000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = "<group>"; };
|
30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = "<group>"; };
|
||||||
31C3033E8868D05B2C55C8B1 /* Pods-passExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
31C3033E8868D05B2C55C8B1 /* Pods-passExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
3A5620D17DF5E86B61761D0E /* Pods_pass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_pass.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
3A5620D17DF5E86B61761D0E /* Pods_pass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_pass.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
|
@ -703,6 +705,7 @@
|
||||||
DC917BDF1E2E8231000FDF54 /* LaunchScreen.storyboard */,
|
DC917BDF1E2E8231000FDF54 /* LaunchScreen.storyboard */,
|
||||||
DC917BDA1E2E8231000FDF54 /* Main.storyboard */,
|
DC917BDA1E2E8231000FDF54 /* Main.storyboard */,
|
||||||
30BF5ECA21EA8FB5000E4154 /* Localizable.strings */,
|
30BF5ECA21EA8FB5000E4154 /* Localizable.strings */,
|
||||||
|
30BF5ED521ED2434000E4154 /* Localizable.stringsdict */,
|
||||||
);
|
);
|
||||||
path = pass;
|
path = pass;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1015,6 +1018,7 @@
|
||||||
30BF5EC821EA8FB5000E4154 /* Localizable.strings in Resources */,
|
30BF5EC821EA8FB5000E4154 /* Localizable.strings in Resources */,
|
||||||
DCFB77A31E500D9C008DE471 /* PasswordDetailTitleTableViewCell.xib in Resources */,
|
DCFB77A31E500D9C008DE471 /* PasswordDetailTitleTableViewCell.xib in Resources */,
|
||||||
DC917BDE1E2E8231000FDF54 /* Assets.xcassets in Resources */,
|
DC917BDE1E2E8231000FDF54 /* Assets.xcassets in Resources */,
|
||||||
|
30BF5ED721ED2434000E4154 /* Localizable.stringsdict in Resources */,
|
||||||
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */,
|
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */,
|
||||||
DC917BDC1E2E8231000FDF54 /* Main.storyboard in Resources */,
|
DC917BDC1E2E8231000FDF54 /* Main.storyboard in Resources */,
|
||||||
A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */,
|
A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */,
|
||||||
|
|
@ -1324,6 +1328,14 @@
|
||||||
name = Localizable.strings;
|
name = Localizable.strings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
30BF5ED521ED2434000E4154 /* Localizable.stringsdict */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
30BF5ED621ED2434000E4154 /* en */,
|
||||||
|
);
|
||||||
|
name = Localizable.stringsdict;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A239F59A2158C08C00576CBF /* MainInterface.storyboard */ = {
|
A239F59A2158C08C00576CBF /* MainInterface.storyboard */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
* The store could not be migrated to the current model version.
|
* The store could not be migrated to the current model version.
|
||||||
Check the error message to determine what the actual problem was.
|
Check the error message to determine what the actual problem was.
|
||||||
*/
|
*/
|
||||||
fatalError("Unresolved error \(error), \(error.userInfo)")
|
fatalError("UnresolvedError".localize("\(error), \(error.userInfo)"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return container
|
return container
|
||||||
|
|
@ -157,7 +157,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
// Replace this implementation with code to handle the error appropriately.
|
||||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||||
let nserror = error as NSError
|
let nserror = error as NSError
|
||||||
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
|
fatalError("UnresolvedError".localize("\(nserror), \(nserror.userInfo)"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import passKit
|
||||||
|
|
||||||
class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
||||||
|
|
||||||
private static let VALUE_NOT_AVAILABLE = "Value not available"
|
private static let VALUE_NOT_AVAILABLE = "ValueNotAvailable".localize()
|
||||||
|
|
||||||
private var needRefresh = false
|
private var needRefresh = false
|
||||||
private var indicator: UIActivityIndicatorView = {
|
private var indicator: UIActivityIndicatorView = {
|
||||||
|
|
@ -62,12 +62,12 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
||||||
let type = UITableViewCellAccessoryType.none
|
let type = UITableViewCellAccessoryType.none
|
||||||
strongSelf.tableData = [
|
strongSelf.tableData = [
|
||||||
// section 0
|
// section 0
|
||||||
[[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: passwords],
|
[[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords".localize(), .detailText: passwords],
|
||||||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: size],
|
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Size".localize(), .detailText: size],
|
||||||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Local Commits", .detailText: localCommits],
|
[.style: CellDataStyle.value1, .accessoryType: type, .title: "LocalCommits".localize(), .detailText: localCommits],
|
||||||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: lastSynced],
|
[.style: CellDataStyle.value1, .accessoryType: type, .title: "LastSynced".localize(), .detailText: lastSynced],
|
||||||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: commits],
|
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits".localize(), .detailText: commits],
|
||||||
[.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"],
|
[.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"],
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
strongSelf.indicator.stopAnimating()
|
strongSelf.indicator.stopAnimating()
|
||||||
|
|
@ -95,7 +95,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
||||||
|
|
||||||
private func lastSyncedTimeString() -> String {
|
private func lastSyncedTimeString() -> String {
|
||||||
guard let date = self.passwordStore.lastSyncedTime else {
|
guard let date = self.passwordStore.lastSyncedTime else {
|
||||||
return "Oops! Sync again?"
|
return "SyncAgain?".localize()
|
||||||
}
|
}
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .medium
|
formatter.dateStyle = .medium
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ class AboutTableViewController: BasicStaticTableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
tableData = [
|
tableData = [
|
||||||
// section 0
|
// section 0
|
||||||
[[.title: "Website", .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
|
[[.title: "Website".localize(), .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
|
||||||
[.title: "Help", .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
|
[.title: "Help".localize(), .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
|
||||||
[.title: "Contact Developer", .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],],
|
[.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],],
|
||||||
|
|
||||||
// section 1,
|
// section 1,
|
||||||
[[.title: "Open Source Components", .action: "segue", .link: "showOpenSourceComponentsSegue"],
|
[[.title: "OpenSourceComponents".localize(), .action: "segue", .link: "showOpenSourceComponentsSegue"],
|
||||||
[.title: "Special Thanks", .action: "segue", .link: "showSpecialThanksSegue"],],
|
[.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"],],
|
||||||
]
|
]
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +29,7 @@ class AboutTableViewController: BasicStaticTableViewController {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
let footerLabel = UILabel(frame: CGRect(x: 8, y: 15, width: tableView.frame.width, height: 60))
|
let footerLabel = UILabel(frame: CGRect(x: 8, y: 15, width: tableView.frame.width, height: 60))
|
||||||
footerLabel.numberOfLines = 0
|
footerLabel.numberOfLines = 0
|
||||||
footerLabel.text = "Pass for iOS \(Bundle.main.releaseVersionNumber!) (\(Bundle.main.buildVersionNumber!))"
|
footerLabel.text = "PassForIos".localize() + " \(Bundle.main.releaseVersionNumber!) (\(Bundle.main.buildVersionNumber!))"
|
||||||
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
|
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||||
footerLabel.textColor = UIColor.lightGray
|
footerLabel.textColor = UIColor.lightGray
|
||||||
footerLabel.textAlignment = .center
|
footerLabel.textAlignment = .center
|
||||||
|
|
@ -41,7 +41,7 @@ class AboutTableViewController: BasicStaticTableViewController {
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||||
if section == 1 {
|
if section == 1 {
|
||||||
return "Acknowledgements".uppercased()
|
return "Acknowledgements".localize().uppercased()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
||||||
if identifier == "saveAddPasswordSegue" {
|
if identifier == "saveAddPasswordSegue" {
|
||||||
// check PGP key
|
// check PGP key
|
||||||
guard passwordStore.privateKey != nil else {
|
guard passwordStore.privateKey != nil else {
|
||||||
let alertTitle = "Cannot Add Password"
|
let alertTitle = "CannotAddPassword".localize()
|
||||||
let alertMessage = "PGP Key is not set. Please set your PGP Key first."
|
let alertMessage = "PgpKeyNotSet.".localize()
|
||||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,45 +41,38 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
||||||
self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
|
self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
|
||||||
if SharedDefaults[.gitSignatureName] == nil && SharedDefaults[.gitSignatureEmail] == nil {
|
if SharedDefaults[.gitSignatureName] == nil && SharedDefaults[.gitSignatureEmail] == nil {
|
||||||
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 17)
|
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 17)
|
||||||
gitSignatureTableViewCell.detailTextLabel?.text = "Not Set"
|
gitSignatureTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell {
|
if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell {
|
||||||
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: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "Erase Password Data", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
|
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
|
||||||
SVProgressHUD.show(withStatus: "Erasing ...")
|
SVProgressHUD.show(withStatus: "Erasing...".localize())
|
||||||
self.passwordStore.erase()
|
self.passwordStore.erase()
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil))
|
alert.addAction(UIAlertAction(title: "Dismiss".localize(), style: UIAlertActionStyle.cancel, handler:nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
} else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell {
|
} else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell {
|
||||||
let alert = UIAlertController(title: "Discard All Changes?", message: "Do you want to permanently discard all changes to the local copy of your password data? You cannot undo this action.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "Discard All Changes", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
|
alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
|
||||||
SVProgressHUD.show(withStatus: "Resetting ...")
|
SVProgressHUD.show(withStatus: "Resetting...".localize())
|
||||||
do {
|
do {
|
||||||
let numberDiscarded = try self.passwordStore.reset()
|
let numberDiscarded = try self.passwordStore.reset()
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
switch numberDiscarded {
|
SVProgressHUD.showSuccess(withStatus: "DiscardedCommits(%d)".localize(numberDiscarded))
|
||||||
case 0:
|
|
||||||
SVProgressHUD.showSuccess(withStatus: "No local commits")
|
|
||||||
case 1:
|
|
||||||
SVProgressHUD.showSuccess(withStatus: "Discarded 1 commit")
|
|
||||||
default:
|
|
||||||
SVProgressHUD.showSuccess(withStatus: "Discarded \(numberDiscarded) commits")
|
|
||||||
}
|
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil))
|
alert.addAction(UIAlertAction(title: "Dismiss".localize(), style: UIAlertActionStyle.cancel, handler:nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,8 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
||||||
sendEmail(toRecipients: [urlComponents.path], subject: subject)
|
sendEmail(toRecipients: [urlComponents.path], subject: subject)
|
||||||
} else {
|
} else {
|
||||||
let email = urlComponents.path
|
let email = urlComponents.path
|
||||||
let alertTitle = "Cannot open Mail App"
|
let alertTitle = "CannotOpenMail".localize()
|
||||||
let alertMessage = "Email copied: \(email)"
|
let alertMessage = "CopiedEmail".localize(email)
|
||||||
Utils.copyToPasteboard(textToCopy: email)
|
Utils.copyToPasteboard(textToCopy: email)
|
||||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ class CommitLogsTableViewController: UITableViewController {
|
||||||
do {
|
do {
|
||||||
return try passwordStore.getRecentCommits(count: 20)
|
return try passwordStore.getRecentCommits(count: 20)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,22 +58,22 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
tableData = [
|
tableData = [
|
||||||
// section 0
|
// section 0
|
||||||
[[.title: "About Repository", .action: "segue", .link: "showAboutRepositorySegue"],],
|
[[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"],],
|
||||||
|
|
||||||
// section 1
|
// section 1
|
||||||
[
|
[
|
||||||
[.title: "Password Generator Flavor", .action: "none", .style: CellDataStyle.value1],
|
[.title: "PasswordGeneratorFlavor".localize(), .action: "none", .style: CellDataStyle.value1],
|
||||||
],
|
],
|
||||||
|
|
||||||
// section 2
|
// section 2
|
||||||
[
|
[
|
||||||
[.title: "Remember PGP Key Passphrase", .action: "none",],
|
[.title: "RememberPgpKeyPassphrase".localize(), .action: "none",],
|
||||||
[.title: "Remember Git Credential Passphrase", .action: "none",],
|
[.title: "RememberGitCredentialPassphrase".localize(), .action: "none",],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
[.title: "Show Folders", .action: "none",],
|
[.title: "ShowFolders".localize(), .action: "none",],
|
||||||
[.title: "Hide Unknown Fields", .action: "none",],
|
[.title: "HideUnknownFields".localize(), .action: "none",],
|
||||||
[.title: "Hide OTP Fields", .action: "none",],
|
[.title: "HideOtpFields".localize(), .action: "none",],
|
||||||
],
|
],
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
@ -84,7 +84,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||||
switch cell.textLabel!.text! {
|
switch cell.textLabel!.text! {
|
||||||
case "Hide Unknown Fields":
|
case "HideUnknownFields".localize():
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
let detailButton = UIButton(type: .detailDisclosure)
|
let detailButton = UIButton(type: .detailDisclosure)
|
||||||
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
|
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
|
||||||
|
|
@ -96,7 +96,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
cell.accessoryView = accessoryView
|
cell.accessoryView = accessoryView
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
hideUnknownSwitch.isOn = SharedDefaults[.isHideUnknownOn]
|
hideUnknownSwitch.isOn = SharedDefaults[.isHideUnknownOn]
|
||||||
case "Hide OTP Fields":
|
case "HideOtpFields".localize():
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
let detailButton = UIButton(type: .detailDisclosure)
|
let detailButton = UIButton(type: .detailDisclosure)
|
||||||
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
|
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
|
||||||
|
|
@ -108,19 +108,19 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
cell.accessoryView = accessoryView
|
cell.accessoryView = accessoryView
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
hideOTPSwitch.isOn = SharedDefaults[.isHideOTPOn]
|
hideOTPSwitch.isOn = SharedDefaults[.isHideOTPOn]
|
||||||
case "Remember PGP Key Passphrase":
|
case "RememberPgpKeyPassphrase".localize():
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
cell.accessoryView = rememberPGPPassphraseSwitch
|
cell.accessoryView = rememberPGPPassphraseSwitch
|
||||||
case "Remember Git Credential Passphrase":
|
case "RememberGitCredentialPassphrase".localize():
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
cell.accessoryView = rememberGitCredentialPassphraseSwitch
|
cell.accessoryView = rememberGitCredentialPassphraseSwitch
|
||||||
case "Show Folders":
|
case "ShowFolders".localize():
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
cell.accessoryView = showFolderSwitch
|
cell.accessoryView = showFolderSwitch
|
||||||
case "Password Generator Flavor":
|
case "PasswordGeneratorFlavor".localize():
|
||||||
cell.accessoryType = .disclosureIndicator
|
cell.accessoryType = .disclosureIndicator
|
||||||
cell.detailTextLabel?.text = PasswordGeneratorFlavour.from(SharedDefaults[.passwordGeneratorFlavor]).name
|
cell.detailTextLabel?.text = PasswordGeneratorFlavour.from(SharedDefaults[.passwordGeneratorFlavor]).name
|
||||||
default: break
|
default: break
|
||||||
|
|
@ -131,7 +131,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
super.tableView(tableView, didSelectRowAt: indexPath)
|
super.tableView(tableView, didSelectRowAt: indexPath)
|
||||||
let cell = tableView.cellForRow(at: indexPath)!
|
let cell = tableView.cellForRow(at: indexPath)!
|
||||||
if cell.textLabel!.text! == "Password Generator Flavor" {
|
if cell.textLabel!.text! == "PasswordGeneratorFlavor".localize() {
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
showPasswordGeneratorFlavorActionSheet(sourceCell: cell)
|
showPasswordGeneratorFlavorActionSheet(sourceCell: cell)
|
||||||
}
|
}
|
||||||
|
|
@ -141,12 +141,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
var randomFlavorActionTitle = ""
|
var randomFlavorActionTitle = ""
|
||||||
var appleFlavorActionTitle = ""
|
var appleFlavorActionTitle = ""
|
||||||
randomFlavorActionTitle = "✓ Random String"
|
|
||||||
appleFlavorActionTitle = "Apple's Keychain Style"
|
|
||||||
if SharedDefaults[.passwordGeneratorFlavor] == PasswordGeneratorFlavour.RANDOM.rawValue {
|
if SharedDefaults[.passwordGeneratorFlavor] == PasswordGeneratorFlavour.RANDOM.rawValue {
|
||||||
|
randomFlavorActionTitle = "✓ " + "RandomString".localize()
|
||||||
|
appleFlavorActionTitle = "ApplesKeychainStyle".localize()
|
||||||
} else {
|
} else {
|
||||||
randomFlavorActionTitle = "Random String"
|
randomFlavorActionTitle = "RandomString".localize()
|
||||||
appleFlavorActionTitle = "✓ Apple's Keychain Style"
|
appleFlavorActionTitle = "✓ " + "ApplesKeychainStyle".localize()
|
||||||
}
|
}
|
||||||
let randomFlavorAction = UIAlertAction(title: randomFlavorActionTitle, style: .default) { _ in
|
let randomFlavorAction = UIAlertAction(title: randomFlavorActionTitle, style: .default) { _ in
|
||||||
SharedDefaults[.passwordGeneratorFlavor] = PasswordGeneratorFlavour.RANDOM.rawValue
|
SharedDefaults[.passwordGeneratorFlavor] = PasswordGeneratorFlavour.RANDOM.rawValue
|
||||||
|
|
@ -158,7 +158,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
sourceCell.detailTextLabel?.text = PasswordGeneratorFlavour.APPLE.name
|
sourceCell.detailTextLabel?.text = PasswordGeneratorFlavour.APPLE.name
|
||||||
}
|
}
|
||||||
|
|
||||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
|
||||||
optionMenu.addAction(randomFlavorAction)
|
optionMenu.addAction(randomFlavorAction)
|
||||||
optionMenu.addAction(appleFlavorAction)
|
optionMenu.addAction(appleFlavorAction)
|
||||||
optionMenu.addAction(cancelAction)
|
optionMenu.addAction(cancelAction)
|
||||||
|
|
@ -168,15 +168,15 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) {
|
@objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) {
|
||||||
let alertMessage = "Only \"key: value\" format in additional fields is supported. Unsupported fields will be given \"unknown\" keys. Turn on this switch to hide unsupported fields."
|
let alertMessage = "HideUnknownFieldsExplanation.".localize()
|
||||||
let alertTitle = "Hide Unknown Fields"
|
let alertTitle = "HideUnknownFields".localize()
|
||||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapHideOTPSwitchDetailButton(_ sender: Any?) {
|
@objc func tapHideOTPSwitchDetailButton(_ sender: Any?) {
|
||||||
let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ",")
|
let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ", ")
|
||||||
let alertMessage = "Turn on this switch to hide the fields related to one time passwords (i.e., \(keywordsString))."
|
let alertMessage = "HideOtpFieldsExplanation.".localize(keywordsString)
|
||||||
let alertTitle = "Hide One Time Password Fields"
|
let alertTitle = "HideOtpFields".localize()
|
||||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class GitConfigSettingTableViewController: UITableViewController {
|
||||||
let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text!
|
let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text!
|
||||||
let email = emailTextField.text!.isEmpty ? Globals.gitSignatureDefaultEmail : nameTextField.text!
|
let email = emailTextField.text!.isEmpty ? Globals.gitSignatureDefaultEmail : nameTextField.text!
|
||||||
guard GTSignature(name: name, email: email, time: nil) != nil else {
|
guard GTSignature(name: name, email: email, time: nil) != nil else {
|
||||||
Utils.alert(title: "Error", message: "Invalid name or email.", controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: "InvalidNameOrEmail".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
numberOfSegments = 0
|
numberOfSegments = 0
|
||||||
previousSegment = ""
|
previousSegment = ""
|
||||||
key = ""
|
key = ""
|
||||||
message = "Looking for the starting frame."
|
message = "LookingForStartingFrame.".localize()
|
||||||
hasStarted = false
|
hasStarted = false
|
||||||
isDone = false
|
isDone = false
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
// check the number of segments
|
// check the number of segments
|
||||||
numberOfSegments = numberOfSegments + 1
|
numberOfSegments = numberOfSegments + 1
|
||||||
guard numberOfSegments <= ScannedSSHKey.maxNumberOfGif else {
|
guard numberOfSegments <= ScannedSSHKey.maxNumberOfGif else {
|
||||||
key = "Too many QR codes"
|
key = "TooManyQrCodes".localize()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
}
|
}
|
||||||
|
|
||||||
// update message
|
// update message
|
||||||
message = "\(numberOfSegments) scanned QR codes."
|
message = "ScannedQrCodes(%d)".localize(numberOfSegments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var scanned = ScannedSSHKey()
|
var scanned = ScannedSSHKey()
|
||||||
|
|
@ -74,7 +74,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
armorPrivateKeyTextView.text = SharedDefaults[.gitSSHPrivateKeyArmor]
|
armorPrivateKeyTextView.text = SharedDefaults[.gitSSHPrivateKeyArmor]
|
||||||
armorPrivateKeyTextView.delegate = self
|
armorPrivateKeyTextView.delegate = self
|
||||||
|
|
||||||
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
|
scanPrivateKeyCell?.textLabel?.text = "ScanPrivateKeyQrCodes".localize()
|
||||||
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
|
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
|
||||||
scanPrivateKeyCell?.selectionStyle = .default
|
scanPrivateKeyCell?.selectionStyle = .default
|
||||||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||||
|
|
@ -85,7 +85,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
do {
|
do {
|
||||||
try passwordStore.initGitSSHKey(with: armorPrivateKeyTextView.text)
|
try passwordStore.initGitSSHKey(with: armorPrivateKeyTextView.text)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Cannot Save", message: "Cannot Save SSH Key", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "CannotSaveSshKey".localize(), controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
SharedDefaults[.gitSSHKeySource] = "armor"
|
SharedDefaults[.gitSSHKeySource] = "armor"
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
|
|
@ -113,7 +113,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||||
scanned.addSegment(segment: line)
|
scanned.addSegment(segment: line)
|
||||||
if scanned.isDone {
|
if scanned.isDone {
|
||||||
return (accept: true, message: "Done")
|
return (accept: true, message: "Done".localize())
|
||||||
} else {
|
} else {
|
||||||
return (accept: false, message: scanned.message)
|
return (accept: false, message: scanned.message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Prepare Repository")
|
SVProgressHUD.show(withStatus: "PrepareRepository".localize())
|
||||||
var gitCredential: GitCredential
|
var gitCredential: GitCredential
|
||||||
if auth == "Password" {
|
if auth == "Password" {
|
||||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username))
|
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username))
|
||||||
|
|
@ -112,7 +112,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
},
|
},
|
||||||
checkoutProgressBlock: { (path, completedSteps, totalSteps) in
|
checkoutProgressBlock: { (path, completedSteps, totalSteps) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SVProgressHUD.showProgress(Float(completedSteps)/Float(totalSteps), status: "Checkout Master Branch")
|
SVProgressHUD.showProgress(Float(completedSteps)/Float(totalSteps), status: "CheckingOutBranch".localize(branchName))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|
@ -121,16 +121,16 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
SharedDefaults[.gitBranchName] = branchName
|
SharedDefaults[.gitBranchName] = branchName
|
||||||
SharedDefaults[.gitAuthenticationMethod] = auth
|
SharedDefaults[.gitAuthenticationMethod] = auth
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let savePassphraseAlert = UIAlertController(title: "Done", message: "Do you want to save the Git credential password/passphrase?", preferredStyle: UIAlertControllerStyle.alert)
|
let savePassphraseAlert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in
|
||||||
SharedDefaults[.isRememberGitCredentialPassphraseOn] = false
|
SharedDefaults[.isRememberGitCredentialPassphraseOn] = false
|
||||||
self.passwordStore.gitPassword = nil
|
self.passwordStore.gitPassword = nil
|
||||||
self.passwordStore.gitSSHPrivateKeyPassphrase = nil
|
self.passwordStore.gitSSHPrivateKeyPassphrase = nil
|
||||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in
|
||||||
SharedDefaults[.isRememberGitCredentialPassphraseOn] = true
|
SharedDefaults[.isRememberGitCredentialPassphraseOn] = true
|
||||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||||
})
|
})
|
||||||
|
|
@ -141,9 +141,9 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
let error = error as NSError
|
let error = error as NSError
|
||||||
var message = error.localizedDescription
|
var message = error.localizedDescription
|
||||||
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
||||||
message = "\(message)\nUnderlying error: \(underlyingError.localizedDescription)"
|
message = "\(message)\n\("UnderlyingError".localize()): \(underlyingError.localizedDescription)"
|
||||||
}
|
}
|
||||||
Utils.alert(title: "Error", message: message, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: message, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +156,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
} else if cell == authSSHKeyCell {
|
} else if cell == authSSHKeyCell {
|
||||||
|
|
||||||
if !passwordStore.gitSSHKeyExists() {
|
if !passwordStore.gitSSHKeyExists() {
|
||||||
Utils.alert(title: "Cannot Select SSH Key", message: "Please setup SSH key first.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self, completion: nil)
|
||||||
authenticationMethod = "Password"
|
authenticationMethod = "Password"
|
||||||
} else {
|
} else {
|
||||||
authenticationMethod = "SSH Key"
|
authenticationMethod = "SSH Key"
|
||||||
|
|
@ -170,7 +170,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
// some sanity checks
|
// some sanity checks
|
||||||
guard let gitURL = URL(string: gitURLTextField.text!) else {
|
guard let gitURL = URL(string: gitURLTextField.text!) else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please set the Git repository URL.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,28 +179,28 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
break
|
break
|
||||||
case let val where val == "ssh":
|
case let val where val == "ssh":
|
||||||
guard let sshUsername = gitURL.user, sshUsername.isEmpty == false else {
|
guard let sshUsername = gitURL.user, sshUsername.isEmpty == false else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Cannot find the username in the Git repository URL. Example URL: ssh://git@server/path/to/repo.git.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "CannotFindUsername.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let username = usernameTextField.text, username == sshUsername else {
|
guard let username = usernameTextField.text, username == sshUsername else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please check the entered username and the username in the Git repository URL. They should match.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "CheckEnteredUsername.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case let val where val == "http":
|
case let val where val == "http":
|
||||||
Utils.alert(title: "Cannot Save", message: "Please use https instead of http.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "UseHttps.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
Utils.alert(title: "Cannot Save", message: "Please specify the scheme of the Git repository URL (https or ssh).", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "SpecifySchema.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if passwordStore.repositoryExisted() {
|
if passwordStore.repositoryExisted() {
|
||||||
let alert = UIAlertController(title: "Overwrite?", message: "This operation will overwrite your current password store data (repository). Data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "Overwrite", style: UIAlertActionStyle.destructive, handler: { _ in
|
alert.addAction(UIAlertAction(title: "Overwrite".localize(), style: UIAlertActionStyle.destructive, handler: { _ in
|
||||||
// perform segue only after a successful clone
|
// perform segue only after a successful clone
|
||||||
self.cloneAndSegueIfSuccess()
|
self.cloneAndSegueIfSuccess()
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler: nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
} else {
|
} else {
|
||||||
// perform segue only after a successful clone
|
// perform segue only after a successful clone
|
||||||
|
|
@ -210,9 +210,9 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
func showSSHKeyActionSheet() {
|
func showSSHKeyActionSheet() {
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
var urlActionTitle = "Download from URL"
|
var urlActionTitle = "DownloadFromUrl".localize()
|
||||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
var armorActionTitle = "AsciiArmorEncryptedKey".localize()
|
||||||
var fileActionTitle = "iTunes File Sharing"
|
var fileActionTitle = "ITunesFileSharing".localize()
|
||||||
|
|
||||||
if SharedDefaults[.gitSSHKeySource] == "url" {
|
if SharedDefaults[.gitSSHKeySource] == "url" {
|
||||||
urlActionTitle = "✓ \(urlActionTitle)"
|
urlActionTitle = "✓ \(urlActionTitle)"
|
||||||
|
|
@ -227,41 +227,41 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
|
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
|
||||||
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
|
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
|
||||||
}
|
}
|
||||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
|
||||||
optionMenu.addAction(urlAction)
|
optionMenu.addAction(urlAction)
|
||||||
optionMenu.addAction(armorAction)
|
optionMenu.addAction(armorAction)
|
||||||
|
|
||||||
if passwordStore.gitSSHKeyExists(inFileSharing: true) {
|
if passwordStore.gitSSHKeyExists(inFileSharing: true) {
|
||||||
// might keys updated via iTunes, or downloaded/pasted inside the app
|
// might keys updated via iTunes, or downloaded/pasted inside the app
|
||||||
fileActionTitle.append(" (Import)")
|
fileActionTitle.append(" (\("Import".localize()))")
|
||||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.gitSSHKeyImportFromFileSharing()
|
try self.passwordStore.gitSSHKeyImportFromFileSharing()
|
||||||
SharedDefaults[.gitSSHKeySource] = "file"
|
SharedDefaults[.gitSSHKeySource] = "file"
|
||||||
SVProgressHUD.showSuccess(withStatus: "Imported")
|
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
optionMenu.addAction(fileAction)
|
optionMenu.addAction(fileAction)
|
||||||
} else {
|
} else {
|
||||||
fileActionTitle.append(" (Tips)")
|
fileActionTitle.append(" (\("Tips".localize()))")
|
||||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||||
let title = "Tips"
|
let title = "Tips".localize()
|
||||||
let message = "Copy your ASCII-armored private key to Pass with the name \"ssh_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish."
|
let message = "CopyPrivateKeyToPass.".localize()
|
||||||
Utils.alert(title: title, message: message, controller: self)
|
Utils.alert(title: title, message: message, controller: self)
|
||||||
}
|
}
|
||||||
optionMenu.addAction(fileAction)
|
optionMenu.addAction(fileAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
if SharedDefaults[.gitSSHKeySource] != nil {
|
if SharedDefaults[.gitSSHKeySource] != nil {
|
||||||
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
|
let deleteAction = UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in
|
||||||
self.passwordStore.removeGitSSHKeys()
|
self.passwordStore.removeGitSSHKeys()
|
||||||
SharedDefaults[.gitSSHKeySource] = nil
|
SharedDefaults[.gitSSHKeySource] = nil
|
||||||
if let sshLabel = self.sshLabel {
|
if let sshLabel = self.sshLabel {
|
||||||
sshLabel.isEnabled = false
|
sshLabel.isEnabled = false
|
||||||
self.checkAuthenticationMethod(method: "Password")
|
self.checkAuthenticationMethod(method: "Password".localize())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
optionMenu.addAction(deleteAction)
|
optionMenu.addAction(deleteAction)
|
||||||
|
|
@ -278,23 +278,23 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
var message = ""
|
var message = ""
|
||||||
switch credential {
|
switch credential {
|
||||||
case .http:
|
case .http:
|
||||||
message = "Please fill in the password of your Git account."
|
message = "FillInGitAccountPassword.".localize()
|
||||||
case .ssh:
|
case .ssh:
|
||||||
message = "Please fill in the passphrase of your SSH key."
|
message = "FillInSshKeyPassphrase.".localize()
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Password".localize(), message: message, preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
textField.text = lastPassword ?? ""
|
textField.text = lastPassword ?? ""
|
||||||
textField.isSecureTextEntry = true
|
textField.isSecureTextEntry = true
|
||||||
})
|
})
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
password = alert.textFields!.first!.text
|
password = alert.textFields!.first!.text
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel) { _ in
|
||||||
password = nil
|
password = nil
|
||||||
sem.signal()
|
sem.signal()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
numberOfSegments = 0
|
numberOfSegments = 0
|
||||||
previousSegment = ""
|
previousSegment = ""
|
||||||
key = ""
|
key = ""
|
||||||
message = "Looking for the starting frame."
|
message = "LookingForStartingFrame.".localize()
|
||||||
hasStarted = false
|
hasStarted = false
|
||||||
isDone = false
|
isDone = false
|
||||||
}
|
}
|
||||||
|
|
@ -55,12 +55,12 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
switch keyType {
|
switch keyType {
|
||||||
case .publicKey:
|
case .publicKey:
|
||||||
if findPrivate {
|
if findPrivate {
|
||||||
message = "Please scan public key."
|
message = "ScanPrivateKey.".localize()
|
||||||
}
|
}
|
||||||
hasStarted = findPublic
|
hasStarted = findPublic
|
||||||
case .privateKey:
|
case .privateKey:
|
||||||
if findPublic {
|
if findPublic {
|
||||||
message = "Please scan private key."
|
message = "ScanPrivateKey.".localize()
|
||||||
}
|
}
|
||||||
hasStarted = findPrivate
|
hasStarted = findPrivate
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
// check the number of segments
|
// check the number of segments
|
||||||
numberOfSegments = numberOfSegments + 1
|
numberOfSegments = numberOfSegments + 1
|
||||||
guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else {
|
guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else {
|
||||||
key = "Too many QR codes"
|
key = "TooManyQrCodes"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +83,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
}
|
}
|
||||||
|
|
||||||
// update message
|
// update message
|
||||||
message = "\(numberOfSegments) scanned QR codes."
|
message = "ScannedQrCodes(%d)".localize(numberOfSegments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var scanned = ScannedPGPKey()
|
var scanned = ScannedPGPKey()
|
||||||
|
|
@ -94,12 +94,12 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor]
|
armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor]
|
||||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||||
|
|
||||||
scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes"
|
scanPublicKeyCell?.textLabel?.text = "ScanPublicKeyQrCodes".localize()
|
||||||
scanPublicKeyCell?.textLabel?.textColor = Globals.blue
|
scanPublicKeyCell?.textLabel?.textColor = Globals.blue
|
||||||
scanPublicKeyCell?.selectionStyle = .default
|
scanPublicKeyCell?.selectionStyle = .default
|
||||||
scanPublicKeyCell?.accessoryType = .disclosureIndicator
|
scanPublicKeyCell?.accessoryType = .disclosureIndicator
|
||||||
|
|
||||||
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
|
scanPrivateKeyCell?.textLabel?.text = "ScanPrivateKeyQrCodes".localize()
|
||||||
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
|
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
|
||||||
scanPrivateKeyCell?.selectionStyle = .default
|
scanPrivateKeyCell?.selectionStyle = .default
|
||||||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||||
|
|
@ -107,25 +107,25 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
|
|
||||||
@IBAction func save(_ sender: Any) {
|
@IBAction func save(_ sender: Any) {
|
||||||
guard armorPublicKeyTextView.text.isEmpty == false else {
|
guard armorPublicKeyTextView.text.isEmpty == false else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please set public key first.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "SetPublicKey.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard armorPrivateKeyTextView.text.isEmpty == false else {
|
guard armorPrivateKeyTextView.text.isEmpty == false else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please set private key first.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKey.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in
|
||||||
self.pgpPassphrase = nil
|
self.pgpPassphrase = nil
|
||||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in
|
||||||
// ask for the passphrase
|
// ask for the passphrase
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
self.pgpPassphrase = alert.textFields?.first?.text
|
self.pgpPassphrase = alert.textFields?.first?.text
|
||||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
|
|
@ -163,7 +163,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||||
scanned.addSegment(segment: line)
|
scanned.addSegment(segment: line)
|
||||||
if scanned.isDone {
|
if scanned.isDone {
|
||||||
return (accept: true, message: "Done")
|
return (accept: true, message: "Done".localize())
|
||||||
} else {
|
} else {
|
||||||
return (accept: false, message: scanned.message)
|
return (accept: false, message: scanned.message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ class PGPKeySettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
private func validatePGPKeyURL(input: String?) -> Bool {
|
private func validatePGPKeyURL(input: String?) -> Bool {
|
||||||
guard let path = input, let url = URL(string: path) else {
|
guard let path = input, let url = URL(string: path) else {
|
||||||
Utils.alert(title: "Cannot Save PGP Key", message: "Please set PGP Key URL first.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlFirst.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
guard let scheme = url.scheme, scheme == "https", scheme == "https" else {
|
guard let scheme = url.scheme, scheme == "https", scheme == "https" else {
|
||||||
Utils.alert(title: "Cannot Save PGP Key", message: "HTTP connection is not supported.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSavePgpKey".localize(), message: "HttpNotSupported.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -41,18 +41,18 @@ class PGPKeySettingTableViewController: UITableViewController {
|
||||||
validatePGPKeyURL(input: pgpPrivateKeyURLTextField.text) == true else {
|
validatePGPKeyURL(input: pgpPrivateKeyURLTextField.text) == true else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in
|
||||||
self.pgpPassphrase = nil
|
self.pgpPassphrase = nil
|
||||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in
|
||||||
// ask for the passphrase
|
// ask for the passphrase
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
self.pgpPassphrase = alert.textFields?.first?.text
|
self.pgpPassphrase = alert.textFields?.first?.text
|
||||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
if self.shouldPopCurrentView {
|
if self.shouldPopCurrentView {
|
||||||
let alert = UIAlertController(title: "Notice", message: "All previous local changes have been discarded. Your current Password Store will be shown.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Notice".localize(), message: "PreviousChangesDiscarded.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
_ = self.navigationController?.popViewController(animated: true)
|
_ = self.navigationController?.popViewController(animated: true)
|
||||||
}))
|
}))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
|
|
@ -93,8 +93,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
let sem = DispatchSemaphore(value: 0)
|
let sem = DispatchSemaphore(value: 0)
|
||||||
var passphrase = ""
|
var passphrase = ""
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
passphrase = alert.textFields!.first!.text!
|
passphrase = alert.textFields!.first!.text!
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
|
|
@ -113,7 +113,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
|
|
||||||
@objc private func decryptThenShowPassword() {
|
@objc private func decryptThenShowPassword() {
|
||||||
guard let passwordEntity = passwordEntity else {
|
guard let passwordEntity = passwordEntity else {
|
||||||
Utils.alert(title: "Cannot Show Password", message: "The password does not exist.", controller: self, handler: {(UIAlertAction) -> Void in
|
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: {(UIAlertAction) -> Void in
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
@ -127,11 +127,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
// remove the wrong passphrase so that users could enter it next time
|
// remove the wrong passphrase so that users could enter it next time
|
||||||
self.passwordStore.pgpKeyPassphrase = nil
|
self.passwordStore.pgpKeyPassphrase = nil
|
||||||
// alert: cancel or try again
|
// alert: cancel or try again
|
||||||
let alert = UIAlertController(title: "Cannot Show Password", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default) { _ in
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.default) { _ in
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
})
|
})
|
||||||
alert.addAction(UIAlertAction(title: "Try again", style: UIAlertActionStyle.destructive) {_ in
|
alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: UIAlertActionStyle.destructive) {_ in
|
||||||
self.decryptThenShowPassword()
|
self.decryptThenShowPassword()
|
||||||
})
|
})
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
|
|
@ -194,15 +194,15 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
|
|
||||||
@IBAction private func saveEditPassword(segue: UIStoryboardSegue) {
|
@IBAction private func saveEditPassword(segue: UIStoryboardSegue) {
|
||||||
if self.password!.changed != 0 {
|
if self.password!.changed != 0 {
|
||||||
SVProgressHUD.show(withStatus: "Saving")
|
SVProgressHUD.show(withStatus: "Saving".localize())
|
||||||
do {
|
do {
|
||||||
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
|
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
self.setTableData()
|
self.setTableData()
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
SVProgressHUD.showSuccess(withStatus: "Success")
|
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +211,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
do {
|
do {
|
||||||
try passwordStore.delete(passwordEntity: passwordEntity!)
|
try passwordStore.delete(passwordEntity: passwordEntity!)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
let _ = navigationController?.popViewController(animated: true)
|
let _ = navigationController?.popViewController(animated: true)
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +242,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
// show one time password
|
// show one time password
|
||||||
if password.otpType != .none {
|
if password.otpType != .none {
|
||||||
if let (title, otp) = self.password?.getOtpStrings() {
|
if let (title, otp) = self.password?.getOtpStrings() {
|
||||||
section = TableSection(type: .addition, header: "One Time Password")
|
section = TableSection(type: .addition, header: "OneTimePassword".localize())
|
||||||
section.item.append(title => otp)
|
section.item.append(title => otp)
|
||||||
tableData.append(section)
|
tableData.append(section)
|
||||||
oneTimePasswordIndexPath = IndexPath(row: 0, section: tableData.count - 1)
|
oneTimePasswordIndexPath = IndexPath(row: 0, section: tableData.count - 1)
|
||||||
|
|
@ -259,7 +259,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
|
|
||||||
// misc section
|
// misc section
|
||||||
section = TableSection(type: .misc)
|
section = TableSection(type: .misc)
|
||||||
section.item.append(AdditionField(title: "Show Raw"))
|
section.item.append(AdditionField(title: "ShowRaw".localize()))
|
||||||
tableData.append(section)
|
tableData.append(section)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -315,10 +315,10 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell {
|
if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell {
|
||||||
tappedCell.becomeFirstResponder()
|
tappedCell.becomeFirstResponder()
|
||||||
let menuController = UIMenuController.shared
|
let menuController = UIMenuController.shared
|
||||||
let revealItem = UIMenuItem(title: "Reveal", action: #selector(LabelTableViewCell.revealPassword(_:)))
|
let revealItem = UIMenuItem(title: "Reveal".localize(), action: #selector(LabelTableViewCell.revealPassword(_:)))
|
||||||
let concealItem = UIMenuItem(title: "Conceal", action: #selector(LabelTableViewCell.concealPassword(_:)))
|
let concealItem = UIMenuItem(title: "Conceal".localize(), action: #selector(LabelTableViewCell.concealPassword(_:)))
|
||||||
let nextHOTPItem = UIMenuItem(title: "Next Password", action: #selector(LabelTableViewCell.getNextHOTP(_:)))
|
let nextHOTPItem = UIMenuItem(title: "NextPassword".localize(), action: #selector(LabelTableViewCell.getNextHOTP(_:)))
|
||||||
let openURLItem = UIMenuItem(title: "Copy Password & Open Link", action: #selector(LabelTableViewCell.openLink(_:)))
|
let openURLItem = UIMenuItem(title: "CopyAndOpen".localize(), action: #selector(LabelTableViewCell.openLink(_:)))
|
||||||
menuController.menuItems = [revealItem, concealItem, nextHOTPItem, openURLItem]
|
menuController.menuItems = [revealItem, concealItem, nextHOTPItem, openURLItem]
|
||||||
menuController.setTargetRect(tappedCell.contentLabel.frame, in: tappedCell.contentLabel.superview!)
|
menuController.setTargetRect(tappedCell.contentLabel.frame, in: tappedCell.contentLabel.superview!)
|
||||||
menuController.setMenuVisible(true, animated: true)
|
menuController.setMenuVisible(true, animated: true)
|
||||||
|
|
@ -340,7 +340,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
func getNextHOTP() {
|
func getNextHOTP() {
|
||||||
guard password != nil, passwordEntity != nil, password?.otpType == .hotp else {
|
guard password != nil, passwordEntity != nil, password?.otpType == .hotp else {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
Utils.alert(title: "Error", message: "Get next password of a non-HOTP entry.", controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: "GetNextPasswordOfNonHotp.".localize(), controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -355,9 +355,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
do {
|
do {
|
||||||
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
|
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
SVProgressHUD.showSuccess(withStatus: "Password Copied\nCounter Updated")
|
SVProgressHUD.showSuccess(withStatus: "PasswordCopied".localize() + "\n" + "CounterUpdated".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +365,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
func openLink(to address: String?) {
|
func openLink(to address: String?) {
|
||||||
guard address != nil, let url = URL(string: formActualWebAddress(from: address!)) else {
|
guard address != nil, let url = URL(string: formActualWebAddress(from: address!)) else {
|
||||||
return DispatchQueue.main.async {
|
return DispatchQueue.main.async {
|
||||||
Utils.alert(title: "Error", message: "Cannot find a valid URL", controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: "CannotFindValidUrl".localize(), controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SecurePasteboard.shared.copy(textToCopy: password?.password)
|
SecurePasteboard.shared.copy(textToCopy: password?.password)
|
||||||
|
|
@ -436,7 +436,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
|
|
||||||
detailTextLabel.textAlignment = .center
|
detailTextLabel.textAlignment = .center
|
||||||
detailTextLabel.textColor = .gray
|
detailTextLabel.textColor = .gray
|
||||||
detailTextLabel.text = "\(numberOfHiddenFields) hidden field\(numberOfHiddenFields > 1 ? "s" : "")"
|
detailTextLabel.text = "HiddenFields(%d)".localize(numberOfHiddenFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||||
|
|
@ -451,7 +451,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
|
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||||
footerLabel.textColor = UIColor.gray
|
footerLabel.textColor = UIColor.gray
|
||||||
let dateString = self.passwordStore.getLatestUpdateInfo(filename: password!.url.path)
|
let dateString = self.passwordStore.getLatestUpdateInfo(filename: password!.url.path)
|
||||||
footerLabel.text = "Last Updated: \(dateString)"
|
footerLabel.text = "LastUpdated".localize(dateString)
|
||||||
view.addSubview(footerLabel)
|
view.addSubview(footerLabel)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
@ -481,7 +481,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
let section = tableData[indexPath.section]
|
let section = tableData[indexPath.section]
|
||||||
if section.type == .misc {
|
if section.type == .misc {
|
||||||
if section.item[indexPath.row].title == "Show Raw" {
|
if section.item[indexPath.row].title == "ShowRaw".localize() {
|
||||||
performSegue(withIdentifier: "showRawPasswordSegue", sender: self)
|
performSegue(withIdentifier: "showRawPasswordSegue", sender: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
private var navigationItemTitle: String?
|
private var navigationItemTitle: String?
|
||||||
|
|
||||||
private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()}
|
private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()}
|
||||||
private var sectionFooterTitles = ["", "", "Use \"key: value\" format for additional fields.", ""]
|
private var sectionFooterTitles = ["", "", "UseKeyValueFormat.".localize(), ""]
|
||||||
private let nameSection = 0
|
private let nameSection = 0
|
||||||
private let passwordSection = 1
|
private let passwordSection = 1
|
||||||
private let additionsSection = 2
|
private let additionsSection = 2
|
||||||
|
|
@ -47,23 +47,24 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
super.loadView()
|
super.loadView()
|
||||||
|
|
||||||
deletePasswordCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
deletePasswordCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
||||||
deletePasswordCell!.textLabel?.text = "Delete Password"
|
deletePasswordCell!.textLabel?.text = "DeletePassword".localize()
|
||||||
deletePasswordCell!.textLabel?.textColor = Globals.red
|
deletePasswordCell!.textLabel?.textColor = Globals.red
|
||||||
deletePasswordCell?.selectionStyle = .default
|
deletePasswordCell?.selectionStyle = .default
|
||||||
|
|
||||||
scanQRCodeCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
scanQRCodeCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
||||||
scanQRCodeCell?.textLabel?.text = "Add One-Time Password"
|
scanQRCodeCell?.textLabel?.text = "AddOneTimePassword".localize()
|
||||||
scanQRCodeCell?.textLabel?.textColor = Globals.blue
|
scanQRCodeCell?.textLabel?.textColor = Globals.blue
|
||||||
scanQRCodeCell?.selectionStyle = .default
|
scanQRCodeCell?.selectionStyle = .default
|
||||||
scanQRCodeCell?.accessoryType = .disclosureIndicator
|
scanQRCodeCell?.accessoryType = .disclosureIndicator
|
||||||
|
|
||||||
memorablePasswordGeneratorCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
memorablePasswordGeneratorCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
||||||
memorablePasswordGeneratorCell?.textLabel?.text = "Get a Memorable One: xkpasswd"
|
memorablePasswordGeneratorCell?.textLabel?.text = "GetMemorableOne".localize()
|
||||||
memorablePasswordGeneratorCell?.textLabel?.textColor = Globals.blue
|
memorablePasswordGeneratorCell?.textLabel?.textColor = Globals.blue
|
||||||
memorablePasswordGeneratorCell?.selectionStyle = .default
|
memorablePasswordGeneratorCell?.selectionStyle = .default
|
||||||
memorablePasswordGeneratorCell?.accessoryType = .disclosureIndicator
|
memorablePasswordGeneratorCell?.accessoryType = .disclosureIndicator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
if navigationItemTitle != nil {
|
if navigationItemTitle != nil {
|
||||||
|
|
@ -113,7 +114,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
currentPasswordLength <= maximumLength {
|
currentPasswordLength <= maximumLength {
|
||||||
defaultLength = currentPasswordLength
|
defaultLength = currentPasswordLength
|
||||||
}
|
}
|
||||||
passwordLengthCell?.reset(title: "Length",
|
passwordLengthCell?.reset(title: "Length".localize(),
|
||||||
minimumValue: minimumLength,
|
minimumValue: minimumLength,
|
||||||
maximumValue: maximumLength,
|
maximumValue: maximumLength,
|
||||||
defaultValue: defaultLength)
|
defaultValue: defaultLength)
|
||||||
|
|
@ -161,11 +162,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
let selectedCell = tableView.cellForRow(at: indexPath)
|
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||||
if selectedCell == deletePasswordCell {
|
if selectedCell == deletePasswordCell {
|
||||||
let alert = UIAlertController(title: "Delete Password?", message: nil, preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "Delete", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
|
alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
|
||||||
self.performSegue(withIdentifier: "deletePasswordSegue", sender: self)
|
self.performSegue(withIdentifier: "deletePasswordSegue", sender: self)
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler:nil))
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler:nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
} else if selectedCell == scanQRCodeCell {
|
} else if selectedCell == scanQRCodeCell {
|
||||||
self.performSegue(withIdentifier: "showQRScannerSegue", sender: self)
|
self.performSegue(withIdentifier: "showQRScannerSegue", sender: self)
|
||||||
|
|
@ -185,11 +186,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
// check whether the current password looks like an OTP field
|
// check whether the current password looks like an OTP field
|
||||||
func generateAndCopyPassword() {
|
func generateAndCopyPassword() {
|
||||||
if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) {
|
if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) {
|
||||||
let alert = UIAlertController(title: "Overwrite?", message: "Overwrite the one-time password configuration?", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive, handler: {_ in
|
||||||
self.generateAndCopyPasswordNoOtpCheck()
|
self.generateAndCopyPasswordNoOtpCheck()
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler: nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
} else {
|
} else {
|
||||||
self.generateAndCopyPasswordNoOtpCheck()
|
self.generateAndCopyPasswordNoOtpCheck()
|
||||||
|
|
@ -243,9 +244,9 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
// MARK: - QRScannerControllerDelegate Methods
|
// MARK: - QRScannerControllerDelegate Methods
|
||||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||||
if let url = URL(string: line), let _ = Token(url: url) {
|
if let url = URL(string: line), let _ = Token(url: url) {
|
||||||
return (accept: true, message: "Valid token URL")
|
return (accept: true, message: "ValidTokenUrl".localize())
|
||||||
} else {
|
} else {
|
||||||
return (accept: false, message: "Invalid token URL")
|
return (accept: false, message: "InvalidTokenUrl".localize())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,20 +303,20 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
func checkName() -> Bool {
|
func checkName() -> Bool {
|
||||||
// the name field should not be empty
|
// the name field should not be empty
|
||||||
guard let name = nameCell?.getContent(), name.isEmpty == false else {
|
guard let name = nameCell?.getContent(), name.isEmpty == false else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please fill in the name.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "FillInName.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// the name should not start with /
|
// the name should not start with /
|
||||||
guard name.hasPrefix("/") == false else {
|
guard name.hasPrefix("/") == false else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please remove the prefix \"/\" from your password name.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "RemovePrefix.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// the name field should be a valid url
|
// the name field should be a valid url
|
||||||
guard let path = name.stringByAddingPercentEncodingForRFC3986(),
|
guard let path = name.stringByAddingPercentEncodingForRFC3986(),
|
||||||
var passwordURL = URL(string: path) else {
|
var passwordURL = URL(string: path) else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Password name is invalid.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -324,7 +325,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
while passwordURL.path != "." {
|
while passwordURL.path != "." {
|
||||||
passwordURL = passwordURL.deletingLastPathComponent()
|
passwordURL = passwordURL.deletingLastPathComponent()
|
||||||
if passwordURL.path != "." && passwordURL.path.count >= previousPathLength {
|
if passwordURL.path != "." && passwordURL.path.count >= previousPathLength {
|
||||||
Utils.alert(title: "Cannot Save", message: "Cannot parse the filename. Please check and simplify the password name.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "CannotParseFilename.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
previousPathLength = passwordURL.path.count
|
previousPathLength = passwordURL.path.count
|
||||||
|
|
@ -337,8 +338,8 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty })
|
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty })
|
||||||
if copiedLinesSplit?.count ?? 0 > 0 {
|
if copiedLinesSplit?.count ?? 0 > 0 {
|
||||||
let generatedPassword = copiedLinesSplit![0]
|
let generatedPassword = copiedLinesSplit![0]
|
||||||
let alert = UIAlertController(title: "Wanna use it?", message: "", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "WannaUseIt?".localize(), message: "", preferredStyle: UIAlertControllerStyle.alert)
|
||||||
let message = NSMutableAttributedString(string: "It seems like you have copied something. The first string is:\n")
|
let message = NSMutableAttributedString(string: "\("SeemsLikeYouHaveCopiedSomething.".localize()) \("FirstStringIs:".localize())\n")
|
||||||
message.append(Utils.attributedPassword(plainPassword: generatedPassword))
|
message.append(Utils.attributedPassword(plainPassword: generatedPassword))
|
||||||
alert.setValue(message, forKey: "attributedMessage")
|
alert.setValue(message, forKey: "attributedMessage")
|
||||||
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.default, handler: {[unowned self] (action) -> Void in
|
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.default, handler: {[unowned self] (action) -> Void in
|
||||||
|
|
@ -349,7 +350,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
// make sure the clipboard gets cleared in 45s
|
// make sure the clipboard gets cleared in 45s
|
||||||
SecurePasteboard.shared.copy(textToCopy: generatedPassword)
|
SecurePasteboard.shared.copy(textToCopy: generatedPassword)
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler:nil))
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler:nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
return nil
|
return nil
|
||||||
}()
|
}()
|
||||||
private lazy var backUIBarButtonItem: UIBarButtonItem = {
|
private lazy var backUIBarButtonItem: UIBarButtonItem = {
|
||||||
let backUIBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(self.backAction(_:)))
|
let backUIBarButtonItem = UIBarButtonItem(title: "Back".localize(), style: .plain, target: self, action: #selector(self.backAction(_:)))
|
||||||
return backUIBarButtonItem
|
return backUIBarButtonItem
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -110,18 +110,18 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
if let controller = segue.source as? AddPasswordTableViewController {
|
if let controller = segue.source as? AddPasswordTableViewController {
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Saving")
|
SVProgressHUD.show(withStatus: "Saving".localize())
|
||||||
DispatchQueue.global(qos: .userInitiated).async {
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
do {
|
do {
|
||||||
let _ = try self.passwordStore.add(password: controller.password!)
|
let _ = try self.passwordStore.add(password: controller.password!)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// will trigger reloadTableView() by a notification
|
// will trigger reloadTableView() by a notification
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,13 +131,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
private func syncPasswords() {
|
private func syncPasswords() {
|
||||||
guard passwordStore.repositoryExisted() else {
|
guard passwordStore.repositoryExisted() else {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) {
|
||||||
Utils.alert(title: "Error", message: "There is no password store right now.", controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: "NoPasswordStore.".localize(), controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Sync Password Store")
|
SVProgressHUD.show(withStatus: "SyncingPasswordStore".localize())
|
||||||
var gitCredential: GitCredential
|
var gitCredential: GitCredential
|
||||||
if SharedDefaults[.gitAuthenticationMethod] == "Password" {
|
if SharedDefaults[.gitAuthenticationMethod] == "Password" {
|
||||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: SharedDefaults[.gitUsername]!))
|
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: SharedDefaults[.gitUsername]!))
|
||||||
|
|
@ -159,13 +159,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
if self.passwordStore.numberOfLocalCommits ?? 0 > 0 {
|
if self.passwordStore.numberOfLocalCommits ?? 0 > 0 {
|
||||||
try self.passwordStore.pushRepository(credential: gitCredential, requestGitPassword: self.requestGitPassword(credential:lastPassword:), transferProgressBlock: {(current, total, bytes, stop) in
|
try self.passwordStore.pushRepository(credential: gitCredential, requestGitPassword: self.requestGitPassword(credential:lastPassword:), 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: "PushingToRemoteRepository".localize())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.reloadTableView(parent: nil)
|
self.reloadTableView(parent: nil)
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
self.syncControl.endRefreshing()
|
self.syncControl.endRefreshing()
|
||||||
}
|
}
|
||||||
|
|
@ -176,14 +176,14 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
let error = error as NSError
|
let error = error as NSError
|
||||||
var message = error.localizedDescription
|
var message = error.localizedDescription
|
||||||
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
||||||
message = "\(message)\nUnderlying error: \(underlyingError.localizedDescription)"
|
message = "\(message)\n\("UnderlyingError".localize(underlyingError.localizedDescription))"
|
||||||
if underlyingError.localizedDescription.contains("Wrong passphrase") {
|
if underlyingError.localizedDescription.contains("WrongPassphrase".localize()) {
|
||||||
message = "\(message)\nRecovery suggestion: Wrong credential password/passphrase has been removed, please try again."
|
message = "\(message)\n\("RecoverySuggestion".localize())"
|
||||||
gitCredential.delete()
|
gitCredential.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) {
|
||||||
Utils.alert(title: "Error", message: message, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: message, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
if SharedDefaults[.isShowFolderOn] {
|
if SharedDefaults[.isShowFolderOn] {
|
||||||
searchController.searchBar.scopeButtonTitles = ["Current", "All"]
|
searchController.searchBar.scopeButtonTitles = ["Current".localize(), "All".localize()]
|
||||||
} else {
|
} else {
|
||||||
searchController.searchBar.scopeButtonTitles = nil
|
searchController.searchBar.scopeButtonTitles = nil
|
||||||
}
|
}
|
||||||
|
|
@ -365,8 +365,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
let sem = DispatchSemaphore(value: 0)
|
let sem = DispatchSemaphore(value: 0)
|
||||||
var passphrase = ""
|
var passphrase = ""
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
passphrase = alert.textFields!.first!.text!
|
passphrase = alert.textFields!.first!.text!
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
|
|
@ -381,7 +381,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// bring back
|
// bring back
|
||||||
SVProgressHUD.show(withStatus: "Decrypting")
|
SVProgressHUD.show(withStatus: "Decrypting".localize())
|
||||||
}
|
}
|
||||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||||
|
|
@ -391,28 +391,28 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
|
|
||||||
private func decryptThenCopyPassword(from indexPath: IndexPath) {
|
private func decryptThenCopyPassword(from indexPath: IndexPath) {
|
||||||
guard self.passwordStore.privateKey != 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: "CannotCopyPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let passwordEntity = getPasswordEntry(by: indexPath).passwordEntity!
|
let passwordEntity = getPasswordEntry(by: indexPath).passwordEntity!
|
||||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.dark)
|
SVProgressHUD.setDefaultStyle(.dark)
|
||||||
SVProgressHUD.show(withStatus: "Decrypting")
|
SVProgressHUD.show(withStatus: "Decrypting".localize())
|
||||||
DispatchQueue.global(qos: .userInteractive).async {
|
DispatchQueue.global(qos: .userInteractive).async {
|
||||||
var decryptedPassword: Password?
|
var decryptedPassword: Password?
|
||||||
do {
|
do {
|
||||||
decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
|
decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SecurePasteboard.shared.copy(textToCopy: decryptedPassword?.password)
|
SecurePasteboard.shared.copy(textToCopy: decryptedPassword?.password)
|
||||||
SVProgressHUD.showSuccess(withStatus: "Password copied. We will clear the pasteboard in 45 seconds.")
|
SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 0.6)
|
SVProgressHUD.dismiss(withDelay: 0.6)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// remove the wrong passphrase so that users could enter it next time
|
// remove the wrong passphrase so that users could enter it next time
|
||||||
self.passwordStore.pgpKeyPassphrase = nil
|
self.passwordStore.pgpKeyPassphrase = nil
|
||||||
Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -453,7 +453,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" {
|
||||||
guard self.passwordStore.privateKey != nil else {
|
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: "CannotShowPassword".localize(), message: "SetPgpKey.".localize(), 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)!
|
||||||
tableView.deselectRow(at: selectedIndexPath, animated: true)
|
tableView.deselectRow(at: selectedIndexPath, animated: true)
|
||||||
|
|
@ -462,7 +462,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
}
|
}
|
||||||
} else if identifier == "addPasswordSegue" {
|
} else if identifier == "addPasswordSegue" {
|
||||||
guard self.passwordStore.publicKey != nil, self.passwordStore.storeRepository != nil else {
|
guard self.passwordStore.publicKey != nil, self.passwordStore.storeRepository != nil else {
|
||||||
Utils.alert(title: "Cannot Add Password", message: "Please make sure PGP Key and Git Server are properly set.", controller: self, completion: nil)
|
Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -537,13 +537,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
|
self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
|
||||||
|
|
||||||
// set the sync control title
|
// set the sync control title
|
||||||
let atribbutedTitle = "Last Synced: \(lastSyncedTimeString())"
|
let atribbutedTitle = "LastSynced".localize() + ": \(lastSyncedTimeString())"
|
||||||
syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle)
|
syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func lastSyncedTimeString() -> String {
|
private func lastSyncedTimeString() -> String {
|
||||||
guard let date = self.passwordStore.lastSyncedTime else {
|
guard let date = self.passwordStore.lastSyncedTime else {
|
||||||
return "Oops! Sync again?"
|
return "SyncAgain?".localize()
|
||||||
}
|
}
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .medium
|
formatter.dateStyle = .medium
|
||||||
|
|
@ -615,23 +615,23 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
var message = ""
|
var message = ""
|
||||||
switch credential {
|
switch credential {
|
||||||
case .http:
|
case .http:
|
||||||
message = "Please fill in the password of your Git account."
|
message = "FillInGitAccountPassword.".localize()
|
||||||
case .ssh:
|
case .ssh:
|
||||||
message = "Please fill in the password of your SSH key."
|
message = "FillInSshKeyPassphrase.".localize()
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Password".localize(), message: message, preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
textField.text = lastPassword ?? ""
|
textField.text = lastPassword ?? ""
|
||||||
textField.isSecureTextEntry = true
|
textField.isSecureTextEntry = true
|
||||||
})
|
})
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
password = alert.textFields!.first!.text
|
password = alert.textFields!.first!.text
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
|
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel) { _ in
|
||||||
password = nil
|
password = nil
|
||||||
sem.signal()
|
sem.signal()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
|
||||||
|
|
||||||
// Move the message label to the front
|
// Move the message label to the front
|
||||||
scannerOutput.layer.cornerRadius = 10
|
scannerOutput.layer.cornerRadius = 10
|
||||||
scannerOutput.text = "No QR code detected"
|
scannerOutput.text = "NoQrCodeDetected.".localize()
|
||||||
view.bringSubview(toFront: scannerOutput)
|
view.bringSubview(toFront: scannerOutput)
|
||||||
|
|
||||||
// Initialize QR Code Frame to highlight the QR code
|
// Initialize QR Code Frame to highlight the QR code
|
||||||
|
|
@ -109,7 +109,7 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
|
||||||
captureSession?.stopRunning()
|
captureSession?.stopRunning()
|
||||||
delegate?.handleScannedOutput(line: scanned)
|
delegate?.handleScannedOutput(line: scanned)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
self.navigationController?.popViewController(animated: true)
|
self.navigationController?.popViewController(animated: true)
|
||||||
}
|
}
|
||||||
|
|
@ -119,21 +119,21 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
|
||||||
scannerOutput.text = scanned
|
scannerOutput.text = scanned
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scannerOutput.text = "No string value"
|
scannerOutput.text = "NoStringValue".localize()
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qrCodeFrameView?.frame = CGRect.zero
|
qrCodeFrameView?.frame = CGRect.zero
|
||||||
scannerOutput.text = "No QR code detected"
|
scannerOutput.text = "NoQrCodeDetected.".localize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func presentCameraSettings() {
|
func presentCameraSettings() {
|
||||||
let alertController = UIAlertController(title: "Error",
|
let alertController = UIAlertController(title: "Error".localize(),
|
||||||
message: "Camera access denied.\nWARNING: Toggle the camera permission resets the app! Save your changes.",
|
message: "CameraAccessDenied.".localize() + "\n" + "WarningToggleCameraPermissionsResetsApp.".localize(),
|
||||||
preferredStyle: .alert)
|
preferredStyle: .alert)
|
||||||
alertController.addAction(UIAlertAction(title: "Cancel", style: .default))
|
alertController.addAction(UIAlertAction(title: "Cancel".localize(), style: .default))
|
||||||
alertController.addAction(UIAlertAction(title: "Settings", style: .cancel) { _ in
|
alertController.addAction(UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in
|
||||||
if let url = URL(string: UIApplicationOpenSettingsURLString) {
|
if let url = URL(string: UIApplicationOpenSettingsURLString) {
|
||||||
UIApplication.shared.open(url, options: [:], completionHandler: { _ in
|
UIApplication.shared.open(url, options: [:], completionHandler: { _ in
|
||||||
// Handle
|
// Handle
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class SSHKeySettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
||||||
guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else {
|
guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else {
|
||||||
Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil)
|
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ class SSHKeySettingTableViewController: UITableViewController {
|
||||||
do {
|
do {
|
||||||
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
SharedDefaults[.gitSSHKeySource] = "url"
|
SharedDefaults[.gitSSHKeySource] = "url"
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
|
|
|
||||||
|
|
@ -35,21 +35,21 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .public)
|
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .public)
|
||||||
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .secret)
|
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .secret)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||||
SVProgressHUD.showSuccess(withStatus: "Success")
|
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
Utils.alert(title: "Remember to Remove the Key", message: "Remember to remove the key from the server.", controller: self, completion: nil)
|
Utils.alert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromServer.".localize(), controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,20 +65,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPublicKeyArmor] ?? "", keyType: .public)
|
try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPublicKeyArmor] ?? "", keyType: .public)
|
||||||
try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPrivateKeyArmor] ?? "", keyType: .secret)
|
try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPrivateKeyArmor] ?? "", keyType: .secret)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||||
SVProgressHUD.showSuccess(withStatus: "Success")
|
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||||
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 = "NotSet".localize()
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -90,20 +90,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
SharedDefaults[.pgpKeySource] = "file"
|
SharedDefaults[.pgpKeySource] = "file"
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.pgpKeyImportFromFileSharing()
|
try self.passwordStore.pgpKeyImportFromFileSharing()
|
||||||
try self.passwordStore.initPGPKeys()
|
try self.passwordStore.initPGPKeys()
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||||
SVProgressHUD.showSuccess(withStatus: "Imported")
|
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
|
||||||
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 = "NotSet".localize()
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,9 +133,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
|
|
||||||
private func setPasscodeLockCell() {
|
private func setPasscodeLockCell() {
|
||||||
if passcodeLock.hasPasscode {
|
if passcodeLock.hasPasscode {
|
||||||
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
self.passcodeTableViewCell.detailTextLabel?.text = "On".localize()
|
||||||
} else {
|
} else {
|
||||||
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
|
self.passcodeTableViewCell.detailTextLabel?.text = "Off".localize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,13 +143,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
if let pgpKeyID = self.passwordStore.pgpKeyID {
|
if let pgpKeyID = self.passwordStore.pgpKeyID {
|
||||||
pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID
|
pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID
|
||||||
} else {
|
} else {
|
||||||
pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setPasswordRepositoryTableViewCellDetailText() {
|
private func setPasswordRepositoryTableViewCellDetailText() {
|
||||||
if SharedDefaults[.gitURL] == nil {
|
if SharedDefaults[.gitURL] == nil {
|
||||||
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
passwordRepositoryTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||||
} else {
|
} else {
|
||||||
passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]!.host
|
passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]!.host
|
||||||
}
|
}
|
||||||
|
|
@ -176,9 +176,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
|
|
||||||
func showPGPKeyActionSheet() {
|
func showPGPKeyActionSheet() {
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
var urlActionTitle = "Download from URL"
|
var urlActionTitle = "DownloadFromUrl".localize()
|
||||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
var armorActionTitle = "AsciiArmorEncryptedKey".localize()
|
||||||
var fileActionTitle = "iTunes File Sharing"
|
var fileActionTitle = "ITunesFileSharing".localize()
|
||||||
|
|
||||||
if SharedDefaults[.pgpKeySource] == "url" {
|
if SharedDefaults[.pgpKeySource] == "url" {
|
||||||
urlActionTitle = "✓ \(urlActionTitle)"
|
urlActionTitle = "✓ \(urlActionTitle)"
|
||||||
|
|
@ -193,26 +193,26 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
|
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
|
||||||
self.performSegue(withIdentifier: "setPGPKeyByASCIISegue", sender: self)
|
self.performSegue(withIdentifier: "setPGPKeyByASCIISegue", sender: self)
|
||||||
}
|
}
|
||||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
|
||||||
optionMenu.addAction(urlAction)
|
optionMenu.addAction(urlAction)
|
||||||
optionMenu.addAction(armorAction)
|
optionMenu.addAction(armorAction)
|
||||||
|
|
||||||
if passwordStore.pgpKeyExists(inFileSharing: true) {
|
if passwordStore.pgpKeyExists(inFileSharing: true) {
|
||||||
fileActionTitle.append(" (Import)")
|
fileActionTitle.append(" (\("Import".localize()))")
|
||||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||||
// passphrase related
|
// passphrase related
|
||||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in
|
||||||
self.passwordStore.pgpKeyPassphrase = nil
|
self.passwordStore.pgpKeyPassphrase = nil
|
||||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||||
self.saveImportedPGPKey()
|
self.saveImportedPGPKey()
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in
|
||||||
// ask for the passphrase
|
// ask for the passphrase
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text
|
self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text
|
||||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||||
self.saveImportedPGPKey()
|
self.saveImportedPGPKey()
|
||||||
|
|
@ -227,10 +227,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
}
|
}
|
||||||
optionMenu.addAction(fileAction)
|
optionMenu.addAction(fileAction)
|
||||||
} else {
|
} else {
|
||||||
fileActionTitle.append(" (Tips)")
|
fileActionTitle.append(" (\("Tips".localize()))")
|
||||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||||
let title = "Tips"
|
let title = "Tips".localize()
|
||||||
let message = "Copy your ASCII-armored public and private keys to Pass with names \"gpg_key.pub\" and \"gpg_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish."
|
let message = "CopyPrivateKeyToPass.".localize()
|
||||||
Utils.alert(title: title, message: message, controller: self)
|
Utils.alert(title: title, message: message, controller: self)
|
||||||
}
|
}
|
||||||
optionMenu.addAction(fileAction)
|
optionMenu.addAction(fileAction)
|
||||||
|
|
@ -238,9 +238,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
|
|
||||||
|
|
||||||
if SharedDefaults[.pgpKeySource] != nil {
|
if SharedDefaults[.pgpKeySource] != nil {
|
||||||
let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in
|
let deleteAction = UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in
|
||||||
self.passwordStore.removePGPKeys()
|
self.passwordStore.removePGPKeys()
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||||
}
|
}
|
||||||
optionMenu.addAction(deleteAction)
|
optionMenu.addAction(deleteAction)
|
||||||
}
|
}
|
||||||
|
|
@ -255,7 +255,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
let passcodeRemoveViewController = PasscodeLockViewController()
|
let passcodeRemoveViewController = PasscodeLockViewController()
|
||||||
|
|
||||||
|
|
||||||
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
|
let removePasscodeAction = UIAlertAction(title: "RemovePasscode".localize(), style: .destructive) { [weak self] _ in
|
||||||
passcodeRemoveViewController.successCallback = {
|
passcodeRemoveViewController.successCallback = {
|
||||||
self?.passcodeLock.delete()
|
self?.passcodeLock.delete()
|
||||||
self?.setPasscodeLockCell()
|
self?.setPasscodeLockCell()
|
||||||
|
|
@ -263,11 +263,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let changePasscodeAction = UIAlertAction(title: "Change Passcode", style: .default) { [weak self] _ in
|
let changePasscodeAction = UIAlertAction(title: "ChangePasscode".localize(), style: .default) { [weak self] _ in
|
||||||
self?.setPasscodeLock()
|
self?.setPasscodeLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
|
||||||
optionMenu.addAction(removePasscodeAction)
|
optionMenu.addAction(removePasscodeAction)
|
||||||
optionMenu.addAction(changePasscodeAction)
|
optionMenu.addAction(changePasscodeAction)
|
||||||
optionMenu.addAction(cancelAction)
|
optionMenu.addAction(cancelAction)
|
||||||
|
|
@ -292,20 +292,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
|
|
||||||
func setPasscodeLock() {
|
func setPasscodeLock() {
|
||||||
// prepare the alert for setting the passcode
|
// prepare the alert for setting the passcode
|
||||||
setPasscodeLockAlert = UIAlertController(title: "Set passcode", message: "Fill in your passcode for Pass (at least 4 characters)", preferredStyle: .alert)
|
setPasscodeLockAlert = UIAlertController(title: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert)
|
||||||
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
|
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
|
||||||
textField.placeholder = "Password"
|
textField.placeholder = "Password".localize()
|
||||||
textField.isSecureTextEntry = true
|
textField.isSecureTextEntry = true
|
||||||
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
|
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
|
||||||
})
|
})
|
||||||
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
|
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
|
||||||
textField.placeholder = "Password Confirmation"
|
textField.placeholder = "PasswordConfirmation".localize()
|
||||||
textField.isSecureTextEntry = true
|
textField.isSecureTextEntry = true
|
||||||
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
|
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
|
||||||
})
|
})
|
||||||
|
|
||||||
// save action
|
// save action
|
||||||
let saveAction = UIAlertAction(title: "Save", style: .default) { (action:UIAlertAction) -> Void in
|
let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (action:UIAlertAction) -> Void in
|
||||||
let passcode: String = self.setPasscodeLockAlert!.textFields![0].text!
|
let passcode: String = self.setPasscodeLockAlert!.textFields![0].text!
|
||||||
self.passcodeLock.save(passcode: passcode)
|
self.passcodeLock.save(passcode: passcode)
|
||||||
// refresh the passcode lock cell ("On")
|
// refresh the passcode lock cell ("On")
|
||||||
|
|
@ -314,7 +314,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
saveAction.isEnabled = false // disable the Save button by default
|
saveAction.isEnabled = false // disable the Save button by default
|
||||||
|
|
||||||
// cancel action
|
// cancel action
|
||||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
|
||||||
|
|
||||||
// present
|
// present
|
||||||
setPasscodeLockAlert?.addAction(saveAction)
|
setPasscodeLockAlert?.addAction(saveAction)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import UIKit
|
||||||
|
|
||||||
class SpecialThanksTableViewController: BasicStaticTableViewController {
|
class SpecialThanksTableViewController: BasicStaticTableViewController {
|
||||||
let openSourceComponents = [
|
let openSourceComponents = [
|
||||||
["Contributors",
|
["Contributors".localize(),
|
||||||
"https://github.com/mssun/passforios/graphs/contributors"],
|
"https://github.com/mssun/passforios/graphs/contributors"],
|
||||||
["Password Store",
|
["Password Store",
|
||||||
"https://passwordstore.org"],
|
"https://passwordstore.org"],
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ extension Utils {
|
||||||
static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
||||||
SVProgressHUD.dismiss()
|
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: handler))
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: handler))
|
||||||
controller.present(alert, animated: true, completion: completion)
|
controller.present(alert, animated: true, completion: completion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ class LabelTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentLabel.font = Globals.passwordFont
|
contentLabel.font = Globals.passwordFont
|
||||||
} else if title.caseInsensitiveCompare("hmac-based") == .orderedSame {
|
} else if title.caseInsensitiveCompare("HmacBased".localize()) == .orderedSame {
|
||||||
type = .HOTP
|
type = .HOTP
|
||||||
if isReveal {
|
if isReveal {
|
||||||
contentLabel.text = content
|
contentLabel.text = content
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,239 @@
|
||||||
Copyright © 2019 Bob Sun. All rights reserved.
|
Copyright © 2019 Bob Sun. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"Apple" = "Apple";
|
// General
|
||||||
"Random" = "Random";
|
"PassForIos" = "Pass for iOS";
|
||||||
|
"Passphrase" = "Passphrase";
|
||||||
|
"Passwords" = "Passwords";
|
||||||
|
"Apple" = "Apple";
|
||||||
|
"Settings" = "Settings";
|
||||||
|
"Contributors" = "Contributors";
|
||||||
|
|
||||||
|
// OTP related
|
||||||
|
"TimeBased" = "time-based";
|
||||||
|
"HmacBased" = "HMAC-based";
|
||||||
|
"None" = "None";
|
||||||
|
"ExpiresIn" = "(expires in %ds)";
|
||||||
|
|
||||||
|
// General (error) messages
|
||||||
|
"Error" = "Error";
|
||||||
|
"CannotSave" = "Cannot Save";
|
||||||
|
"UnresolvedError" = "Unresolved error %@";
|
||||||
|
"MigrationError" = "Migration error: %@";
|
||||||
|
"UnderlyingError" = "Underlying Error: %@";
|
||||||
|
"ErrorSaving" = "Error saving: %@";
|
||||||
|
"CannotCopyPassword" = "Cannot copy password";
|
||||||
|
"CannotAddPassword" = "Cannot add password";
|
||||||
|
"WrongPassphrase" = "Wrong passphrase";
|
||||||
|
"MakeSurePgpAndGitProperlySet." = "Please make sure PGP key and Git server are properly set.";
|
||||||
|
"RecoverySuggestion" = "Recovery suggestion: Wrong credential password/passphrase has been removed, please try again.";
|
||||||
|
"NSURLFileAllocatedSizeKeyShouldAlwaysReturnValue." = "Huh? NSURLFileAllocatedSizeKey should always return a value.";
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
"PasswordGeneratorFlavor" = "Password Generator Flavor";
|
||||||
|
"RememberPgpKeyPassphrase" = "Remember PGP Key Passphrase";
|
||||||
|
"RememberGitCredentialPassphrase" = "Remember Git Credential Passphrase";
|
||||||
|
"ShowFolders" = "Show Folders";
|
||||||
|
"HideUnknownFields" = "Hide Unknown Fields";
|
||||||
|
"HideUnknownFieldsExplanation." = "Only \"key: value\" format in additional fields is supported. Unsupported fields will be given \"unknown\" keys. Turn on this switch to hide unsupported fields.";
|
||||||
|
"HideOtpFields" = "Hide OTP Fields";
|
||||||
|
"HideOtpFieldsExplanation." = "Turn on this switch to hide the fields related to one time passwords (i.e., %@).";
|
||||||
|
"Random" = "Random";
|
||||||
|
"RandomString" = "Random String";
|
||||||
|
"ApplesKeychainStyle" = "Apple's Keychain Style";
|
||||||
|
|
||||||
|
// Git
|
||||||
|
"FailedToFetchPasswords" = "Failed to fetch passwords";
|
||||||
|
"FailedToFetchPasswordEntities" = "Failed to fetch password entities: %@";
|
||||||
|
"FailedToInsertPasswordEntity" = "Failed to insert password entity: %@";
|
||||||
|
"FailedToDeletePasswordEntity" = "Failed to delete password entity: %@";
|
||||||
|
"FailedToSavePasswordEntity" = "Failed to save password entity: %@";
|
||||||
|
"FailureToSaveContext" = "Failure to save context: %@";
|
||||||
|
"RepositoryRemoteMasterNotFoundError." = "Cannot find remote branch origin/master.";
|
||||||
|
"KeyImportError." = "Cannot import the key.";
|
||||||
|
"PasswordDuplicatedError." = "Cannot add the password; password is duplicated.";
|
||||||
|
"GitResetError." = "Cannot identify the latest synced commit.";
|
||||||
|
"PGPPublicKeyNotExistError." = "PGP public key doesn't exist.";
|
||||||
|
"WrongPasswordFilename." = "Cannot write to the password file.";
|
||||||
|
"DecryptionError." = "Cannot decrypt password.";
|
||||||
|
"UnknownError." = "Unknown error.";
|
||||||
|
"PrepareRepository" = "Prepare Repository";
|
||||||
|
"CheckingOutBranch" = "Checking out branch '%@'";
|
||||||
|
"WantToSaveGitCredential?" = "Do you want to save the Git credential password/passphrase?";
|
||||||
|
|
||||||
|
// Repository
|
||||||
|
"RepositoryNotSetError." = "Git repository is not set.";
|
||||||
|
"SetGitRepositoryUrl" = "Please set the Git repository URL.";
|
||||||
|
"CannotFindUsername." = "Cannot find the username in the Git repository URL. Example URL: ssh://git@server/path/to/repo.git.";
|
||||||
|
"CheckEnteredUsername." = "Please check the entered username and the username in the Git repository URL. They should match.";
|
||||||
|
"UseHttps." = "Please use HTTPS instead of HTTP.";
|
||||||
|
"SpecifySchema." = "Please specify the scheme of the Git repository URL (HTTPS or SSH).";
|
||||||
|
"Overwrite?" = "Overwrite?";
|
||||||
|
"Overwrite" = "Overwrite";
|
||||||
|
"OperationWillOverwriteData." = "This operation will overwrite your current password store data (repository). Data on your remote server will not be affected.";
|
||||||
|
"DownloadFromUrl" = "Download from URL";
|
||||||
|
"AsciiArmorEncryptedKey" = "ASCII-Armor Encrypted Key";
|
||||||
|
"ITunesFileSharing" = "iTunes File Sharing";
|
||||||
|
"Import" = "Import";
|
||||||
|
"Imported" = "Imported";
|
||||||
|
"Tips" = "Tips";
|
||||||
|
"CopyPrivateKeyToPass." = "Copy your ASCII-armored private key to Pass with the name \"ssh_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish.";
|
||||||
|
"FillInGitAccountPassword." = "Please fill in the password of your Git account.";
|
||||||
|
"NoPasswordStore." = "There is no password store right now.";
|
||||||
|
"SyncingPasswordStore" = "Syncing Password Store";
|
||||||
|
"PushingToRemoteRepository" = "Pushing to Remote Repository";
|
||||||
|
|
||||||
|
// SSH
|
||||||
|
"FillInSshKeyPassphrase." = "Please fill in the passphrase of your SSH key.";
|
||||||
|
"CannotSelectSshKey" = "Cannot Select SSH Key";
|
||||||
|
"PleaseSetupSshKeyFirst." = "Please setup SSH key first.";
|
||||||
|
"RemoveSShKeys" = "Remove Git SSH Keys";
|
||||||
|
"SetPrivateKeyUrl." = "Please set private key URL first.";
|
||||||
|
|
||||||
|
// QR code scanning
|
||||||
|
"LookingForStartingFrame." = "Looking for the starting frame.";
|
||||||
|
"TooManyQrCodes" = "Too many QR codes";
|
||||||
|
"ScanPrivateKeyQrCodes" = "Scan Private Key QR Codes";
|
||||||
|
"CannotSaveSshKey" = "Cannot Save SSH Key";
|
||||||
|
"ScanPublicKey." = "Please scan public key.";
|
||||||
|
"ScanPrivateKey." = "Please scan private key.";
|
||||||
|
"ScanPrivateKeyQrCodes" = "Scan Private Key QR codes";
|
||||||
|
"ScanPublicKeyQrCodes" = "Scan Public Key QR codes";
|
||||||
|
"SetPrivateKey." = "Please set private key first.";
|
||||||
|
"SetPublicKey." = "Please set public key first.";
|
||||||
|
"NoQrCodeDetected." = "No QR code detected.";
|
||||||
|
"NoStringValue" = "No string value";
|
||||||
|
"CameraAccessDenied." = "Camera access denied.";
|
||||||
|
"WarningToggleCameraPermissionsResetsApp." = "WARNING: Toggle the camera permission resets the app! Save your changes.";
|
||||||
|
|
||||||
|
// PGP
|
||||||
|
"Decrypting" = "Decrypting";
|
||||||
|
"PgpKeyNotSet." = "PGP Key is not set. Please set your PGP Key first.";
|
||||||
|
"FillInPgpPassphrase." = "Please fill in the passphrase of your PGP secret key.";
|
||||||
|
"SetPgpKey." = "PGP Key is not set. Please set your PGP Key first.";
|
||||||
|
"WantToSavePassphrase?" = "Do you want to save the passphrase for later decryption?";
|
||||||
|
"CannotSavePgpKey" = "Cannot Save PGP Key";
|
||||||
|
"SetPgpKeyUrlFirst." = "Please set PGP key URL first.";
|
||||||
|
"FetchingPgpKey" = "Fetching PGP Key";
|
||||||
|
"RememberToRemoveKey" = "Remember to Remove the Key";
|
||||||
|
"RememberToRemoveKeyFromServer." = "Remember to remove the key from the server.";
|
||||||
|
"RemovePgpKeys" = "Remove PGP Keys";
|
||||||
|
|
||||||
|
// App passcode
|
||||||
|
"RemovePasscode" = "Remove Passcode";
|
||||||
|
"ChangePasscode" = "Change Passcode";
|
||||||
|
"SetPasscode" = "Set Passcode";
|
||||||
|
"PasswordConfirmation" = "Password Confirmation";
|
||||||
|
"FillInAppPasscode." = "Fill in your passcode for Pass (at least 4 characters).";
|
||||||
|
|
||||||
|
// Git signature
|
||||||
|
"NotSet" = "Not Set";
|
||||||
|
"InvalidNameOrEmail" = "Invalid name or e-mail";
|
||||||
|
|
||||||
|
// Erase password store
|
||||||
|
"ErasePasswordStoreData?" = "Erase password store data?";
|
||||||
|
"ErasePasswordStoreData" = "Erase Password Store Data";
|
||||||
|
"EraseExplanation." = "This will delete all local data and settings. Password store data on your remote server will not be affected.";
|
||||||
|
"Erasing..." = "Erasing ...";
|
||||||
|
|
||||||
|
// Discard local changes
|
||||||
|
"DiscardAllLocalChanges?" = "Discard all local changes?";
|
||||||
|
"DiscardAllLocalChanges" = "Discard All Local Changes";
|
||||||
|
"DiscardExplanation." = "Do you want to permanently discard all changes to the local copy of your password data? You cannot undo this action.";
|
||||||
|
"Resetting..." = "Resetting ...";
|
||||||
|
|
||||||
|
// Time related
|
||||||
|
"Unknown" = "Unknown";
|
||||||
|
"JustNow" = "Just now";
|
||||||
|
"TimeAgo" = "%@ ago";
|
||||||
|
|
||||||
|
// Commit messages
|
||||||
|
"AddPassword." = "Add password for %@ to store using Pass for iOS.";
|
||||||
|
"RemovePassword." = "Remove %@ from store using Pass for iOS.";
|
||||||
|
"EditPassword." = "Edit password for %@ using Pass for iOS.";
|
||||||
|
"RenamePassword." = "Rename %@ to %@ using Pass for iOS.";
|
||||||
|
|
||||||
|
// Menu buttons
|
||||||
|
"Ok" = "OK";
|
||||||
|
"Cancel" = "Cancel";
|
||||||
|
"Dismiss" = "Dismiss";
|
||||||
|
"Done" = "Done";
|
||||||
|
"Yes" = "Yes";
|
||||||
|
"No" = "No";
|
||||||
|
"TryAgain" = "Try Again";
|
||||||
|
"Delete" = "Delete";
|
||||||
|
"Back" = "Back";
|
||||||
|
"Current" = "Current";
|
||||||
|
"All" = "All";
|
||||||
|
"On" = "On";
|
||||||
|
"Off" = "Off";
|
||||||
|
"Save" = "Save";
|
||||||
|
|
||||||
|
// Lock screen
|
||||||
|
"EnterPasscode" = "Enter passcode for Pass";
|
||||||
|
"Passcode" = "Passcode";
|
||||||
|
"TouchId" = "Touch ID";
|
||||||
|
"FaceId" = "Face ID";
|
||||||
|
"AuthenticationNeeded." = "Authentication is needed to access Pass.";
|
||||||
|
|
||||||
|
// About repository
|
||||||
|
"AboutRepository" = "About Repository";
|
||||||
|
"ValueNotAvailable" = "Value not available";
|
||||||
|
"Size" = "Size";
|
||||||
|
"LocalCommits" = "Local Commits";
|
||||||
|
"LastSynced" = "Last Synced";
|
||||||
|
"Commits" = "Commits";
|
||||||
|
"CommitLogs" = "Commit Logs";
|
||||||
|
"SyncAgain?" = "Oops! Sync again?";
|
||||||
|
|
||||||
|
// About app
|
||||||
|
"Website" = "Website";
|
||||||
|
"Help" = "Help";
|
||||||
|
"ContactDeveloper" = "Contact Developer";
|
||||||
|
"OpenSourceComponents" = "Open Source Components";
|
||||||
|
"SpecialThanks" = "Special Thanks";
|
||||||
|
"Acknowledgements" = "Acknowledgements";
|
||||||
|
"ValueNotAvailable" = "Value not available";
|
||||||
|
|
||||||
|
// External applications
|
||||||
|
"CannotOpenMail" = "Cannot open Mail app";
|
||||||
|
"CopiedEmail" = "Copied email %@";
|
||||||
|
"HttpNotSupported." = "HTTP connection is not supported.";
|
||||||
|
|
||||||
|
// Password view
|
||||||
|
"Notice" = "Notice";
|
||||||
|
"PreviousChangesDiscarded." = "All previous local changes have been discarded. Your current Password Store will be shown.";
|
||||||
|
"CannotShowPassword" = "Cannot show password";
|
||||||
|
"PasswordDoesNotExist" = "The password does not exist.";
|
||||||
|
"Saving" = "Saving";
|
||||||
|
"Success" = "Success";
|
||||||
|
"OneTimePassword" = "One-Time Password";
|
||||||
|
"ShowRaw" = "Show Raw";
|
||||||
|
"Reveal" = "Reveal";
|
||||||
|
"Conceal" = "Conceal";
|
||||||
|
"NextPassword" = "Next Password";
|
||||||
|
"CopyAndOpen" = "Copy Password & Open Link";
|
||||||
|
"GetNextPasswordOfNonHotp." = "Get next password of a non-HOTP entry.";
|
||||||
|
"PasswordCopied" = "Password Copied";
|
||||||
|
"CounterUpdated" = "Counter Updated";
|
||||||
|
"CannotFindValidUrl" = "Cannot find a valid URL";
|
||||||
|
"LastUpdated" = "Last Updated: %@";
|
||||||
|
"PasswordCopiedToPasteboard." = "Password copied. We will clear the pasteboard in 45 seconds.";
|
||||||
|
|
||||||
|
// Password editor
|
||||||
|
"UseKeyValueFormat." = "Use \"key: value\" format for additional fields.";
|
||||||
|
"DeletePassword" = "Delete Password";
|
||||||
|
"AddOneTimePassword" = "Add One-Time Password";
|
||||||
|
"GetMemorableOne" = "Get a Memorable One: xkpasswd";
|
||||||
|
"Length" = "Length";
|
||||||
|
"DeletePassword?" = "Delete Password?";
|
||||||
|
"OverwriteOtpConfiguration?" = "Overwrite the one-time password configuration?";
|
||||||
|
"ValidTokenUrl" = "Valid token URL";
|
||||||
|
"InvalidTokenUrl" = "Invalid token URL";
|
||||||
|
"FillInName." = "Please fill in the name.";
|
||||||
|
"RemovePrefix." = "Please remove the prefix \"/\" from your password name.";
|
||||||
|
"PasswordNameInvalid." = "Password name is invalid.";
|
||||||
|
"CannotParseFilename." = "Cannot parse the filename. Please check and simplify the password name.";
|
||||||
|
"WannaUseIt?" = "Wanna use it?";
|
||||||
|
"SeemsLikeYouHaveCopiedSomething." = "It seems like you have copied something.";
|
||||||
|
"FirstStringIs:" = "The first string is:";
|
||||||
|
|
|
||||||
76
pass/en.lproj/Localizable.stringsdict
Normal file
76
pass/en.lproj/Localizable.stringsdict
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>ScannedQrCodes(%d)</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@code@</string>
|
||||||
|
<key>codes</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>zero</key>
|
||||||
|
<string>No scanned QR code</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>One scanned QR code</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>%d scanned QR codes</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>DiscardedCommits(%d)</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@commits@</string>
|
||||||
|
<key>commits</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>NSStringFormatValueTypeKey</key>
|
||||||
|
<string>d</string>
|
||||||
|
<key>zero</key>
|
||||||
|
<string>No local commits</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>Discarded one commit</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>Discarded %d commits</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>HiddenFields(%d)</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@fields@</string>
|
||||||
|
<key>fields</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>NSStringFormatValueTypeKey</key>
|
||||||
|
<string>d</string>
|
||||||
|
<key>zero</key>
|
||||||
|
<string>No hidden field</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>One hidden field</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>%d hidden fields</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>WrongAttempts(%d)</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@attempts@</string>
|
||||||
|
<key>attempts</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>NSStringFormatValueTypeKey</key>
|
||||||
|
<string>d</string>
|
||||||
|
<key>zero</key>
|
||||||
|
<string>No wrong attempt</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>One wrong attempt</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>%d wrong attempts</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -146,7 +146,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
||||||
let entry = getPasswordEntry(by: indexPath)
|
let entry = getPasswordEntry(by: indexPath)
|
||||||
|
|
||||||
guard self.passwordStore.privateKey != 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: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +166,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// remove the wrong passphrase so that users could enter it next time
|
// remove the wrong passphrase so that users could enter it next time
|
||||||
self.passwordStore.pgpKeyPassphrase = nil
|
self.passwordStore.pgpKeyPassphrase = nil
|
||||||
Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -187,8 +187,8 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
||||||
let sem = DispatchSemaphore(value: 0)
|
let sem = DispatchSemaphore(value: 0)
|
||||||
var passphrase = ""
|
var passphrase = ""
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertController.Style.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertAction.Style.default, handler: {_ in
|
||||||
passphrase = alert.textFields!.first!.text!
|
passphrase = alert.textFields!.first!.text!
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
let entry = getPasswordEntry(by: indexPath)
|
let entry = getPasswordEntry(by: indexPath)
|
||||||
|
|
||||||
guard self.passwordStore.privateKey != 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: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +192,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// remove the wrong passphrase so that users could enter it next time
|
// remove the wrong passphrase so that users could enter it next time
|
||||||
self.passwordStore.pgpKeyPassphrase = nil
|
self.passwordStore.pgpKeyPassphrase = nil
|
||||||
Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,8 +214,8 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
let sem = DispatchSemaphore(value: 0)
|
let sem = DispatchSemaphore(value: 0)
|
||||||
var passphrase = ""
|
var passphrase = ""
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in
|
||||||
passphrase = alert.textFields!.first!.text!
|
passphrase = alert.textFields!.first!.text!
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
super.loadView()
|
super.loadView()
|
||||||
|
|
||||||
let passcodeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
let passcodeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
||||||
passcodeLabel.text = "Enter passcode for Pass"
|
passcodeLabel.text = "EnterPasscode".localize()
|
||||||
passcodeLabel.font = UIFont.boldSystemFont(ofSize: 18)
|
passcodeLabel.font = UIFont.boldSystemFont(ofSize: 18)
|
||||||
passcodeLabel.textColor = UIColor.black
|
passcodeLabel.textColor = UIColor.black
|
||||||
passcodeLabel.textAlignment = .center
|
passcodeLabel.textAlignment = .center
|
||||||
|
|
@ -48,7 +48,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
|
|
||||||
let passcodeTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
let passcodeTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
||||||
passcodeTextField.borderStyle = UITextBorderStyle.roundedRect
|
passcodeTextField.borderStyle = UITextBorderStyle.roundedRect
|
||||||
passcodeTextField.placeholder = "passcode"
|
passcodeTextField.placeholder = "Passcode".localize()
|
||||||
passcodeTextField.isSecureTextEntry = true
|
passcodeTextField.isSecureTextEntry = true
|
||||||
passcodeTextField.clearButtonMode = UITextFieldViewMode.whileEditing
|
passcodeTextField.clearButtonMode = UITextFieldViewMode.whileEditing
|
||||||
passcodeTextField.delegate = self
|
passcodeTextField.delegate = self
|
||||||
|
|
@ -71,10 +71,10 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
var authError: NSError?
|
var authError: NSError?
|
||||||
if #available(iOS 8.0, macOS 10.12.1, *) {
|
if #available(iOS 8.0, macOS 10.12.1, *) {
|
||||||
if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
|
if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
|
||||||
var biometryType = "Touch ID"
|
var biometryType = "TouchId".localize()
|
||||||
if #available(iOS 11.0, *) {
|
if #available(iOS 11.0, *) {
|
||||||
if myContext.biometryType == LABiometryType.faceID {
|
if myContext.biometryType == LABiometryType.faceID {
|
||||||
biometryType = "Face ID"
|
biometryType = "FaceId".localize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
biometryAuthButton.setTitle(biometryType, for: .normal)
|
biometryAuthButton.setTitle(biometryType, for: .normal)
|
||||||
|
|
@ -83,7 +83,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
let cancelButton = UIButton(type: .custom)
|
let cancelButton = UIButton(type: .custom)
|
||||||
cancelButton.setTitle("Cancel", for: .normal)
|
cancelButton.setTitle("Cancel".localize(), for: .normal)
|
||||||
cancelButton.setTitleColor(Globals.blue, for: .normal)
|
cancelButton.setTitleColor(Globals.blue, for: .normal)
|
||||||
cancelButton.addTarget(self, action: #selector(passcodeLockDidCancel), for: .touchUpInside)
|
cancelButton.addTarget(self, action: #selector(passcodeLockDidCancel), for: .touchUpInside)
|
||||||
cancelButton.isHidden = !self.isCancellable
|
cancelButton.isHidden = !self.isCancellable
|
||||||
|
|
@ -167,7 +167,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
|
|
||||||
@objc func bioButtonPressedAction(_ uiButton: UIButton) {
|
@objc func bioButtonPressedAction(_ uiButton: UIButton) {
|
||||||
let myContext = LAContext()
|
let myContext = LAContext()
|
||||||
let myLocalizedReasonString = "Authentication is needed to access Pass."
|
let myLocalizedReasonString = "AuthenticationNeeded.".localize()
|
||||||
var authError: NSError?
|
var authError: NSError?
|
||||||
|
|
||||||
if #available(iOS 8.0, *) {
|
if #available(iOS 8.0, *) {
|
||||||
|
|
@ -188,11 +188,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
if textField == passcodeTextField {
|
if textField == passcodeTextField {
|
||||||
if !PasscodeLock.shared.check(passcode: textField.text ?? "") {
|
if !PasscodeLock.shared.check(passcode: textField.text ?? "") {
|
||||||
passcodeFailedAttempts = passcodeFailedAttempts + 1
|
passcodeFailedAttempts = passcodeFailedAttempts + 1
|
||||||
if passcodeFailedAttempts == 1 {
|
passcodeWrongAttemptsLabel?.text = "WrongAttempts(%d)".localize(passcodeFailedAttempts)
|
||||||
passcodeWrongAttemptsLabel?.text = "1 wrong attempt"
|
|
||||||
} else {
|
|
||||||
passcodeWrongAttemptsLabel?.text = "\(passcodeFailedAttempts) wrong attempts"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textField.resignFirstResponder()
|
textField.resignFirstResponder()
|
||||||
|
|
|
||||||
|
|
@ -23,27 +23,6 @@ public enum AppError: Error {
|
||||||
|
|
||||||
extension AppError: LocalizedError {
|
extension AppError: LocalizedError {
|
||||||
public var errorDescription: String? {
|
public var errorDescription: String? {
|
||||||
switch self {
|
return String(describing: self).localize()
|
||||||
case .RepositoryNotSetError:
|
|
||||||
return "Git repository is not set."
|
|
||||||
case let .RepositoryRemoteBranchNotFoundError(remoteBranchName):
|
|
||||||
return "Cannot find remote branch 'origin/\(remoteBranchName)'."
|
|
||||||
case let .RepositoryBranchNotFound(branchName):
|
|
||||||
return "Branch with name '\(branchName)' not found in repository."
|
|
||||||
case .KeyImportError:
|
|
||||||
return "Cannot import the key."
|
|
||||||
case .PasswordDuplicatedError:
|
|
||||||
return "Cannot add the password: password duplicated."
|
|
||||||
case .GitResetError:
|
|
||||||
return "Cannot identify the latest synced commit."
|
|
||||||
case .PGPPublicKeyNotExistError:
|
|
||||||
return "PGP public key doesn't exist."
|
|
||||||
case .WrongPasswordFilename:
|
|
||||||
return "Cannot write to the password file."
|
|
||||||
case .DecryptionError:
|
|
||||||
return "Cannot decrypt password."
|
|
||||||
case .UnknownError:
|
|
||||||
return "Unknown error."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ public extension FileManager {
|
||||||
fileSize = try fileSize ?? resourceValueForKey(URLResourceKey.fileAllocatedSizeKey)
|
fileSize = try fileSize ?? resourceValueForKey(URLResourceKey.fileAllocatedSizeKey)
|
||||||
|
|
||||||
guard let size = fileSize else {
|
guard let size = fileSize else {
|
||||||
preconditionFailure("huh? NSURLFileAllocatedSizeKey should always return a value")
|
preconditionFailure("NSURLFileAllocatedSizeKeyShouldAlwaysReturnValue.".localize())
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're good, add up the value.
|
// We're good, add up the value.
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class Utils {
|
||||||
|
|
||||||
public static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
public static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
||||||
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: handler))
|
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: handler))
|
||||||
controller.present(alert, animated: true, completion: completion)
|
controller.present(alert, animated: true, completion: completion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,9 +175,9 @@ public class Password {
|
||||||
if case let .timer(period) = otpToken!.generator.factor {
|
if case let .timer(period) = otpToken!.generator.factor {
|
||||||
let timeSinceEpoch = Date().timeIntervalSince1970
|
let timeSinceEpoch = Date().timeIntervalSince1970
|
||||||
let validTime = Int(period - timeSinceEpoch.truncatingRemainder(dividingBy: period))
|
let validTime = Int(period - timeSinceEpoch.truncatingRemainder(dividingBy: period))
|
||||||
description += " (expires in \(validTime)s)"
|
description += " " + "ExpiresIn".localize(validTime)
|
||||||
}
|
}
|
||||||
return (description, otpToken!.currentPassword ?? "error")
|
return (description, otpToken!.currentPassword ?? "Error".localize())
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the password strings
|
// return the password strings
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ public class PasswordStore {
|
||||||
* The store could not be migrated to the current model version.
|
* The store could not be migrated to the current model version.
|
||||||
Check the error message to determine what the actual problem was.
|
Check the error message to determine what the actual problem was.
|
||||||
*/
|
*/
|
||||||
fatalError("Unresolved error \(error), \(error.userInfo)")
|
fatalError("UnresolvedError".localize("\(error.localizedDescription), \(error.userInfo)"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return container.viewContext
|
return container.viewContext
|
||||||
|
|
@ -162,7 +162,7 @@ public class PasswordStore {
|
||||||
}
|
}
|
||||||
try fm.moveItem(atPath: Globals.repositoryPathLegacy, toPath: Globals.repositoryPath)
|
try fm.moveItem(atPath: Globals.repositoryPathLegacy, toPath: Globals.repositoryPath)
|
||||||
} catch {
|
} catch {
|
||||||
print("Migration error: \(error)")
|
print("MigrationError".localize(error))
|
||||||
}
|
}
|
||||||
updatePasswordEntityCoreData()
|
updatePasswordEntityCoreData()
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +266,7 @@ public class PasswordStore {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to fetch password entities: \(error)")
|
fatalError("FailedToFetchPasswordEntities".localize(error))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -282,7 +282,7 @@ public class PasswordStore {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to fetch password entities: \(error)")
|
fatalError("FailedToFetchPasswordEntities".localize(error))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -293,7 +293,7 @@ public class PasswordStore {
|
||||||
passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@ and isDir = %@", path, isDir as NSNumber)
|
passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@ and isDir = %@", path, isDir as NSNumber)
|
||||||
return try context.fetch(passwordEntityFetchRequest).first as? PasswordEntity
|
return try context.fetch(passwordEntityFetchRequest).first as? PasswordEntity
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to fetch password entities: \(error)")
|
fatalError("FailedToFetchPasswordEntities".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,7 +417,7 @@ public class PasswordStore {
|
||||||
do {
|
do {
|
||||||
try context.save()
|
try context.save()
|
||||||
} catch {
|
} catch {
|
||||||
print("Error with save: \(error)")
|
print("ErrorSaving".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,7 +445,7 @@ public class PasswordStore {
|
||||||
let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity]
|
let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity]
|
||||||
return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending }
|
return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending }
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to fetch passwords: \(error)")
|
fatalError("FailedToFetchPasswords".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -458,7 +458,7 @@ public class PasswordStore {
|
||||||
let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity]
|
let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity]
|
||||||
return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending }
|
return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending }
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to fetch passwords: \(error)")
|
fatalError("FailedToFetchPasswords".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,7 +470,7 @@ public class PasswordStore {
|
||||||
let passwordEntities = try context.fetch(passwordEntityFetchRequest) as! [PasswordEntity]
|
let passwordEntities = try context.fetch(passwordEntityFetchRequest) as! [PasswordEntity]
|
||||||
return passwordEntities
|
return passwordEntities
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to fetch passwords: \(error)")
|
fatalError("FailedToFetchPasswords".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,32 +484,32 @@ public class PasswordStore {
|
||||||
try context.save()
|
try context.save()
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to save: \(error)")
|
fatalError("ErrorSaving".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getLatestUpdateInfo(filename: String) -> String {
|
public func getLatestUpdateInfo(filename: String) -> String {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
return "Unknown"
|
return "Unknown".localize()
|
||||||
}
|
}
|
||||||
guard let blameHunks = try? storeRepository.blame(withFile: filename, options: nil).hunks,
|
guard let blameHunks = try? storeRepository.blame(withFile: filename, options: nil).hunks,
|
||||||
let latestCommitTime = blameHunks.map({
|
let latestCommitTime = blameHunks.map({
|
||||||
$0.finalSignature?.time?.timeIntervalSince1970 ?? 0
|
$0.finalSignature?.time?.timeIntervalSince1970 ?? 0
|
||||||
}).max() else {
|
}).max() else {
|
||||||
return "Unknown"
|
return "Unknown".localize()
|
||||||
}
|
}
|
||||||
let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime)
|
let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime)
|
||||||
let currentDate = Date()
|
let currentDate = Date()
|
||||||
var autoFormattedDifference: String
|
var autoFormattedDifference: String
|
||||||
if currentDate.timeIntervalSince(lastCommitDate) <= 60 {
|
if currentDate.timeIntervalSince(lastCommitDate) <= 60 {
|
||||||
autoFormattedDifference = "Just now"
|
autoFormattedDifference = "JustNow".localize()
|
||||||
} else {
|
} else {
|
||||||
let diffDate = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: lastCommitDate, to: currentDate)
|
let diffDate = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: lastCommitDate, to: currentDate)
|
||||||
let dateComponentsFormatter = DateComponentsFormatter()
|
let dateComponentsFormatter = DateComponentsFormatter()
|
||||||
dateComponentsFormatter.unitsStyle = .full
|
dateComponentsFormatter.unitsStyle = .full
|
||||||
dateComponentsFormatter.maximumUnitCount = 2
|
dateComponentsFormatter.maximumUnitCount = 2
|
||||||
dateComponentsFormatter.includesApproximationPhrase = true
|
dateComponentsFormatter.includesApproximationPhrase = true
|
||||||
autoFormattedDifference = dateComponentsFormatter.string(from: diffDate)!.appending(" ago")
|
autoFormattedDifference = "TimeAgo".localize(dateComponentsFormatter.string(from: diffDate)!)
|
||||||
}
|
}
|
||||||
return autoFormattedDifference
|
return autoFormattedDifference
|
||||||
}
|
}
|
||||||
|
|
@ -646,7 +646,7 @@ public class PasswordStore {
|
||||||
try self.context.save()
|
try self.context.save()
|
||||||
ret = passwordEntity
|
ret = passwordEntity
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to insert a PasswordEntity: \(error)")
|
fatalError("FailedToInsertPasswordEntity".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
@ -658,7 +658,7 @@ public class PasswordStore {
|
||||||
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)
|
||||||
try gitAdd(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.")
|
let _ = try gitCommit(message: "AddPassword.".localize(password.url.deletingPathExtension().path))
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
return newPasswordEntity
|
return newPasswordEntity
|
||||||
}
|
}
|
||||||
|
|
@ -668,7 +668,7 @@ public class PasswordStore {
|
||||||
try gitRm(path: deletedFileURL.path)
|
try gitRm(path: deletedFileURL.path)
|
||||||
try deletePasswordEntities(passwordEntity: passwordEntity)
|
try deletePasswordEntities(passwordEntity: passwordEntity)
|
||||||
try deleteDirectoryTree(at: deletedFileURL)
|
try deleteDirectoryTree(at: deletedFileURL)
|
||||||
let _ = try gitCommit(message: "Remove \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) from store using Pass for iOS.")
|
let _ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!))
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -679,7 +679,7 @@ public class PasswordStore {
|
||||||
let saveURL = storeURL.appendingPathComponent(passwordEntity.getURL()!.path)
|
let saveURL = storeURL.appendingPathComponent(passwordEntity.getURL()!.path)
|
||||||
try self.encrypt(password: password).write(to: saveURL)
|
try self.encrypt(password: password).write(to: saveURL)
|
||||||
try gitAdd(path: passwordEntity.getURL()!.path)
|
try gitAdd(path: passwordEntity.getURL()!.path)
|
||||||
let _ = try gitCommit(message: "Edit password for \(passwordEntity.getURL()!.deletingPathExtension().path.removingPercentEncoding!) using Pass for iOS.")
|
let _ = try gitCommit(message: "EditPassword.".localize(passwordEntity.getURL()!.deletingPathExtension().path.removingPercentEncoding!))
|
||||||
newPasswordEntity = passwordEntity
|
newPasswordEntity = passwordEntity
|
||||||
newPasswordEntity?.synced = false
|
newPasswordEntity?.synced = false
|
||||||
}
|
}
|
||||||
|
|
@ -696,8 +696,7 @@ public class PasswordStore {
|
||||||
// delete
|
// delete
|
||||||
try deleteDirectoryTree(at: deletedFileURL)
|
try deleteDirectoryTree(at: deletedFileURL)
|
||||||
try deletePasswordEntities(passwordEntity: passwordEntity)
|
try deletePasswordEntities(passwordEntity: passwordEntity)
|
||||||
let _ = try gitCommit(message: "Rename \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) to \(password.url.deletingPathExtension().path.removingPercentEncoding!) using Pass for iOS.")
|
let _ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!))
|
||||||
|
|
||||||
}
|
}
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
return newPasswordEntity
|
return newPasswordEntity
|
||||||
|
|
@ -712,7 +711,7 @@ public class PasswordStore {
|
||||||
do {
|
do {
|
||||||
try self.context.save()
|
try self.context.save()
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to delete a PasswordEntity: \(error)")
|
fatalError("FailedToDeletePasswordEntity".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -721,7 +720,7 @@ public class PasswordStore {
|
||||||
do {
|
do {
|
||||||
try context.save()
|
try context.save()
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failed to save a PasswordEntity: \(error)")
|
fatalError("FailedToSavePasswordEntity".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -752,11 +751,11 @@ public class PasswordStore {
|
||||||
do {
|
do {
|
||||||
try self.context.save()
|
try self.context.save()
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failure to save context: \(error)")
|
fatalError("FailureToSaveContext".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
fatalError("Failure to save context: \(error)")
|
fatalError("FailureToSaveContext".localize(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@
|
||||||
import OneTimePassword
|
import OneTimePassword
|
||||||
|
|
||||||
public enum OtpType: String {
|
public enum OtpType: String {
|
||||||
case totp = "time-based"
|
case totp = "TimeBased"
|
||||||
case hotp = "HMAC-based"
|
case hotp = "HmacBased"
|
||||||
case none
|
case none = "None"
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
return rawValue
|
return rawValue.localize()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(token: Token?) {
|
init(token: Token?) {
|
||||||
|
|
|
||||||
|
|
@ -304,9 +304,11 @@ class PasswordTest: XCTestCase {
|
||||||
func testOtpStringsTotpToken() {
|
func testOtpStringsTotpToken() {
|
||||||
let password = getPasswordObjectWith(content: TOTP_URL)
|
let password = getPasswordObjectWith(content: TOTP_URL)
|
||||||
let otpStrings = password.getOtpStrings()
|
let otpStrings = password.getOtpStrings()
|
||||||
|
let otpDescription = otpStrings!.description
|
||||||
|
|
||||||
XCTAssertNotNil(otpStrings)
|
XCTAssertNotNil(otpStrings)
|
||||||
XCTAssert(otpStrings!.description.hasPrefix("time-based (expires in"))
|
XCTAssert(otpDescription.hasPrefix("TimeBased".localize() + " ("))
|
||||||
|
XCTAssert(otpDescription.hasSuffix(")"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOtpStringsHotpToken() {
|
func testOtpStringsHotpToken() {
|
||||||
|
|
@ -314,6 +316,6 @@ class PasswordTest: XCTestCase {
|
||||||
let otpStrings = password.getOtpStrings()
|
let otpStrings = password.getOtpStrings()
|
||||||
|
|
||||||
XCTAssertNotNil(otpStrings)
|
XCTAssertNotNil(otpStrings)
|
||||||
XCTAssertEqual(otpStrings!.description, "HMAC-based")
|
XCTAssertEqual(otpStrings!.description, "HmacBased".localize())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ class OtpTypeTest: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDescription() {
|
func testDescription() {
|
||||||
XCTAssertEqual(OtpType(name: "totp").description, "time-based")
|
XCTAssertEqual(OtpType(name: "totp").description, "TimeBased".localize())
|
||||||
XCTAssertEqual(OtpType(name: "hotp").description, "HMAC-based")
|
XCTAssertEqual(OtpType(name: "hotp").description, "HmacBased".localize())
|
||||||
XCTAssertEqual(OtpType(name: nil).description, "none")
|
XCTAssertEqual(OtpType(name: nil).description, "None".localize())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue