Enable SwiftLint rule 'multiline_arguments_brackets' and fix all violations

This commit is contained in:
Danny Moesch 2020-07-05 00:16:22 +02:00 committed by Mingshen Sun
parent b4c25726a5
commit c87f4e9792
18 changed files with 286 additions and 220 deletions

View file

@ -97,7 +97,7 @@ whitelist_rules:
# - missing_docs # - missing_docs
- modifier_order - modifier_order
- multiline_arguments - multiline_arguments
# - multiline_arguments_brackets - multiline_arguments_brackets
# - multiline_function_chains # - multiline_function_chains
# - multiline_literal_brackets # - multiline_literal_brackets
# - multiline_parameters # - multiline_parameters

View file

@ -123,7 +123,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil)
} }
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))] container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))]
container.loadPersistentStores(completionHandler: { _, error in container.loadPersistentStores { _, error in
if let error = error as NSError? { if let error = error as NSError? {
// 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.
@ -138,7 +138,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
*/ */
fatalError("UnresolvedError".localize("\(error), \(error.userInfo)")) fatalError("UnresolvedError".localize("\(error), \(error.userInfo)"))
} }
}) }
return container return container
}() }()

View file

@ -48,29 +48,32 @@ class AdvancedSettingsTableViewController: UITableViewController {
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: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in alert.addAction(
SVProgressHUD.show(withStatus: "Erasing...".localize()) UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive) { [unowned self] (_) -> Void in
self.passwordStore.erase() SVProgressHUD.show(withStatus: "Erasing...".localize())
self.navigationController!.popViewController(animated: true) self.passwordStore.erase()
SVProgressHUD.showSuccess(withStatus: "Done".localize()) self.navigationController!.popViewController(animated: true)
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.showSuccess(withStatus: "Done".localize())
})) SVProgressHUD.dismiss(withDelay: 1)
}
)
alert.addAction(UIAlertAction.dismiss()) alert.addAction(UIAlertAction.dismiss())
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
} else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell { } else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell {
let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in alert.addAction(
SVProgressHUD.show(withStatus: "Resetting...".localize()) UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive) { [unowned self] (_) -> Void in
do { SVProgressHUD.show(withStatus: "Resetting...".localize())
let numberDiscarded = try self.passwordStore.reset() do {
self.navigationController!.popViewController(animated: true) let numberDiscarded = try self.passwordStore.reset()
SVProgressHUD.showSuccess(withStatus: "DiscardedCommits(%d)".localize(numberDiscarded)) self.navigationController!.popViewController(animated: true)
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.showSuccess(withStatus: "DiscardedCommits(%d)".localize(numberDiscarded))
} catch { SVProgressHUD.dismiss(withDelay: 1)
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
}
} }
)
}))
alert.addAction(UIAlertAction.dismiss()) alert.addAction(UIAlertAction.dismiss())
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
} }

View file

@ -146,9 +146,11 @@ class GitRepositorySettingsTableViewController: UITableViewController {
if passwordStore.repositoryExists() { if passwordStore.repositoryExists() {
let overwriteAlert: UIAlertController = { let overwriteAlert: UIAlertController = {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: .alert) let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Overwrite".localize(), style: .destructive) { _ in alert.addAction(
self.cloneAndSegueIfSuccess() UIAlertAction(title: "Overwrite".localize(), style: .destructive) { _ in
}) self.cloneAndSegueIfSuccess()
}
)
alert.addAction(UIAlertAction.cancel()) alert.addAction(UIAlertAction.cancel())
return alert return alert
}() }()
@ -174,26 +176,32 @@ class GitRepositorySettingsTableViewController: UITableViewController {
SVProgressHUD.showProgress(progress, status: "CheckingOutBranch".localize(self.gitBranchName)) SVProgressHUD.showProgress(progress, status: "CheckingOutBranch".localize(self.gitBranchName))
} }
try self.passwordStore.cloneRepository(remoteRepoURL: self.gitUrl, try self.passwordStore.cloneRepository(
credential: self.gitCredential, remoteRepoURL: self.gitUrl,
branchName: self.gitBranchName, credential: self.gitCredential,
requestCredentialPassword: self.requestCredentialPassword, branchName: self.gitBranchName,
transferProgressBlock: transferProgressBlock, requestCredentialPassword: self.requestCredentialPassword,
checkoutProgressBlock: checkoutProgressBlock) transferProgressBlock: transferProgressBlock,
checkoutProgressBlock: checkoutProgressBlock
)
SVProgressHUD.dismiss { SVProgressHUD.dismiss {
let savePassphraseAlert: UIAlertController = { let savePassphraseAlert: UIAlertController = {
let alert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: .alert) let alert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in alert.addAction(
Defaults.isRememberGitCredentialPassphraseOn = false UIAlertAction(title: "No".localize(), style: .default) { _ in
self.passwordStore.gitPassword = nil Defaults.isRememberGitCredentialPassphraseOn = false
self.passwordStore.gitSSHPrivateKeyPassphrase = nil self.passwordStore.gitPassword = nil
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) self.passwordStore.gitSSHPrivateKeyPassphrase = nil
}) self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in }
Defaults.isRememberGitCredentialPassphraseOn = true )
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) alert.addAction(
}) UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in
Defaults.isRememberGitCredentialPassphraseOn = true
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
}
)
return alert return alert
}() }()
DispatchQueue.main.async { DispatchQueue.main.async {
@ -244,35 +252,47 @@ class GitRepositorySettingsTableViewController: UITableViewController {
private func showSSHKeyActionSheet() { private func showSSHKeyActionSheet() {
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
optionMenu.addAction(UIAlertAction(title: SSHKeyUrlImportTableViewController.menuLabel, style: .default) { _ in optionMenu.addAction(
self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self) UIAlertAction(title: SSHKeyUrlImportTableViewController.menuLabel, style: .default) { _ in
}) self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self)
optionMenu.addAction(UIAlertAction(title: SSHKeyArmorImportTableViewController.menuLabel, style: .default) { _ in }
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self) )
}) optionMenu.addAction(
optionMenu.addAction(UIAlertAction(title: SSHKeyFileImportTableViewController.menuLabel, style: .default) { _ in UIAlertAction(title: SSHKeyArmorImportTableViewController.menuLabel, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByFileSegue", sender: self) self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
}) }
)
optionMenu.addAction(
UIAlertAction(title: SSHKeyFileImportTableViewController.menuLabel, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByFileSegue", sender: self)
}
)
if isReadyToUse() { if isReadyToUse() {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in optionMenu.addAction(
self.importSSHKey(using: self) UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in
}) self.importSSHKey(using: self)
}
)
} else { } else {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Tips".localize()))", style: .default) { _ in optionMenu.addAction(
let title = "Tips".localize() UIAlertAction(title: "\(Self.menuLabel) (\("Tips".localize()))", style: .default) { _ in
let message = "SshCopyPrivateKeyToPass.".localize() let title = "Tips".localize()
Utils.alert(title: title, message: message, controller: self) let message = "SshCopyPrivateKeyToPass.".localize()
}) Utils.alert(title: title, message: message, controller: self)
}
)
} }
if Defaults.gitSSHKeySource != nil { if Defaults.gitSSHKeySource != nil {
optionMenu.addAction(UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in optionMenu.addAction(
self.passwordStore.removeGitSSHKeys() UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in
Defaults.gitSSHKeySource = nil self.passwordStore.removeGitSSHKeys()
self.sshLabel?.isEnabled = false Defaults.gitSSHKeySource = nil
self.gitAuthenticationMethod = .password self.sshLabel?.isEnabled = false
}) self.gitAuthenticationMethod = .password
}
)
} }
optionMenu.addAction(UIAlertAction.cancel()) optionMenu.addAction(UIAlertAction.cancel())
optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell

View file

@ -41,14 +41,16 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
super.viewDidLoad() super.viewDidLoad()
tableData.append([]) tableData.append([])
for item in Self.openSourceComponents { for item in Self.openSourceComponents {
tableData[0].append([ tableData[0].append(
.title: item[0], [
.action: "link", .title: item[0],
.link: item[1], .action: "link",
.accessoryType: UITableViewCell.AccessoryType.detailDisclosureButton, .link: item[1],
.detailDisclosureAction: #selector(actOnDetailDisclosureButton(_:)), .accessoryType: UITableViewCell.AccessoryType.detailDisclosureButton,
.detailDisclosureData: item[2], .detailDisclosureAction: #selector(actOnDetailDisclosureButton(_:)),
]) .detailDisclosureData: item[2],
]
)
} }
} }

View file

@ -88,9 +88,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
@objc @objc
private func decryptThenShowPassword(keyID: String? = nil) { private func decryptThenShowPassword(keyID: String? = nil) {
guard let passwordEntity = passwordEntity else { guard let passwordEntity = passwordEntity else {
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: { (_) -> Void in Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self) {
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
}) }
return return
} }
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
@ -116,9 +116,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
// alert: cancel or try again // alert: cancel or try again
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: .alert) let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) { _ in alert.addAction(
self.decryptThenShowPassword() UIAlertAction(title: "TryAgain".localize(), style: .default) { _ in
}) self.decryptThenShowPassword()
}
)
self.present(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
} }
} }
@ -288,10 +290,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
var newUrlString = urlString var newUrlString = urlString
if urlString.lowercased().hasPrefix("http://") { if urlString.lowercased().hasPrefix("http://") {
// try to replace http url to https url // try to replace http url to https url
newUrlString = urlString.replacingOccurrences(of: "http://", newUrlString = urlString.replacingOccurrences(
with: "https://", of: "http://",
options: .caseInsensitive, with: "https://",
range: urlString.range(of: "http://")) options: .caseInsensitive,
range: urlString.range(of: "http://")
)
} else if urlString.lowercased().hasPrefix("https://") { } else if urlString.lowercased().hasPrefix("https://") {
// do nothing here // do nothing here
} else { } else {

View file

@ -246,9 +246,11 @@ class PasswordEditorTableViewController: UITableViewController {
if selectedCell == deletePasswordCell { if selectedCell == deletePasswordCell {
let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in alert.addAction(
self.performSegue(withIdentifier: "deletePasswordSegue", sender: self) UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive) { [unowned self] (_) -> Void in
})) self.performSegue(withIdentifier: "deletePasswordSegue", sender: self)
}
)
alert.addAction(UIAlertAction.cancel()) alert.addAction(UIAlertAction.cancel())
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
} else if selectedCell == scanQRCodeCell { } else if selectedCell == scanQRCodeCell {
@ -388,9 +390,11 @@ extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
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?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: { _ in alert.addAction(
self.generateAndCopyPasswordNoOtpCheck() UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive) { _ in
})) self.generateAndCopyPasswordNoOtpCheck()
}
)
alert.addAction(UIAlertAction.cancel()) alert.addAction(UIAlertAction.cancel())
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
} else { } else {
@ -436,12 +440,14 @@ extension PasswordEditorTableViewController: SFSafariViewControllerDelegate {
let message = NSMutableAttributedString(string: "\("SeemsLikeYouHaveCopiedSomething.".localize()) \("FirstStringIs:".localize())\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: UIAlertAction.Style.default, handler: { [unowned self] (_) -> Void in alert.addAction(
// update tableData so to make sure reloadData() works correctly UIAlertAction(title: "Yes", style: UIAlertAction.Style.default) { [unowned self] (_) -> Void in
self.tableData[self.passwordSection][0][PasswordEditorCellKey.content] = generatedPassword // update tableData so to make sure reloadData() works correctly
// update cell manually, no need to call reloadData() self.tableData[self.passwordSection][0][PasswordEditorCellKey.content] = generatedPassword
self.fillPasswordCell?.setContent(content: generatedPassword) // update cell manually, no need to call reloadData()
})) self.fillPasswordCell?.setContent(content: generatedPassword)
}
)
alert.addAction(UIAlertAction.cancel()) alert.addAction(UIAlertAction.cancel())
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
} }

View file

@ -192,17 +192,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
do { do {
try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: { git_transfer_progress, _ in try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword) { git_transfer_progress, _ in
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects) / Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize()) SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects) / Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize())
} }
}) }
if self.passwordStore.numberOfLocalCommits > 0 { if self.passwordStore.numberOfLocalCommits > 0 {
try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: { current, total, _, _ in try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword) { current, total, _, _ in
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(current) / Float(total), status: "PushingToRemoteRepository".localize()) SVProgressHUD.showProgress(Float(current) / Float(total), status: "PushingToRemoteRepository".localize())
} }
}) }
} }
DispatchQueue.main.async { DispatchQueue.main.async {
self.reloadTableView(parent: nil) self.reloadTableView(parent: nil)

View file

@ -129,17 +129,19 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
} }
func presentCameraSettings() { func presentCameraSettings() {
let alertController = UIAlertController(title: "Error".localize(), let alertController = UIAlertController(
message: "CameraAccessDenied.".localize() | "WarningToggleCameraPermissionsResetsApp.".localize(), title: "Error".localize(),
preferredStyle: .alert) message: "CameraAccessDenied.".localize() | "WarningToggleCameraPermissionsResetsApp.".localize(),
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "Cancel".localize(), style: .default)) alertController.addAction(UIAlertAction(title: "Cancel".localize(), style: .default))
alertController.addAction(UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in alertController.addAction(
if let url = URL(string: UIApplication.openSettingsURLString) { UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in
UIApplication.shared.open(url, options: [:], completionHandler: { _ in if let url = URL(string: UIApplication.openSettingsURLString) {
// Handle UIApplication.shared.open(url, options: [:]) { _ in }
}) }
} }
}) )
present(alertController, animated: true) present(alertController, animated: true)
} }

View file

@ -30,9 +30,11 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
if privateKeyURL.scheme?.lowercased() == "http" { if privateKeyURL.scheme?.lowercased() == "http" {
let savePassphraseAlert = UIAlertController(title: "HttpNotSecure".localize(), message: "ReallyUseHttp?".localize(), preferredStyle: .alert) let savePassphraseAlert = UIAlertController(title: "HttpNotSecure".localize(), message: "ReallyUseHttp?".localize(), preferredStyle: .alert)
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in }) savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in })
savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in savePassphraseAlert.addAction(
self.performSegue(withIdentifier: "importSSHKeySegue", sender: self) UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in
}) self.performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
)
return present(savePassphraseAlert, animated: true) return present(savePassphraseAlert, animated: true)
} }
sshPrivateKeyURL = privateKeyURL sshPrivateKeyURL = privateKeyURL

View file

@ -142,36 +142,48 @@ 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)
optionMenu.addAction(UIAlertAction(title: PGPKeyUrlImportTableViewController.menuLabel, style: .default) { _ in optionMenu.addAction(
self.performSegue(withIdentifier: "setPGPKeyByURLSegue", sender: self) UIAlertAction(title: PGPKeyUrlImportTableViewController.menuLabel, style: .default) { _ in
}) self.performSegue(withIdentifier: "setPGPKeyByURLSegue", sender: self)
optionMenu.addAction(UIAlertAction(title: PGPKeyArmorImportTableViewController.menuLabel, style: .default) { _ in }
self.performSegue(withIdentifier: "setPGPKeyByASCIISegue", sender: self) )
}) optionMenu.addAction(
optionMenu.addAction(UIAlertAction(title: PGPKeyFileImportTableViewController.menuLabel, style: .default) { _ in UIAlertAction(title: PGPKeyArmorImportTableViewController.menuLabel, style: .default) { _ in
self.performSegue(withIdentifier: "setPGPKeyByFileSegue", sender: self) self.performSegue(withIdentifier: "setPGPKeyByASCIISegue", sender: self)
}) }
)
optionMenu.addAction(
UIAlertAction(title: PGPKeyFileImportTableViewController.menuLabel, style: .default) { _ in
self.performSegue(withIdentifier: "setPGPKeyByFileSegue", sender: self)
}
)
if isReadyToUse() { if isReadyToUse() {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in optionMenu.addAction(
self.saveImportedKeys() UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in
}) self.saveImportedKeys()
}
)
} else { } else {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Tips".localize()))", style: .default) { _ in optionMenu.addAction(
let title = "Tips".localize() UIAlertAction(title: "\(Self.menuLabel) (\("Tips".localize()))", style: .default) { _ in
let message = "PgpCopyPublicAndPrivateKeyToPass.".localize() let title = "Tips".localize()
Utils.alert(title: title, message: message, controller: self) let message = "PgpCopyPublicAndPrivateKeyToPass.".localize()
}) Utils.alert(title: title, message: message, controller: self)
}
)
} }
if Defaults.pgpKeySource != nil { if Defaults.pgpKeySource != nil {
optionMenu.addAction(UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in optionMenu.addAction(
self.keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey()) UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in
self.keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey()) self.keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
PGPAgent.shared.uninitKeys() self.keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() PGPAgent.shared.uninitKeys()
Defaults.pgpKeySource = nil self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
}) Defaults.pgpKeySource = nil
}
)
} }
optionMenu.addAction(UIAlertAction.cancel()) optionMenu.addAction(UIAlertAction.cancel())
optionMenu.popoverPresentationController?.sourceView = pgpKeyTableViewCell optionMenu.popoverPresentationController?.sourceView = pgpKeyTableViewCell
@ -221,16 +233,16 @@ 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: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert) setPasscodeLockAlert = UIAlertController(title: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert)
setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in setPasscodeLockAlert?.addTextField { textField -> Void in
textField.placeholder = "Passcode".localize() textField.placeholder = "Passcode".localize()
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged) textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
}) }
setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in setPasscodeLockAlert?.addTextField { textField -> Void in
textField.placeholder = "PasswordConfirmation".localize() textField.placeholder = "PasswordConfirmation".localize()
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged) textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
}) }
// save action // save action
let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (_: UIAlertAction) -> Void in let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (_: UIAlertAction) -> Void in

View file

@ -31,14 +31,18 @@ public func requestGitCredentialPassword(credential: GitCredential.Credential,
$0.text = lastPassword ?? "" $0.text = lastPassword ?? ""
$0.isSecureTextEntry = true $0.isSecureTextEntry = true
} }
alert.addAction(UIAlertAction.ok { _ in alert.addAction(
password = alert.textFields?.first?.text UIAlertAction.ok { _ in
sem.signal() password = alert.textFields?.first?.text
}) sem.signal()
alert.addAction(UIAlertAction.cancel { _ in }
password = nil )
sem.signal() alert.addAction(
}) UIAlertAction.cancel { _ in
password = nil
sem.signal()
}
)
controller.present(alert, animated: true) controller.present(alert, animated: true)
} }

View file

@ -29,11 +29,11 @@ public class SecurePasteboard {
backgroundTaskID = UIBackgroundTaskIdentifier.invalid backgroundTaskID = UIBackgroundTaskIdentifier.invalid
} }
backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: { [weak self] in backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
UIPasteboard.general.string = "" UIPasteboard.general.string = ""
UIApplication.shared.endBackgroundTask(UIBackgroundTaskIdentifier.invalid) UIApplication.shared.endBackgroundTask(UIBackgroundTaskIdentifier.invalid)
self?.backgroundTaskID = UIBackgroundTaskIdentifier.invalid self?.backgroundTaskID = UIBackgroundTaskIdentifier.invalid
}) }
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + expirationTime) { [weak self] in DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + expirationTime) { [weak self] in
UIPasteboard.general.string = "" UIPasteboard.general.string = ""

View file

@ -67,7 +67,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
for provider in itemProviders { for provider in itemProviders {
// search using the extensionContext inputs // search using the extensionContext inputs
if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) { if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) {
provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, _) -> Void in provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil) { (item, _) -> Void in
let dictionary = item as! NSDictionary let dictionary = item as! NSDictionary
var url: String? var url: String?
if var urlString = dictionary[OnePasswordExtensionKey.URLStringKey] as? String { if var urlString = dictionary[OnePasswordExtensionKey.URLStringKey] as? String {
@ -83,9 +83,9 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
self?.searchBar.becomeFirstResponder() self?.searchBar.becomeFirstResponder()
self?.searchBarSearchButtonClicked((self?.searchBar)!) self?.searchBarSearchButtonClicked((self?.searchBar)!)
} }
}) }
} else if provider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) { } else if provider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) {
provider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil, completionHandler: { (item, _) -> Void in provider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil) { (item, _) -> Void in
var url: String? var url: String?
if let dictionary = item as? NSDictionary, if let dictionary = item as? NSDictionary,
let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary, let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary,
@ -102,9 +102,9 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
self?.searchBar.becomeFirstResponder() self?.searchBar.becomeFirstResponder()
self?.searchBarSearchButtonClicked((self?.searchBar)!) self?.searchBarSearchButtonClicked((self?.searchBar)!)
} }
}) }
} else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) { } else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, _) -> Void in provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (item, _) -> Void in
let url = (item as? NSURL)!.host let url = (item as? NSURL)!.host
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
self?.extensionAction = .fillBrowser self?.extensionAction = .fillBrowser
@ -113,7 +113,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
self?.searchBar.becomeFirstResponder() self?.searchBar.becomeFirstResponder()
self?.searchBarSearchButtonClicked((self?.searchBar)!) self?.searchBarSearchButtonClicked((self?.searchBar)!)
} }
}) }
} }
} }
} }
@ -157,7 +157,8 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
let username = decryptedPassword.getUsernameForCompletion() let username = decryptedPassword.getUsernameForCompletion()
let password = decryptedPassword.password let password = decryptedPassword.password
DispatchQueue.main.async { // prepare a dictionary to return DispatchQueue.main.async {
// prepare a dictionary to return
switch self.extensionAction { switch self.extensionAction {
case .findLogin: case .findLogin:
let extensionItem = NSExtensionItem() let extensionItem = NSExtensionItem()

View file

@ -95,32 +95,34 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
appIconView.layer.masksToBounds = true appIconView.layer.masksToBounds = true
view?.addSubview(appIconView) view?.addSubview(appIconView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate(
passcodeTextField.widthAnchor.constraint(equalToConstant: 250), [
passcodeTextField.heightAnchor.constraint(equalToConstant: 40), passcodeTextField.widthAnchor.constraint(equalToConstant: 250),
passcodeTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor), passcodeTextField.heightAnchor.constraint(equalToConstant: 40),
passcodeTextField.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -20), passcodeTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// above passocde passcodeTextField.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -20),
appIconView.widthAnchor.constraint(equalToConstant: appIconSize), // above passocde
appIconView.heightAnchor.constraint(equalToConstant: appIconSize), appIconView.widthAnchor.constraint(equalToConstant: appIconSize),
appIconView.centerXAnchor.constraint(equalTo: view.centerXAnchor), appIconView.heightAnchor.constraint(equalToConstant: appIconSize),
appIconView.bottomAnchor.constraint(equalTo: passcodeTextField.topAnchor, constant: -appIconSize), appIconView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// below passcode appIconView.bottomAnchor.constraint(equalTo: passcodeTextField.topAnchor, constant: -appIconSize),
biometryAuthButton.widthAnchor.constraint(equalToConstant: 250), // below passcode
biometryAuthButton.heightAnchor.constraint(equalToConstant: 40), biometryAuthButton.widthAnchor.constraint(equalToConstant: 250),
biometryAuthButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), biometryAuthButton.heightAnchor.constraint(equalToConstant: 40),
biometryAuthButton.topAnchor.constraint(equalTo: passcodeTextField.bottomAnchor), biometryAuthButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// cancel (top-left of the screen) biometryAuthButton.topAnchor.constraint(equalTo: passcodeTextField.bottomAnchor),
cancelButton.widthAnchor.constraint(equalToConstant: 150), // cancel (top-left of the screen)
cancelButton.heightAnchor.constraint(equalToConstant: 40), cancelButton.widthAnchor.constraint(equalToConstant: 150),
cancelButton.topAnchor.constraint(equalTo: view.safeTopAnchor), cancelButton.heightAnchor.constraint(equalToConstant: 40),
cancelButton.leftAnchor.constraint(equalTo: view.safeLeftAnchor, constant: 20), cancelButton.topAnchor.constraint(equalTo: view.safeTopAnchor),
// bottom of the screen cancelButton.leftAnchor.constraint(equalTo: view.safeLeftAnchor, constant: 20),
forgotPasscodeButton.widthAnchor.constraint(equalToConstant: 250), // bottom of the screen
forgotPasscodeButton.heightAnchor.constraint(equalToConstant: 40), forgotPasscodeButton.widthAnchor.constraint(equalToConstant: 250),
forgotPasscodeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), forgotPasscodeButton.heightAnchor.constraint(equalToConstant: 40),
forgotPasscodeButton.bottomAnchor.constraint(equalTo: view.safeBottomAnchor, constant: -40), forgotPasscodeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
]) forgotPasscodeButton.bottomAnchor.constraint(equalTo: view.safeBottomAnchor, constant: -40),
]
)
// dismiss keyboard when tapping anywhere // dismiss keyboard when tapping anywhere
let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing)) let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing))
@ -147,10 +149,10 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
// pop // pop
if presentingViewController?.presentedViewController == self { if presentingViewController?.presentedViewController == self {
// if presented as modal // if presented as modal
dismiss(animated: true, completion: { [weak self] in dismiss(animated: true) { [weak self] in
self?.dismissCompletionCallback?() self?.dismissCompletionCallback?()
completionHandler?() completionHandler?()
}) }
} else { } else {
// if pushed in a navigation controller // if pushed in a navigation controller
_ = navigationController?.popViewController(animated: true) _ = navigationController?.popViewController(animated: true)
@ -190,30 +192,32 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
@objc @objc
func forgotPasscodeButtonPressedAction(_: UIButton) { func forgotPasscodeButtonPressedAction(_: UIButton) {
let alert = UIAlertController(title: "ResetPass".localize(), message: "ResetPassExplanation.".localize(), preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "ResetPass".localize(), message: "ResetPassExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in alert.addAction(
let myContext = LAContext() UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive) { [unowned self] (_) -> Void in
var error: NSError? let myContext = LAContext()
// If the device passcode is not set, reset the app. var error: NSError?
guard myContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else { // If the device passcode is not set, reset the app.
self.passwordStore.erase() guard myContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
self.passcodeLockDidSucceed() self.passwordStore.erase()
return self.passcodeLockDidSucceed()
} return
// If the device passcode is set, authentication is required. }
myContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "ErasePasswordStoreData".localize()) { success, error in // If the device passcode is set, authentication is required.
if success { myContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "ErasePasswordStoreData".localize()) { success, error in
DispatchQueue.main.async { if success {
// User authenticated successfully, take appropriate action DispatchQueue.main.async {
self.passwordStore.erase() // User authenticated successfully, take appropriate action
self.passcodeLockDidSucceed() self.passwordStore.erase()
} self.passcodeLockDidSucceed()
} else { }
DispatchQueue.main.async { } else {
Utils.alert(title: "Error".localize(), message: error?.localizedDescription ?? "", controller: self, completion: nil) DispatchQueue.main.async {
Utils.alert(title: "Error".localize(), message: error?.localizedDescription ?? "", controller: self, completion: nil)
}
} }
} }
} }
})) )
alert.addAction(UIAlertAction.dismiss()) alert.addAction(UIAlertAction.dismiss())
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
} }

View file

@ -37,10 +37,12 @@ public extension FileManager {
} }
// We have to enumerate all directory contents, including subdirectories. // We have to enumerate all directory contents, including subdirectories.
let enumerator = self.enumerator(at: directoryURL, let enumerator = self.enumerator(
includingPropertiesForKeys: prefetchedProperties, at: directoryURL,
options: FileManager.DirectoryEnumerationOptions(), includingPropertiesForKeys: prefetchedProperties,
errorHandler: errorHandler) options: FileManager.DirectoryEnumerationOptions(),
errorHandler: errorHandler
)
precondition(enumerator != nil) precondition(enumerator != nil)
// Start the traversal: // Start the traversal:

View file

@ -46,10 +46,12 @@ public enum Utils {
let title = "Passphrase".localize() + " (\(keyID.suffix(8)))" let title = "Passphrase".localize() + " (\(keyID.suffix(8)))"
let message = "FillInPgpPassphrase.".localize() let message = "FillInPgpPassphrase.".localize()
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction.ok { _ in alert.addAction(
passphrase = alert.textFields?.first?.text ?? "" UIAlertAction.ok { _ in
sem.signal() passphrase = alert.textFields?.first?.text ?? ""
}) sem.signal()
}
)
alert.addTextField { textField in alert.addTextField { textField in
textField.text = AppKeychain.shared.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) ?? "" textField.text = AppKeychain.shared.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) ?? ""
textField.isSecureTextEntry = true textField.isSecureTextEntry = true

View file

@ -62,7 +62,7 @@ public class PasswordStore {
try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil)
} }
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))] container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))]
container.loadPersistentStores(completionHandler: { _, error in container.loadPersistentStores { _, error in
if let error = error as NSError? { if let error = error as NSError? {
// 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.
@ -77,7 +77,7 @@ public class PasswordStore {
*/ */
fatalError("UnresolvedError".localize("\(error.localizedDescription), \(error.userInfo)")) fatalError("UnresolvedError".localize("\(error.localizedDescription), \(error.userInfo)"))
} }
}) }
return container.viewContext return container.viewContext
}() }()
@ -198,10 +198,12 @@ public class PasswordStore {
gitPassword = nil gitPassword = nil
gitSSHPrivateKeyPassphrase = nil gitSSHPrivateKeyPassphrase = nil
do { do {
storeRepository = try GTRepository.clone(from: remoteRepoURL, storeRepository = try GTRepository.clone(
toWorkingDirectory: tempStoreURL, from: remoteRepoURL,
options: options, toWorkingDirectory: tempStoreURL,
transferProgressBlock: transferProgressBlock) options: options,
transferProgressBlock: transferProgressBlock
)
try fm.moveItem(at: tempStoreURL, to: storeURL) try fm.moveItem(at: tempStoreURL, to: storeURL)
storeRepository = try GTRepository(url: storeURL) storeRepository = try GTRepository(url: storeURL)
if (try storeRepository?.currentBranch().name) != branchName { if (try storeRepository?.currentBranch().name) != branchName {
@ -375,10 +377,10 @@ public class PasswordStore {
guard let storeRepository = storeRepository else { guard let storeRepository = storeRepository else {
return "Unknown".localize() 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 else {
let latestCommitTime = blameHunks.map({ return "Unknown".localize()
$0.finalSignature?.time?.timeIntervalSince1970 ?? 0 }
}).max() else { guard let latestCommitTime = blameHunks.map({ $0.finalSignature?.time?.timeIntervalSince1970 ?? 0 }).max() else {
return "Unknown".localize() return "Unknown".localize()
} }
let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime) let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime)