Enable SwiftLint rule 'identifier_name' and handle all violations
This commit is contained in:
parent
7ada4dd96d
commit
e8389eb262
21 changed files with 157 additions and 156 deletions
|
|
@ -77,7 +77,7 @@ whitelist_rules:
|
||||||
- generic_type_name
|
- generic_type_name
|
||||||
- ibinspectable_in_extension
|
- ibinspectable_in_extension
|
||||||
- identical_operands
|
- identical_operands
|
||||||
# - identifier_name
|
- identifier_name
|
||||||
- implicit_getter
|
- implicit_getter
|
||||||
- implicit_return
|
- implicit_return
|
||||||
# - implicitly_unwrapped_optional
|
# - implicitly_unwrapped_optional
|
||||||
|
|
@ -212,6 +212,9 @@ attributes:
|
||||||
closure_body_length:
|
closure_body_length:
|
||||||
warning: 40
|
warning: 40
|
||||||
error: 60
|
error: 60
|
||||||
|
identifier_name:
|
||||||
|
excluded: ["id", "to", "Defaults"]
|
||||||
|
allowed_symbols: ["_"]
|
||||||
type_name:
|
type_name:
|
||||||
max_length: 50
|
max_length: 50
|
||||||
trailing_closure:
|
trailing_closure:
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
|
||||||
// Start accessing a security-scoped resource.
|
// Start accessing a security-scoped resource.
|
||||||
guard url.startAccessingSecurityScopedResource() else {
|
guard url.startAccessingSecurityScopedResource() else {
|
||||||
// Handle the failure here.
|
// Handle the failure here.
|
||||||
throw AppError.ReadingFile(fileName)
|
throw AppError.readingFile(fileName: fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure you release the security-scoped resource when you are done.
|
// Make sure you release the security-scoped resource when you are done.
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,10 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self)
|
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self)
|
||||||
self.password = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
self.password = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||||
self.showPassword()
|
self.showPassword()
|
||||||
} catch let AppError.PgpPrivateKeyNotFound(key) {
|
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// alert: cancel or try again
|
// alert: cancel or try again
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||||
self.decryptThenShowPassword(keyID: action.title)
|
self.decryptThenShowPassword(keyID: action.title)
|
||||||
|
|
@ -193,11 +193,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
tableView.reloadData()
|
tableView.reloadData()
|
||||||
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
} catch let AppError.PgpPublicKeyNotFound(key) {
|
} catch let AppError.pgpPublicKeyNotFound(keyID: key) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// alert: cancel or select keys
|
// alert: cancel or select keys
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||||
self.saveEditPassword(password: password, keyID: action.title)
|
self.saveEditPassword(password: password, keyID: action.title)
|
||||||
|
|
|
||||||
|
|
@ -155,11 +155,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}
|
}
|
||||||
} catch let AppError.PgpPublicKeyNotFound(key) {
|
} catch let AppError.pgpPublicKeyNotFound(keyID: key) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// alert: cancel or select keys
|
// alert: cancel or select keys
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let alert = UIAlertController(title: "Cannot Encrypt Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "Cannot Encrypt Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||||
self.addPassword(password: password, keyID: action.title)
|
self.addPassword(password: password, keyID: action.title)
|
||||||
|
|
@ -291,7 +291,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let ac = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
let allAction = UIAlertAction(title: "All Passwords", style: .default) { _ in
|
let allAction = UIAlertAction(title: "All Passwords", style: .default) { _ in
|
||||||
self.reloadTableView(parent: nil, label: .all)
|
self.reloadTableView(parent: nil, label: .all)
|
||||||
}
|
}
|
||||||
|
|
@ -303,11 +303,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
}
|
}
|
||||||
let cancelAction = UIAlertAction.cancel()
|
let cancelAction = UIAlertAction.cancel()
|
||||||
|
|
||||||
ac.addAction(allAction)
|
alertController.addAction(allAction)
|
||||||
ac.addAction(unsyncedAction)
|
alertController.addAction(unsyncedAction)
|
||||||
ac.addAction(cancelAction)
|
alertController.addAction(cancelAction)
|
||||||
|
|
||||||
present(ac, animated: true, completion: nil)
|
present(alertController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
|
@ -488,10 +488,10 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize())
|
SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 0.6)
|
SVProgressHUD.dismiss(withDelay: 0.6)
|
||||||
}
|
}
|
||||||
} catch let AppError.PgpPrivateKeyNotFound(key) {
|
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// alert: cancel or try again
|
// alert: cancel or try again
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||||
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
||||||
|
|
@ -514,8 +514,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
var newSections = [(title: String, entries: [PasswordTableEntry])]()
|
var newSections = [(title: String, entries: [PasswordTableEntry])]()
|
||||||
|
|
||||||
// initialize all sections
|
// initialize all sections
|
||||||
for i in 0 ..< sectionTitles.count {
|
for titleNumber in 0 ..< sectionTitles.count {
|
||||||
newSections.append((title: sectionTitles[i], entries: [PasswordTableEntry]()))
|
newSections.append((title: sectionTitles[titleNumber], entries: [PasswordTableEntry]()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// put entries into sections
|
// put entries into sections
|
||||||
|
|
@ -525,10 +525,10 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort each list and set sectionTitles
|
// sort each list and set sectionTitles
|
||||||
for i in 0 ..< sectionTitles.count {
|
for titleNumber in 0 ..< sectionTitles.count {
|
||||||
let entriesToSort = newSections[i].entries
|
let entriesToSort = newSections[titleNumber].entries
|
||||||
let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordTableEntry.title))
|
let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordTableEntry.title))
|
||||||
newSections[i].entries = sortedEntries as! [PasswordTableEntry]
|
newSections[titleNumber].entries = sortedEntries as! [PasswordTableEntry]
|
||||||
}
|
}
|
||||||
|
|
||||||
// only keep non-empty sections
|
// only keep non-empty sections
|
||||||
|
|
@ -544,8 +544,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
if identifier == "showPasswordDetail" {
|
if identifier == "showPasswordDetail" {
|
||||||
guard PGPAgent.shared.isPrepared else {
|
guard PGPAgent.shared.isPrepared else {
|
||||||
Utils.alert(title: "CannotShowPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
Utils.alert(title: "CannotShowPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||||
if let s = sender as? UITableViewCell {
|
if let sender = sender as? UITableViewCell {
|
||||||
let selectedIndexPath = tableView.indexPath(for: s)!
|
let selectedIndexPath = tableView.indexPath(for: sender)!
|
||||||
tableView.deselectRow(at: selectedIndexPath, animated: true)
|
tableView.deselectRow(at: selectedIndexPath, animated: true)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate {
|
||||||
// Start accessing a security-scoped resource.
|
// Start accessing a security-scoped resource.
|
||||||
guard url.startAccessingSecurityScopedResource() else {
|
guard url.startAccessingSecurityScopedResource() else {
|
||||||
// Handle the failure here.
|
// Handle the failure here.
|
||||||
throw AppError.ReadingFile(fileName)
|
throw AppError.readingFile(fileName: fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure you release the security-scoped resource when you are done.
|
// Make sure you release the security-scoped resource when you are done.
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,9 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
||||||
let passwordCredential = ASPasswordCredential(user: username, password: password)
|
let passwordCredential = ASPasswordCredential(user: username, password: password)
|
||||||
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
|
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
|
||||||
}
|
}
|
||||||
} catch let AppError.PgpPrivateKeyNotFound(key) {
|
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||||
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,10 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch let AppError.PgpPrivateKeyNotFound(key) {
|
} catch let AppError.pgpPrivateKeyNotFound(keyID: key) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
// alert: cancel or try again
|
// alert: cancel or try again
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||||
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title)
|
||||||
|
|
|
||||||
|
|
@ -47,5 +47,5 @@ enum OnePasswordExtensionError {
|
||||||
static let errorCodeCollectFieldsScriptFailed = 4
|
static let errorCodeCollectFieldsScriptFailed = 4
|
||||||
static let errorCodeFillFieldsScriptFailed = 5
|
static let errorCodeFillFieldsScriptFailed = 5
|
||||||
static let errorCodeUnexpectedData = 6
|
static let errorCodeUnexpectedData = 6
|
||||||
static let errorCodeFailedToObtainURLStringFromWebView = 7
|
static let errorCodeFailedToObtainURLStringFromWebView = 7 // swiftlint:disable:this identifier_name
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import Crypto
|
||||||
|
|
||||||
struct GopenPGPInterface: PGPInterface {
|
struct GopenPGPInterface: PGPInterface {
|
||||||
private static let errorMapping: [String: Error] = [
|
private static let errorMapping: [String: Error] = [
|
||||||
"gopenpgp: error in unlocking key: openpgp: invalid data: private key checksum failure": AppError.WrongPassphrase,
|
"gopenpgp: error in unlocking key: openpgp: invalid data: private key checksum failure": AppError.wrongPassphrase,
|
||||||
"openpgp: incorrect key": AppError.KeyExpiredOrIncompatible,
|
"openpgp: incorrect key": AppError.keyExpiredOrIncompatible,
|
||||||
]
|
]
|
||||||
|
|
||||||
private var publicKeys: [String: CryptoKey] = [:]
|
private var publicKeys: [String: CryptoKey] = [:]
|
||||||
|
|
@ -23,24 +23,24 @@ struct GopenPGPInterface: PGPInterface {
|
||||||
|
|
||||||
for key in pubKeys {
|
for key in pubKeys {
|
||||||
var error: NSError?
|
var error: NSError?
|
||||||
guard let k = CryptoNewKeyFromArmored(key, &error) else {
|
guard let cryptoKey = CryptoNewKeyFromArmored(key, &error) else {
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
throw error!
|
throw error!
|
||||||
}
|
}
|
||||||
throw AppError.KeyImport
|
throw AppError.keyImport
|
||||||
}
|
}
|
||||||
publicKeys[k.getFingerprint().lowercased()] = k
|
publicKeys[cryptoKey.getFingerprint().lowercased()] = cryptoKey
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in prvKeys {
|
for key in prvKeys {
|
||||||
var error: NSError?
|
var error: NSError?
|
||||||
guard let k = CryptoNewKeyFromArmored(key, &error) else {
|
guard let cryptoKey = CryptoNewKeyFromArmored(key, &error) else {
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
throw error!
|
throw error!
|
||||||
}
|
}
|
||||||
throw AppError.KeyImport
|
throw AppError.keyImport
|
||||||
}
|
}
|
||||||
privateKeys[k.getFingerprint().lowercased()] = k
|
privateKeys[cryptoKey.getFingerprint().lowercased()] = cryptoKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,9 +71,9 @@ struct GopenPGPInterface: PGPInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? {
|
func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? {
|
||||||
guard let e = privateKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) }),
|
guard let key = privateKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) }),
|
||||||
let privateKey = privateKeys[e.key] else {
|
let privateKey = privateKeys[key.key] else {
|
||||||
throw AppError.Decryption
|
throw AppError.decryption
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
@ -84,7 +84,7 @@ struct GopenPGPInterface: PGPInterface {
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
throw error!
|
throw error!
|
||||||
}
|
}
|
||||||
throw AppError.Decryption
|
throw AppError.decryption
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = createPgpMessage(from: encryptedData)
|
let message = createPgpMessage(from: encryptedData)
|
||||||
|
|
@ -95,9 +95,9 @@ struct GopenPGPInterface: PGPInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func encrypt(plainData: Data, keyID: String) throws -> Data {
|
func encrypt(plainData: Data, keyID: String) throws -> Data {
|
||||||
guard let e = publicKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) }),
|
guard let key = publicKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) }),
|
||||||
let publicKey = publicKeys[e.key] else {
|
let publicKey = publicKeys[key.key] else {
|
||||||
throw AppError.Encryption
|
throw AppError.encryption
|
||||||
}
|
}
|
||||||
|
|
||||||
var error: NSError?
|
var error: NSError?
|
||||||
|
|
@ -106,7 +106,7 @@ struct GopenPGPInterface: PGPInterface {
|
||||||
guard error == nil else {
|
guard error == nil else {
|
||||||
throw error!
|
throw error!
|
||||||
}
|
}
|
||||||
throw AppError.Encryption
|
throw AppError.encryption
|
||||||
}
|
}
|
||||||
|
|
||||||
let encryptedData = try keyRing.encrypt(CryptoNewPlainMessage(plainData.mutable as Data), privateKey: nil)
|
let encryptedData = try keyRing.encrypt(CryptoNewPlainMessage(plainData.mutable as Data), privateKey: nil)
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,14 @@ struct ObjectivePGPInterface: PGPInterface {
|
||||||
|
|
||||||
init(publicArmoredKey: String, privateArmoredKey: String) throws {
|
init(publicArmoredKey: String, privateArmoredKey: String) throws {
|
||||||
guard let publicKeyData = publicArmoredKey.data(using: .ascii), let privateKeyData = privateArmoredKey.data(using: .ascii) else {
|
guard let publicKeyData = publicArmoredKey.data(using: .ascii), let privateKeyData = privateArmoredKey.data(using: .ascii) else {
|
||||||
throw AppError.KeyImport
|
throw AppError.keyImport
|
||||||
}
|
}
|
||||||
let publicKeys = try ObjectivePGP.readKeys(from: publicKeyData)
|
let publicKeys = try ObjectivePGP.readKeys(from: publicKeyData)
|
||||||
let privateKeys = try ObjectivePGP.readKeys(from: privateKeyData)
|
let privateKeys = try ObjectivePGP.readKeys(from: privateKeyData)
|
||||||
keyring.import(keys: publicKeys)
|
keyring.import(keys: publicKeys)
|
||||||
keyring.import(keys: privateKeys)
|
keyring.import(keys: privateKeys)
|
||||||
guard let publicKey = publicKeys.first, let privateKey = privateKeys.first else {
|
guard let publicKey = publicKeys.first, let privateKey = privateKeys.first else {
|
||||||
throw AppError.KeyImport
|
throw AppError.keyImport
|
||||||
}
|
}
|
||||||
self.publicKey = publicKey
|
self.publicKey = publicKey
|
||||||
self.privateKey = privateKey
|
self.privateKey = privateKey
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public class PGPAgent {
|
||||||
guard let publicKey: String = keyStore.get(for: PgpKey.PUBLIC.getKeychainKey()),
|
guard let publicKey: String = keyStore.get(for: PgpKey.PUBLIC.getKeychainKey()),
|
||||||
let privateKey: String = keyStore.get(for: PgpKey.PRIVATE.getKeychainKey()) else {
|
let privateKey: String = keyStore.get(for: PgpKey.PRIVATE.getKeychainKey()) else {
|
||||||
pgpInterface = nil
|
pgpInterface = nil
|
||||||
throw AppError.KeyImport
|
throw AppError.keyImport
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
pgpInterface = try GopenPGPInterface(publicArmoredKey: publicKey, privateArmoredKey: privateKey)
|
pgpInterface = try GopenPGPInterface(publicArmoredKey: publicKey, privateArmoredKey: privateKey)
|
||||||
|
|
@ -48,7 +48,7 @@ public class PGPAgent {
|
||||||
// Init keys.
|
// Init keys.
|
||||||
try checkAndInit()
|
try checkAndInit()
|
||||||
guard let pgpInterface = pgpInterface else {
|
guard let pgpInterface = pgpInterface else {
|
||||||
throw AppError.Decryption
|
throw AppError.decryption
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyID = keyID
|
var keyID = keyID
|
||||||
|
|
@ -56,7 +56,7 @@ public class PGPAgent {
|
||||||
if pgpInterface.keyID.count == 1 {
|
if pgpInterface.keyID.count == 1 {
|
||||||
keyID = pgpInterface.keyID.first!
|
keyID = pgpInterface.keyID.first!
|
||||||
} else {
|
} else {
|
||||||
throw AppError.PgpPrivateKeyNotFound(keyID: keyID)
|
throw AppError.pgpPrivateKeyNotFound(keyID: keyID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,14 +83,14 @@ public class PGPAgent {
|
||||||
public func encrypt(plainData: Data, keyID: String) throws -> Data {
|
public func encrypt(plainData: Data, keyID: String) throws -> Data {
|
||||||
try checkAndInit()
|
try checkAndInit()
|
||||||
guard let pgpInterface = pgpInterface else {
|
guard let pgpInterface = pgpInterface else {
|
||||||
throw AppError.Encryption
|
throw AppError.encryption
|
||||||
}
|
}
|
||||||
var keyID = keyID
|
var keyID = keyID
|
||||||
if !pgpInterface.containsPublicKey(with: keyID) {
|
if !pgpInterface.containsPublicKey(with: keyID) {
|
||||||
if pgpInterface.keyID.count == 1 {
|
if pgpInterface.keyID.count == 1 {
|
||||||
keyID = pgpInterface.keyID.first!
|
keyID = pgpInterface.keyID.first!
|
||||||
} else {
|
} else {
|
||||||
throw AppError.PgpPublicKeyNotFound(keyID: keyID)
|
throw AppError.pgpPublicKeyNotFound(keyID: keyID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return try pgpInterface.encrypt(plainData: plainData, keyID: keyID)
|
return try pgpInterface.encrypt(plainData: plainData, keyID: keyID)
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ extension UIAlertAction {
|
||||||
public static func selectKey(controller: UIViewController, handler: ((UIAlertAction) -> Void)?) -> UIAlertAction {
|
public static func selectKey(controller: UIViewController, handler: ((UIAlertAction) -> Void)?) -> UIAlertAction {
|
||||||
UIAlertAction(title: "Select Key", style: .default) { _ in
|
UIAlertAction(title: "Select Key", style: .default) { _ in
|
||||||
let selectKeyAlert = UIAlertController(title: "Select from imported keys", message: nil, preferredStyle: .actionSheet)
|
let selectKeyAlert = UIAlertController(title: "Select from imported keys", message: nil, preferredStyle: .actionSheet)
|
||||||
try? PGPAgent.shared.getShortKeyID().forEach { k in
|
try? PGPAgent.shared.getShortKeyID().forEach { keyID in
|
||||||
let action = UIAlertAction(title: k, style: .default, handler: handler)
|
let action = UIAlertAction(title: keyID, style: .default, handler: handler)
|
||||||
selectKeyAlert.addAction(action)
|
selectKeyAlert.addAction(action)
|
||||||
}
|
}
|
||||||
selectKeyAlert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
selectKeyAlert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
||||||
|
|
|
||||||
|
|
@ -7,34 +7,35 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
public enum AppError: Error, Equatable {
|
public enum AppError: Error, Equatable {
|
||||||
case RepositoryNotSet
|
case repositoryNotSet
|
||||||
case RepositoryRemoteBranchNotFound(_: String)
|
case repositoryRemoteBranchNotFound(branchName: String)
|
||||||
case RepositoryBranchNotFound(_: String)
|
case repositoryBranchNotFound(branchName: String)
|
||||||
case KeyImport
|
case keyImport
|
||||||
case ReadingFile(_: String)
|
case readingFile(fileName: String)
|
||||||
case PasswordDuplicated
|
case passwordDuplicated
|
||||||
case GitReset
|
case gitReset
|
||||||
case GitCreateSignature
|
case gitCreateSignature
|
||||||
case GitPushNotSuccessful
|
case gitPushNotSuccessful
|
||||||
case PasswordEntity
|
case passwordEntity
|
||||||
case PgpPublicKeyNotFound(keyID: String)
|
case pgpPublicKeyNotFound(keyID: String)
|
||||||
case PgpPrivateKeyNotFound(keyID: String)
|
case pgpPrivateKeyNotFound(keyID: String)
|
||||||
case KeyExpiredOrIncompatible
|
case keyExpiredOrIncompatible
|
||||||
case WrongPassphrase
|
case wrongPassphrase
|
||||||
case WrongPasswordFilename
|
case wrongPasswordFilename
|
||||||
case Decryption
|
case decryption
|
||||||
case Encryption
|
case encryption
|
||||||
case Encoding
|
case encoding
|
||||||
case Unknown
|
case unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppError: LocalizedError {
|
extension AppError: LocalizedError {
|
||||||
public var errorDescription: String? {
|
public var errorDescription: String? {
|
||||||
let localizationKey = "\(String(describing: self).prefix { $0 != "(" })Error."
|
let enumName = String(describing: self)
|
||||||
|
let localizationKey = "\(enumName.first!.uppercased())\(enumName.dropFirst().prefix { $0 != "(" })Error."
|
||||||
switch self {
|
switch self {
|
||||||
case let .RepositoryRemoteBranchNotFound(name), let .RepositoryBranchNotFound(name), let .ReadingFile(name):
|
case let .repositoryRemoteBranchNotFound(name), let .repositoryBranchNotFound(name), let .readingFile(name):
|
||||||
return localizationKey.localize(name)
|
return localizationKey.localize(name)
|
||||||
case let .PgpPublicKeyNotFound(keyID), let .PgpPrivateKeyNotFound(keyID):
|
case let .pgpPublicKeyNotFound(keyID), let .pgpPrivateKeyNotFound(keyID):
|
||||||
return localizationKey.localize(keyID)
|
return localizationKey.localize(keyID)
|
||||||
default:
|
default:
|
||||||
return localizationKey.localize()
|
return localizationKey.localize()
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,9 @@ public class AppKeychain: KeyStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeAllContent(withPrefix prefix: String) {
|
public func removeAllContent(withPrefix prefix: String) {
|
||||||
for k in keychain.allKeys() {
|
keychain.allKeys()
|
||||||
if k.hasPrefix(prefix) {
|
.filter { $0.hasPrefix(prefix) }
|
||||||
try? keychain.remove(k)
|
.forEach { try? keychain.remove($0) }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getPGPKeyPassphraseKey(keyID: String) -> String {
|
public static func getPGPKeyPassphraseKey(keyID: String) -> String {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class KeyFileManager {
|
||||||
|
|
||||||
public func importKey(from string: String) throws {
|
public func importKey(from string: String) throws {
|
||||||
guard string.unicodeScalars.allSatisfy({ $0.isASCII }) else {
|
guard string.unicodeScalars.allSatisfy({ $0.isASCII }) else {
|
||||||
throw AppError.Encoding
|
throw AppError.encoding
|
||||||
}
|
}
|
||||||
keyHandler(string, keyType.getKeychainKey())
|
keyHandler(string, keyType.getKeychainKey())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import SwiftyUserDefaults
|
||||||
|
|
||||||
extension PasswordEntity {
|
extension PasswordEntity {
|
||||||
public var nameWithCategory: String {
|
public var nameWithCategory: String {
|
||||||
if let p = path, p.hasSuffix(".gpg") {
|
if let path = path, path.hasSuffix(".gpg") {
|
||||||
return String(p.prefix(upTo: p.index(p.endIndex, offsetBy: -4)))
|
return String(path.prefix(upTo: path.index(path.endIndex, offsetBy: -4)))
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -33,10 +33,10 @@ extension PasswordEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getURL() throws -> URL {
|
public func getURL() throws -> URL {
|
||||||
if let p = getPath().stringByAddingPercentEncodingForRFC3986(), let u = URL(string: p) {
|
if let path = getPath().stringByAddingPercentEncodingForRFC3986(), let url = URL(string: path) {
|
||||||
return u
|
return url
|
||||||
}
|
}
|
||||||
throw AppError.Unknown
|
throw AppError.unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: define some getters to get core data, we need to consider
|
// XXX: define some getters to get core data, we need to consider
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ public class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let fm = FileManager.default
|
private let fileManager = FileManager.default
|
||||||
private lazy var context: NSManagedObjectContext = {
|
private lazy var context: NSManagedObjectContext = {
|
||||||
let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")!
|
let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")!
|
||||||
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
||||||
|
|
@ -86,7 +86,7 @@ public class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var sizeOfRepositoryByteCount: UInt64 {
|
public var sizeOfRepositoryByteCount: UInt64 {
|
||||||
(try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: storeURL)) ?? 0
|
(try? fileManager.allocatedSizeOfDirectoryAtURL(directoryURL: storeURL)) ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public var numberOfLocalCommits: Int {
|
public var numberOfLocalCommits: Int {
|
||||||
|
|
@ -108,7 +108,7 @@ public class PasswordStore {
|
||||||
importExistingKeysIntoKeychain()
|
importExistingKeysIntoKeychain()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if fm.fileExists(atPath: storeURL.path) {
|
if fileManager.fileExists(atPath: storeURL.path) {
|
||||||
try self.storeRepository = GTRepository(url: storeURL)
|
try self.storeRepository = GTRepository(url: storeURL)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -127,8 +127,7 @@ public class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func repositoryExists() -> Bool {
|
public func repositoryExists() -> Bool {
|
||||||
let fm = FileManager()
|
fileManager.fileExists(atPath: Globals.repositoryPath)
|
||||||
return fm.fileExists(atPath: Globals.repositoryPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func passwordExisted(password: Password) -> Bool {
|
public func passwordExisted(password: Password) -> Bool {
|
||||||
|
|
@ -178,8 +177,8 @@ public class PasswordStore {
|
||||||
transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { _, _ in },
|
transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { _, _ in },
|
||||||
checkoutProgressBlock: @escaping (String, UInt, UInt) -> Void = { _, _, _ in }
|
checkoutProgressBlock: @escaping (String, UInt, UInt) -> Void = { _, _, _ in }
|
||||||
) throws {
|
) throws {
|
||||||
try? fm.removeItem(at: storeURL)
|
try? fileManager.removeItem(at: storeURL)
|
||||||
try? fm.removeItem(at: tempStoreURL)
|
try? fileManager.removeItem(at: tempStoreURL)
|
||||||
gitPassword = nil
|
gitPassword = nil
|
||||||
gitSSHPrivateKeyPassphrase = nil
|
gitSSHPrivateKeyPassphrase = nil
|
||||||
do {
|
do {
|
||||||
|
|
@ -189,7 +188,7 @@ public class PasswordStore {
|
||||||
options: options,
|
options: options,
|
||||||
transferProgressBlock: transferProgressBlock
|
transferProgressBlock: transferProgressBlock
|
||||||
)
|
)
|
||||||
try fm.moveItem(at: tempStoreURL, to: storeURL)
|
try fileManager.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 {
|
||||||
try checkoutAndChangeBranch(withName: branchName, progressBlock: checkoutProgressBlock)
|
try checkoutAndChangeBranch(withName: branchName, progressBlock: checkoutProgressBlock)
|
||||||
|
|
@ -211,12 +210,12 @@ public class PasswordStore {
|
||||||
|
|
||||||
private func checkoutAndChangeBranch(withName localBranchName: String, progressBlock: @escaping (String, UInt, UInt) -> Void) throws {
|
private func checkoutAndChangeBranch(withName localBranchName: String, progressBlock: @escaping (String, UInt, UInt) -> Void) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
let remoteBranchName = "origin/\(localBranchName)"
|
let remoteBranchName = "origin/\(localBranchName)"
|
||||||
let remoteBranch = try storeRepository.lookUpBranch(withName: remoteBranchName, type: .remote, success: nil)
|
let remoteBranch = try storeRepository.lookUpBranch(withName: remoteBranchName, type: .remote, success: nil)
|
||||||
guard let remoteBranchOid = remoteBranch.oid else {
|
guard let remoteBranchOid = remoteBranch.oid else {
|
||||||
throw AppError.RepositoryRemoteBranchNotFound(remoteBranchName)
|
throw AppError.repositoryRemoteBranchNotFound(branchName: remoteBranchName)
|
||||||
}
|
}
|
||||||
let localBranch = try storeRepository.createBranchNamed(localBranchName, from: remoteBranchOid, message: nil)
|
let localBranch = try storeRepository.createBranchNamed(localBranchName, from: remoteBranchOid, message: nil)
|
||||||
try localBranch.updateTrackingBranch(remoteBranch)
|
try localBranch.updateTrackingBranch(remoteBranch)
|
||||||
|
|
@ -230,7 +229,7 @@ public class PasswordStore {
|
||||||
progressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { _, _ in }
|
progressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { _, _ in }
|
||||||
) throws {
|
) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
let remote = try GTRemote(name: "origin", in: storeRepository)
|
let remote = try GTRemote(name: "origin", in: storeRepository)
|
||||||
try storeRepository.pull(storeRepository.currentBranch(), from: remote, withOptions: options, progress: progressBlock)
|
try storeRepository.pull(storeRepository.currentBranch(), from: remote, withOptions: options, progress: progressBlock)
|
||||||
|
|
@ -245,7 +244,7 @@ public class PasswordStore {
|
||||||
private func updatePasswordEntityCoreData() {
|
private func updatePasswordEntityCoreData() {
|
||||||
deleteCoreData(entityName: "PasswordEntity")
|
deleteCoreData(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
var q = try fm.contentsOfDirectory(atPath: storeURL.path)
|
var entities = try fileManager.contentsOfDirectory(atPath: storeURL.path)
|
||||||
.filter { !$0.hasPrefix(".") }
|
.filter { !$0.hasPrefix(".") }
|
||||||
.map { filename -> PasswordEntity in
|
.map { filename -> PasswordEntity in
|
||||||
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
|
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
|
||||||
|
|
@ -258,18 +257,18 @@ public class PasswordStore {
|
||||||
passwordEntity.parent = nil
|
passwordEntity.parent = nil
|
||||||
return passwordEntity
|
return passwordEntity
|
||||||
}
|
}
|
||||||
while !q.isEmpty {
|
while !entities.isEmpty {
|
||||||
let e = q.first!
|
let entity = entities.first!
|
||||||
q.remove(at: 0)
|
entities.remove(at: 0)
|
||||||
guard !e.name!.hasPrefix(".") else {
|
guard !entity.name!.hasPrefix(".") else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var isDirectory: ObjCBool = false
|
var isDirectory: ObjCBool = false
|
||||||
let filePath = storeURL.appendingPathComponent(e.path!).path
|
let filePath = storeURL.appendingPathComponent(entity.path!).path
|
||||||
if fm.fileExists(atPath: filePath, isDirectory: &isDirectory) {
|
if fileManager.fileExists(atPath: filePath, isDirectory: &isDirectory) {
|
||||||
if isDirectory.boolValue {
|
if isDirectory.boolValue {
|
||||||
e.isDir = true
|
entity.isDir = true
|
||||||
let files = try fm.contentsOfDirectory(atPath: filePath)
|
let files = try fileManager.contentsOfDirectory(atPath: filePath)
|
||||||
.filter { !$0.hasPrefix(".") }
|
.filter { !$0.hasPrefix(".") }
|
||||||
.map { filename -> PasswordEntity in
|
.map { filename -> PasswordEntity in
|
||||||
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
|
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
|
||||||
|
|
@ -278,13 +277,13 @@ public class PasswordStore {
|
||||||
} else {
|
} else {
|
||||||
passwordEntity.name = filename
|
passwordEntity.name = filename
|
||||||
}
|
}
|
||||||
passwordEntity.path = "\(e.path!)/\(filename)"
|
passwordEntity.path = "\(entity.path!)/\(filename)"
|
||||||
passwordEntity.parent = e
|
passwordEntity.parent = entity
|
||||||
return passwordEntity
|
return passwordEntity
|
||||||
}
|
}
|
||||||
q += files
|
entities += files
|
||||||
} else {
|
} else {
|
||||||
e.isDir = false
|
entity.isDir = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -377,7 +376,7 @@ public class PasswordStore {
|
||||||
|
|
||||||
private func gitAdd(path: String) throws {
|
private func gitAdd(path: String) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
try storeRepository.index().addFile(path)
|
try storeRepository.index().addFile(path)
|
||||||
try storeRepository.index().write()
|
try storeRepository.index().write()
|
||||||
|
|
@ -385,11 +384,11 @@ public class PasswordStore {
|
||||||
|
|
||||||
private func gitRm(path: String) throws {
|
private func gitRm(path: String) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
let url = storeURL.appendingPathComponent(path)
|
let url = storeURL.appendingPathComponent(path)
|
||||||
if fm.fileExists(atPath: url.path) {
|
if fileManager.fileExists(atPath: url.path) {
|
||||||
try fm.removeItem(at: url)
|
try fileManager.removeItem(at: url)
|
||||||
}
|
}
|
||||||
try storeRepository.index().removeFile(path)
|
try storeRepository.index().removeFile(path)
|
||||||
try storeRepository.index().write()
|
try storeRepository.index().write()
|
||||||
|
|
@ -397,30 +396,30 @@ public class PasswordStore {
|
||||||
|
|
||||||
private func deleteDirectoryTree(at url: URL) throws {
|
private func deleteDirectoryTree(at url: URL) throws {
|
||||||
var tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
|
var tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
|
||||||
var count = try fm.contentsOfDirectory(atPath: tempURL.path).count
|
var count = try fileManager.contentsOfDirectory(atPath: tempURL.path).count
|
||||||
while count == 0 {
|
while count == 0 {
|
||||||
try fm.removeItem(at: tempURL)
|
try fileManager.removeItem(at: tempURL)
|
||||||
tempURL.deleteLastPathComponent()
|
tempURL.deleteLastPathComponent()
|
||||||
count = try fm.contentsOfDirectory(atPath: tempURL.path).count
|
count = try fileManager.contentsOfDirectory(atPath: tempURL.path).count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createDirectoryTree(at url: URL) throws {
|
private func createDirectoryTree(at url: URL) throws {
|
||||||
let tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
|
let tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
|
||||||
try fm.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil)
|
try fileManager.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func gitMv(from: String, to: String) throws {
|
private func gitMv(from: String, to: String) throws {
|
||||||
let fromURL = storeURL.appendingPathComponent(from)
|
let fromURL = storeURL.appendingPathComponent(from)
|
||||||
let toURL = storeURL.appendingPathComponent(to)
|
let toURL = storeURL.appendingPathComponent(to)
|
||||||
try fm.moveItem(at: fromURL, to: toURL)
|
try fileManager.moveItem(at: fromURL, to: toURL)
|
||||||
try gitAdd(path: to)
|
try gitAdd(path: to)
|
||||||
try gitRm(path: from)
|
try gitRm(path: from)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func gitCommit(message: String) throws -> GTCommit? {
|
private func gitCommit(message: String) throws -> GTCommit? {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
let newTree = try storeRepository.index().writeTree()
|
let newTree = try storeRepository.index().writeTree()
|
||||||
let headReference = try storeRepository.headReference()
|
let headReference = try storeRepository.headReference()
|
||||||
|
|
@ -428,7 +427,7 @@ public class PasswordStore {
|
||||||
try commitEnum.pushSHA(headReference.targetOID!.sha)
|
try commitEnum.pushSHA(headReference.targetOID!.sha)
|
||||||
let parent = commitEnum.nextObject() as! GTCommit
|
let parent = commitEnum.nextObject() as! GTCommit
|
||||||
guard let signature = gitSignatureForNow else {
|
guard let signature = gitSignatureForNow else {
|
||||||
throw AppError.GitCreateSignature
|
throw AppError.gitCreateSignature
|
||||||
}
|
}
|
||||||
let commit = try storeRepository.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
|
let commit = try storeRepository.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
|
||||||
return commit
|
return commit
|
||||||
|
|
@ -436,7 +435,7 @@ public class PasswordStore {
|
||||||
|
|
||||||
private func getLocalBranch(withName branchName: String) throws -> GTBranch? {
|
private func getLocalBranch(withName branchName: String) throws -> GTBranch? {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
let reference = GTBranch.localNamePrefix().appending(branchName)
|
let reference = GTBranch.localNamePrefix().appending(branchName)
|
||||||
let branches = try storeRepository.branches(withPrefix: reference)
|
let branches = try storeRepository.branches(withPrefix: reference)
|
||||||
|
|
@ -448,20 +447,20 @@ public class PasswordStore {
|
||||||
transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer<ObjCBool>) -> Void = { _, _, _, _ in }
|
transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer<ObjCBool>) -> Void = { _, _, _, _ in }
|
||||||
) throws {
|
) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
if let branch = try getLocalBranch(withName: Defaults.gitBranchName) {
|
if let branch = try getLocalBranch(withName: Defaults.gitBranchName) {
|
||||||
let remote = try GTRemote(name: "origin", in: storeRepository)
|
let remote = try GTRemote(name: "origin", in: storeRepository)
|
||||||
try storeRepository.push(branch, to: remote, withOptions: options, progress: transferProgressBlock)
|
try storeRepository.push(branch, to: remote, withOptions: options, progress: transferProgressBlock)
|
||||||
}
|
}
|
||||||
if numberOfLocalCommits != 0 {
|
if numberOfLocalCommits != 0 {
|
||||||
throw AppError.GitPushNotSuccessful
|
throw AppError.gitPushNotSuccessful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addPasswordEntities(password: Password) throws -> PasswordEntity? {
|
private func addPasswordEntities(password: Password) throws -> PasswordEntity? {
|
||||||
guard !passwordExisted(password: password) else {
|
guard !passwordExisted(password: password) else {
|
||||||
throw AppError.PasswordDuplicated
|
throw AppError.passwordDuplicated
|
||||||
}
|
}
|
||||||
|
|
||||||
var passwordURL = password.url
|
var passwordURL = password.url
|
||||||
|
|
@ -472,7 +471,7 @@ public class PasswordStore {
|
||||||
passwordURL = passwordURL.deletingLastPathComponent()
|
passwordURL = passwordURL.deletingLastPathComponent()
|
||||||
// better identify errors before saving a new password
|
// better identify errors before saving a new password
|
||||||
if passwordURL.path != ".", passwordURL.path.count >= previousPathLength {
|
if passwordURL.path != ".", passwordURL.path.count >= previousPathLength {
|
||||||
throw AppError.WrongPasswordFilename
|
throw AppError.wrongPasswordFilename
|
||||||
}
|
}
|
||||||
previousPathLength = passwordURL.path.count
|
previousPathLength = passwordURL.path.count
|
||||||
}
|
}
|
||||||
|
|
@ -610,8 +609,8 @@ public class PasswordStore {
|
||||||
|
|
||||||
public func erase() {
|
public func erase() {
|
||||||
// Delete files.
|
// Delete files.
|
||||||
try? fm.removeItem(at: storeURL)
|
try? fileManager.removeItem(at: storeURL)
|
||||||
try? fm.removeItem(at: tempStoreURL)
|
try? fileManager.removeItem(at: tempStoreURL)
|
||||||
|
|
||||||
// Delete PGP key, SSH key and other secrets from the keychain.
|
// Delete PGP key, SSH key and other secrets from the keychain.
|
||||||
AppKeychain.shared.removeAllContent()
|
AppKeychain.shared.removeAllContent()
|
||||||
|
|
@ -637,7 +636,7 @@ public class PasswordStore {
|
||||||
// return the number of discarded commits
|
// return the number of discarded commits
|
||||||
public func reset() throws -> Int {
|
public func reset() throws -> Int {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
// get a list of local commits
|
// get a list of local commits
|
||||||
let localCommits = try getLocalCommits()
|
let localCommits = try getLocalCommits()
|
||||||
|
|
@ -648,7 +647,7 @@ public class PasswordStore {
|
||||||
guard let firstLocalCommit = localCommits.last,
|
guard let firstLocalCommit = localCommits.last,
|
||||||
firstLocalCommit.parents.count == 1,
|
firstLocalCommit.parents.count == 1,
|
||||||
let newHead = firstLocalCommit.parents.first else {
|
let newHead = firstLocalCommit.parents.first else {
|
||||||
throw AppError.GitReset
|
throw AppError.gitReset
|
||||||
}
|
}
|
||||||
try storeRepository.reset(to: newHead, resetType: .hard)
|
try storeRepository.reset(to: newHead, resetType: .hard)
|
||||||
setAllSynced()
|
setAllSynced()
|
||||||
|
|
@ -661,16 +660,16 @@ public class PasswordStore {
|
||||||
|
|
||||||
private func getLocalCommits() throws -> [GTCommit] {
|
private func getLocalCommits() throws -> [GTCommit] {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSet
|
throw AppError.repositoryNotSet
|
||||||
}
|
}
|
||||||
// get the remote branch
|
// get the remote branch
|
||||||
let remoteBranchName = Defaults.gitBranchName
|
let remoteBranchName = Defaults.gitBranchName
|
||||||
guard let remoteBranch = try storeRepository.remoteBranches().first(where: { $0.shortName == remoteBranchName }) else {
|
guard let remoteBranch = try storeRepository.remoteBranches().first(where: { $0.shortName == remoteBranchName }) else {
|
||||||
throw AppError.RepositoryRemoteBranchNotFound(remoteBranchName)
|
throw AppError.repositoryRemoteBranchNotFound(branchName: remoteBranchName)
|
||||||
}
|
}
|
||||||
// check oid before calling localCommitsRelative
|
// check oid before calling localCommitsRelative
|
||||||
guard remoteBranch.oid != nil else {
|
guard remoteBranch.oid != nil else {
|
||||||
throw AppError.RepositoryRemoteBranchNotFound(remoteBranchName)
|
throw AppError.repositoryRemoteBranchNotFound(branchName: remoteBranchName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a list of local commits
|
// get a list of local commits
|
||||||
|
|
@ -682,7 +681,7 @@ public class PasswordStore {
|
||||||
let keyID = keyID ?? findGPGID(from: encryptedDataPath)
|
let keyID = keyID ?? findGPGID(from: encryptedDataPath)
|
||||||
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
||||||
guard let decryptedData = try PGPAgent.shared.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase) else {
|
guard let decryptedData = try PGPAgent.shared.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase) else {
|
||||||
throw AppError.Decryption
|
throw AppError.decryption
|
||||||
}
|
}
|
||||||
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
|
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
|
||||||
let url = try passwordEntity.getURL()
|
let url = try passwordEntity.getURL()
|
||||||
|
|
@ -696,7 +695,7 @@ public class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeGitSSHKeys() {
|
public func removeGitSSHKeys() {
|
||||||
try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath)
|
try? fileManager.removeItem(atPath: Globals.gitSSHPrivateKeyPath)
|
||||||
Defaults.remove(\.gitSSHKeySource)
|
Defaults.remove(\.gitSSHKeySource)
|
||||||
Defaults.remove(\.gitSSHPrivateKeyArmor)
|
Defaults.remove(\.gitSSHPrivateKeyArmor)
|
||||||
Defaults.remove(\.gitSSHPrivateKeyURL)
|
Defaults.remove(\.gitSSHPrivateKeyURL)
|
||||||
|
|
|
||||||
|
|
@ -25,41 +25,41 @@ class Parser {
|
||||||
private func getAdditionFields() -> [AdditionField] {
|
private func getAdditionFields() -> [AdditionField] {
|
||||||
var additions: [AdditionField] = []
|
var additions: [AdditionField] = []
|
||||||
var unknownIndex: UInt = 0
|
var unknownIndex: UInt = 0
|
||||||
var i = purgedAdditionalLines.startIndex
|
var lineNumber = purgedAdditionalLines.startIndex
|
||||||
while i < purgedAdditionalLines.count {
|
while lineNumber < purgedAdditionalLines.count {
|
||||||
let line = purgedAdditionalLines[i]
|
let line = purgedAdditionalLines[lineNumber]
|
||||||
i += 1
|
lineNumber += 1
|
||||||
var (key, value) = Parser.getKeyValuePair(from: line)
|
var (key, value) = Parser.getKeyValuePair(from: line)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
unknownIndex += 1
|
unknownIndex += 1
|
||||||
key = Constants.unknown(unknownIndex)
|
key = Constants.unknown(unknownIndex)
|
||||||
} else if value == Constants.MULTILINE_WITH_LINE_BREAK_INDICATOR {
|
} else if value == Constants.MULTILINE_WITH_LINE_BREAK_INDICATOR {
|
||||||
value = gatherMultilineValue(startingAt: &i, removingLineBreaks: false)
|
value = gatherMultilineValue(startingAt: &lineNumber, removingLineBreaks: false)
|
||||||
} else if value == Constants.MULTILINE_WITHOUT_LINE_BREAK_INDICATOR {
|
} else if value == Constants.MULTILINE_WITHOUT_LINE_BREAK_INDICATOR {
|
||||||
value = gatherMultilineValue(startingAt: &i, removingLineBreaks: true)
|
value = gatherMultilineValue(startingAt: &lineNumber, removingLineBreaks: true)
|
||||||
}
|
}
|
||||||
additions.append(key! => value)
|
additions.append(key! => value)
|
||||||
}
|
}
|
||||||
return additions
|
return additions
|
||||||
}
|
}
|
||||||
|
|
||||||
private func gatherMultilineValue(startingAt i: inout Int, removingLineBreaks: Bool) -> String {
|
private func gatherMultilineValue(startingAt lineNumber: inout Int, removingLineBreaks: Bool) -> String {
|
||||||
var result = ""
|
var result = ""
|
||||||
guard i < purgedAdditionalLines.count else {
|
guard lineNumber < purgedAdditionalLines.count else {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
let numberInitialBlanks = purgedAdditionalLines[i].enumerated().first {
|
let numberInitialBlanks = purgedAdditionalLines[lineNumber].enumerated().first {
|
||||||
$1 != Character(Constants.BLANK)
|
$1 != Character(Constants.BLANK)
|
||||||
}?.0 ?? purgedAdditionalLines[i].count
|
}?.0 ?? purgedAdditionalLines[lineNumber].count
|
||||||
guard numberInitialBlanks != 0 else {
|
guard numberInitialBlanks != 0 else {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
let initialBlanks = String(repeating: Constants.BLANK, count: numberInitialBlanks)
|
let initialBlanks = String(repeating: Constants.BLANK, count: numberInitialBlanks)
|
||||||
|
|
||||||
while i < purgedAdditionalLines.count, purgedAdditionalLines[i].starts(with: initialBlanks) {
|
while lineNumber < purgedAdditionalLines.count, purgedAdditionalLines[lineNumber].starts(with: initialBlanks) {
|
||||||
result.append(String(purgedAdditionalLines[i].dropFirst(numberInitialBlanks)))
|
result.append(String(purgedAdditionalLines[lineNumber].dropFirst(numberInitialBlanks)))
|
||||||
result.append(Constants.getSeparator(breakingLines: !removingLineBreaks))
|
result.append(Constants.getSeparator(breakingLines: !removingLineBreaks))
|
||||||
i += 1
|
lineNumber += 1
|
||||||
}
|
}
|
||||||
return result.trimmed
|
return result.trimmed
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,10 @@ class PGPAgentTest: XCTestCase {
|
||||||
try KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048.publicKey)
|
try KeyFileManager(keyType: PgpKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048.publicKey)
|
||||||
XCTAssertFalse(pgpAgent.isPrepared)
|
XCTAssertFalse(pgpAgent.isPrepared)
|
||||||
XCTAssertThrowsError(try pgpAgent.initKeys()) {
|
XCTAssertThrowsError(try pgpAgent.initKeys()) {
|
||||||
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
|
XCTAssertEqual($0 as! AppError, AppError.keyImport)
|
||||||
}
|
}
|
||||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
|
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint)) {
|
||||||
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
|
XCTAssertEqual($0 as! AppError, AppError.keyImport)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ class PGPAgentTest: XCTestCase {
|
||||||
try importKeys(ED25519.publicKey, RSA2048.privateKey)
|
try importKeys(ED25519.publicKey, RSA2048.privateKey)
|
||||||
XCTAssert(pgpAgent.isPrepared)
|
XCTAssert(pgpAgent.isPrepared)
|
||||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint, encryptKeyID: RSA2048.fingerprint)) {
|
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint, encryptKeyID: RSA2048.fingerprint)) {
|
||||||
XCTAssertEqual($0 as! AppError, AppError.KeyExpiredOrIncompatible)
|
XCTAssertEqual($0 as! AppError, AppError.keyExpiredOrIncompatible)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ class PGPAgentTest: XCTestCase {
|
||||||
keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||||
keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint)) {
|
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: ED25519.fingerprint)) {
|
||||||
XCTAssertEqual($0 as! AppError, AppError.KeyImport)
|
XCTAssertEqual($0 as! AppError, AppError.keyImport)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ class PGPAgentTest: XCTestCase {
|
||||||
|
|
||||||
// Provide the wrong passphrase.
|
// Provide the wrong passphrase.
|
||||||
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideIncorrectPassphrase)) {
|
XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideIncorrectPassphrase)) {
|
||||||
XCTAssertEqual($0 as! AppError, AppError.WrongPassphrase)
|
XCTAssertEqual($0 as! AppError, AppError.wrongPassphrase)
|
||||||
}
|
}
|
||||||
XCTAssertEqual(passphraseRequestCalledCount, 2)
|
XCTAssertEqual(passphraseRequestCalledCount, 2)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class KeyFileManagerTest: XCTestCase {
|
||||||
|
|
||||||
func testImportKeyFromNonAsciiString() throws {
|
func testImportKeyFromNonAsciiString() throws {
|
||||||
XCTAssertThrowsError(try KeyFileManagerTest.keyFileManager.importKey(from: "≠")) {
|
XCTAssertThrowsError(try KeyFileManagerTest.keyFileManager.importKey(from: "≠")) {
|
||||||
XCTAssertEqual($0 as! AppError, AppError.Encoding)
|
XCTAssertEqual($0 as! AppError, AppError.encoding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,11 @@ func assertDefaults(
|
||||||
}
|
}
|
||||||
|
|
||||||
infix operator ∈: AdditionPrecedence
|
infix operator ∈: AdditionPrecedence
|
||||||
func ∈ (field: AdditionField, password: Password) -> Bool {
|
func ∈ (field: AdditionField, password: Password) -> Bool { // swiftlint:disable:this identifier_name
|
||||||
password.getFilteredAdditions().contains(field)
|
password.getFilteredAdditions().contains(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix operator ∉: AdditionPrecedence
|
infix operator ∉: AdditionPrecedence
|
||||||
func ∉ (field: AdditionField, password: Password) -> Bool {
|
func ∉ (field: AdditionField, password: Password) -> Bool { // swiftlint:disable:this identifier_name
|
||||||
!(field ∈ password)
|
!(field ∈ password)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue