Format code with SwiftFormat automatically in every build

This commit is contained in:
Danny Moesch 2020-06-28 21:25:40 +02:00 committed by Mingshen Sun
parent f167ab7549
commit 7f9f0e43b2
100 changed files with 1124 additions and 1063 deletions

View file

@ -25,7 +25,7 @@ public struct GitCredential {
public func credentialProvider(requestCredentialPassword: @escaping (Credential, String?) -> String?) throws -> GTCredentialProvider {
var attempts = 0
return GTCredentialProvider { (_, _, _) -> (GTCredential?) in
var credential: GTCredential? = nil
var credential: GTCredential?
switch self.credential {
case let .http(userName):
@ -52,7 +52,7 @@ public struct GitCredential {
return nil
}
var lastPassword = self.passwordStore.gitSSHPrivateKeyPassphrase
if lastPassword == nil || attempts != 0 {
if lastPassword == nil || attempts != 0 {
if let requestedPassword = requestCredentialPassword(self.credential, lastPassword) {
if Defaults.isRememberGitCredentialPassphraseOn {
self.passwordStore.gitSSHPrivateKeyPassphrase = requestedPassword
@ -72,10 +72,9 @@ public struct GitCredential {
public func delete() {
switch credential {
case .http:
self.passwordStore.gitPassword = nil
passwordStore.gitPassword = nil
case .ssh:
self.passwordStore.gitSSHPrivateKeyPassphrase = nil
passwordStore.gitSSHPrivateKeyPassphrase = nil
}
}
}

View file

@ -23,7 +23,7 @@ public class PasscodeLock {
}
public var hasPasscode: Bool {
return passcode != nil
passcode != nil
}
public func save(passcode: String) {
@ -32,7 +32,7 @@ public class PasscodeLock {
}
public func check(passcode: String) -> Bool {
return self.passcode == passcode
self.passcode == passcode
}
public func delete() {

View file

@ -6,11 +6,10 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import OneTimePassword
import Base32
import OneTimePassword
public class Password {
public var name: String
public var url: URL
public var plainText: String
@ -29,47 +28,47 @@ public class Password {
}
public var namePath: String {
return url.deletingPathExtension().path
url.deletingPathExtension().path
}
public var nameFromPath: String? {
return url.deletingPathExtension().path.split(separator: "/").last.map { String($0) }
url.deletingPathExtension().path.split(separator: "/").last.map { String($0) }
}
public var password: String {
return parser.firstLine
parser.firstLine
}
public var plainData: Data {
return plainText.data(using: .utf8)!
plainText.data(using: .utf8)!
}
public var additionsPlainText: String {
return parser.additionsSection
parser.additionsSection
}
public var username: String? {
return getAdditionValue(withKey: Constants.USERNAME_KEYWORD)
getAdditionValue(withKey: Constants.USERNAME_KEYWORD)
}
public var login: String? {
return getAdditionValue(withKey: Constants.LOGIN_KEYWORD)
getAdditionValue(withKey: Constants.LOGIN_KEYWORD)
}
public var urlString: String? {
return getAdditionValue(withKey: Constants.URL_KEYWORD)
getAdditionValue(withKey: Constants.URL_KEYWORD)
}
public var currentOtp: String? {
return otpToken?.currentPassword
otpToken?.currentPassword
}
public var numberOfUnknowns: Int {
return additions.map { $0.title }.filter(Constants.isUnknown).count
additions.map(\.title).filter(Constants.isUnknown).count
}
public var numberOfOtpRelated: Int {
return additions.map { $0.title }.filter(Constants.isOtpKeyword).count - (firstLineIsOTPField ? 1 : 0)
additions.map(\.title).filter(Constants.isOtpKeyword).count - (firstLineIsOTPField ? 1 : 0)
}
public init(name: String, url: URL, plainText: String) {
@ -119,7 +118,7 @@ public class Password {
}
public func getFilteredAdditions() -> [AdditionField] {
return additions.filter { field in
additions.filter { field in
let title = field.title.lowercased()
return title != Constants.USERNAME_KEYWORD
&& title != Constants.LOGIN_KEYWORD
@ -194,12 +193,12 @@ public class Password {
newOtpauth?.append("&secret=")
newOtpauth?.append(MF_Base32Codec.base32String(from: otpToken?.generator.secret))
var lines : [String] = []
self.plainText.enumerateLines() { line, _ in
var lines: [String] = []
plainText.enumerateLines { line, _ in
let (key, _) = Parser.getKeyValuePair(from: line)
if !Constants.OTP_KEYWORDS.contains(key ?? "") {
lines.append(line)
} else if key == Constants.OTPAUTH && newOtpauth != nil {
} else if key == Constants.OTPAUTH, newOtpauth != nil {
lines.append(newOtpauth!)
// set to nil to prevent duplication
newOtpauth = nil
@ -208,10 +207,10 @@ public class Password {
if newOtpauth != nil {
lines.append(newOtpauth!)
}
self.updatePassword(name: self.name, url: self.url, plainText: lines.joined(separator: "\n"))
updatePassword(name: name, url: url, plainText: lines.joined(separator: "\n"))
// get and return the password
return self.otpToken?.currentPassword
return otpToken?.currentPassword
}
public func getUsernameForCompletion() -> String {

View file

@ -10,7 +10,6 @@ import Foundation
import SwiftyUserDefaults
extension PasswordEntity {
public var nameWithCategory: String {
if let p = path, p.hasSuffix(".gpg") {
return String(p.prefix(upTo: p.index(p.endIndex, offsetBy: -4)))
@ -19,7 +18,7 @@ extension PasswordEntity {
}
public func getCategoryText() -> String {
return getCategoryArray().joined(separator: " > ")
getCategoryArray().joined(separator: " > ")
}
public func getCategoryArray() -> [String] {
@ -44,17 +43,16 @@ extension PasswordEntity {
// manually write models instead auto generation.
public func getImage() -> Data? {
return image
image
}
public func getName() -> String {
// unwrap non-optional core data
return name ?? ""
name ?? ""
}
public func getPath() -> String {
// unwrap non-optional core data
return path ?? ""
path ?? ""
}
}

View file

@ -6,12 +6,12 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import Foundation
import CoreData
import UIKit
import SwiftyUserDefaults
import ObjectiveGit
import Foundation
import KeychainAccess
import ObjectiveGit
import SwiftyUserDefaults
import UIKit
public class PasswordStore {
public static let shared = PasswordStore()
@ -21,43 +21,40 @@ public class PasswordStore {
dateFormatter.timeStyle = .short
return dateFormatter
}()
public var storeURL: URL
public var tempStoreURL: URL {
get {
URL(fileURLWithPath: "\(storeURL.path)-temp")
}
URL(fileURLWithPath: "\(storeURL.path)-temp")
}
public var storeRepository: GTRepository?
public var gitSignatureForNow: GTSignature? {
get {
let gitSignatureName = Defaults.gitSignatureName ?? Globals.gitSignatureDefaultName
let gitSignatureEmail = Defaults.gitSignatureEmail ?? Globals.gitSignatureDefaultEmail
return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())
}
let gitSignatureName = Defaults.gitSignatureName ?? Globals.gitSignatureDefaultName
let gitSignatureEmail = Defaults.gitSignatureEmail ?? Globals.gitSignatureDefaultEmail
return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())
}
public var gitPassword: String? {
set {
AppKeychain.shared.add(string: newValue, for: Globals.gitPassword)
}
get {
return AppKeychain.shared.get(for: Globals.gitPassword)
AppKeychain.shared.get(for: Globals.gitPassword)
}
}
public var gitSSHPrivateKeyPassphrase: String? {
set {
AppKeychain.shared.add(string: newValue, for: Globals.gitSSHPrivateKeyPassphrase)
}
get {
return AppKeychain.shared.get(for: Globals.gitSSHPrivateKeyPassphrase)
AppKeychain.shared.get(for: Globals.gitSSHPrivateKeyPassphrase)
}
}
private let fm = FileManager.default
lazy private var context: NSManagedObjectContext = {
private lazy var context: NSManagedObjectContext = {
let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")!
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
let container = NSPersistentContainer(name: "pass", managedObjectModel: managedObjectModel!)
@ -65,11 +62,11 @@ public class PasswordStore {
try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil)
}
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
container.loadPersistentStores(completionHandler: { _, error in
if let error = error as NSError? {
// 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.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
@ -83,36 +80,36 @@ public class PasswordStore {
})
return container.viewContext
}()
public var numberOfPasswords : Int {
return self.fetchPasswordEntityCoreData(withDir: false).count
public var numberOfPasswords: Int {
fetchPasswordEntityCoreData(withDir: false).count
}
public var sizeOfRepositoryByteCount : UInt64 {
return (try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: self.storeURL)) ?? 0
public var sizeOfRepositoryByteCount: UInt64 {
(try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: storeURL)) ?? 0
}
public var numberOfLocalCommits: Int {
return (try? getLocalCommits())?.flatMap { $0.count } ?? 0
(try? getLocalCommits()).map(\.count) ?? 0
}
public var lastSyncedTime: Date? {
return Defaults.lastSyncedTime
Defaults.lastSyncedTime
}
public var numberOfCommits: UInt? {
return storeRepository?.numberOfCommits(inCurrentBranch: nil)
storeRepository?.numberOfCommits(inCurrentBranch: nil)
}
init(url: URL = URL(fileURLWithPath: "\(Globals.repositoryPath)")) {
storeURL = url
self.storeURL = url
// Migration
importExistingKeysIntoKeychain()
do {
if fm.fileExists(atPath: storeURL.path) {
try storeRepository = GTRepository.init(url: storeURL)
try self.storeRepository = GTRepository(url: storeURL)
}
} catch {
print(error)
@ -128,12 +125,12 @@ public class PasswordStore {
Defaults.remove(\.pgpPrivateKeyArmor)
Defaults.remove(\.gitSSHPrivateKeyArmor)
}
public func repositoryExists() -> Bool {
let fm = FileManager()
return fm.fileExists(atPath: Globals.repositoryPath)
}
public func passwordExisted(password: Password) -> Bool {
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
do {
@ -148,7 +145,7 @@ public class PasswordStore {
fatalError("FailedToFetchPasswordEntities".localize(error))
}
}
public func passwordEntityExisted(path: String) -> Bool {
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
do {
@ -163,7 +160,7 @@ public class PasswordStore {
fatalError("FailedToFetchPasswordEntities".localize(error))
}
}
public func getPasswordEntity(by path: String, isDir: Bool) -> PasswordEntity? {
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
do {
@ -173,7 +170,7 @@ public class PasswordStore {
fatalError("FailedToFetchPasswordEntities".localize(error))
}
}
public func cloneRepository(remoteRepoURL: URL,
credential: GitCredential,
branchName: String,
@ -183,23 +180,23 @@ public class PasswordStore {
do {
let credentialProvider = try credential.credentialProvider(requestCredentialPassword: requestCredentialPassword)
let options = [GTRepositoryCloneOptionsCredentialProvider: credentialProvider]
try self.cloneRepository(remoteRepoURL: remoteRepoURL, options: options, branchName: branchName, transferProgressBlock: transferProgressBlock, checkoutProgressBlock: checkoutProgressBlock)
try cloneRepository(remoteRepoURL: remoteRepoURL, options: options, branchName: branchName, transferProgressBlock: transferProgressBlock, checkoutProgressBlock: checkoutProgressBlock)
} catch {
credential.delete()
throw(error)
throw (error)
}
}
public func cloneRepository(remoteRepoURL: URL,
options: [AnyHashable : Any]? = nil,
options: [AnyHashable: Any]? = nil,
branchName: String,
transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void,
checkoutProgressBlock: @escaping (String, UInt, UInt) -> Void,
completion: @escaping () -> Void = {}) throws {
try? fm.removeItem(at: storeURL)
try? fm.removeItem(at: tempStoreURL)
self.gitPassword = nil
self.gitSSHPrivateKeyPassphrase = nil
gitPassword = nil
gitSSHPrivateKeyPassphrase = nil
do {
storeRepository = try GTRepository.clone(from: remoteRepoURL,
toWorkingDirectory: tempStoreURL,
@ -216,7 +213,7 @@ public class PasswordStore {
self.deleteCoreData(entityName: "PasswordEntity")
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
}
throw(error)
throw (error)
}
Defaults.lastSyncedTime = Date()
DispatchQueue.main.async {
@ -225,7 +222,7 @@ public class PasswordStore {
completion()
}
}
private func checkoutAndChangeBranch(withName localBranchName: String, progressBlock: @escaping (String, UInt, UInt) -> Void) throws {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -241,7 +238,7 @@ public class PasswordStore {
try storeRepository.checkoutReference(localBranch.reference, options: checkoutOptions)
try storeRepository.moveHEAD(to: localBranch.reference)
}
public func pullRepository(credential: GitCredential,
requestCredentialPassword: @escaping (GitCredential.Credential, String?) -> String?,
progressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
@ -253,30 +250,30 @@ public class PasswordStore {
let remote = try GTRemote(name: "origin", in: storeRepository)
try storeRepository.pull(storeRepository.currentBranch(), from: remote, withOptions: options, progress: progressBlock)
Defaults.lastSyncedTime = Date()
self.setAllSynced()
setAllSynced()
DispatchQueue.main.async {
self.updatePasswordEntityCoreData()
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
}
}
private func updatePasswordEntityCoreData() {
deleteCoreData(entityName: "PasswordEntity")
do {
var q = try fm.contentsOfDirectory(atPath: self.storeURL.path).filter {
var q = try fm.contentsOfDirectory(atPath: storeURL.path).filter {
!$0.hasPrefix(".")
}.map { (filename) -> PasswordEntity in
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
if filename.hasSuffix(".gpg") {
passwordEntity.name = String(filename.prefix(upTo: filename.index(filename.endIndex, offsetBy: -4)))
} else {
passwordEntity.name = filename
}
passwordEntity.path = filename
passwordEntity.parent = nil
return passwordEntity
}.map { (filename) -> PasswordEntity in
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
if filename.hasSuffix(".gpg") {
passwordEntity.name = String(filename.prefix(upTo: filename.index(filename.endIndex, offsetBy: -4)))
} else {
passwordEntity.name = filename
}
passwordEntity.path = filename
passwordEntity.parent = nil
return passwordEntity
}
while q.count > 0 {
while !q.isEmpty {
let e = q.first!
q.remove(at: 0)
guard !e.name!.hasPrefix(".") else {
@ -309,9 +306,9 @@ public class PasswordStore {
} catch {
print(error)
}
self.saveUpdatedContext()
saveUpdatedContext()
}
public func getRecentCommits(count: Int) throws -> [GTCommit] {
guard let storeRepository = storeRepository else {
return []
@ -328,7 +325,7 @@ public class PasswordStore {
}
return commits
}
public func fetchPasswordEntityCoreData(parent: PasswordEntity?) -> [PasswordEntity] {
let passwordEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
do {
@ -339,7 +336,7 @@ public class PasswordStore {
fatalError("FailedToFetchPasswords".localize(error))
}
}
public func fetchPasswordEntityCoreData(withDir: Bool) -> [PasswordEntity] {
let passwordEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
do {
@ -352,8 +349,7 @@ public class PasswordStore {
fatalError("FailedToFetchPasswords".localize(error))
}
}
public func fetchUnsyncedPasswords() -> [PasswordEntity] {
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0)
@ -364,17 +360,17 @@ public class PasswordStore {
fatalError("FailedToFetchPasswords".localize(error))
}
}
public func setAllSynced() {
let passwordEntities = fetchUnsyncedPasswords()
if passwordEntities.count > 0 {
if !passwordEntities.isEmpty {
for passwordEntity in passwordEntities {
passwordEntity.synced = true
}
self.saveUpdatedContext()
saveUpdatedContext()
}
}
public func getLatestUpdateInfo(filename: String) -> String {
guard let storeRepository = storeRepository else {
return "Unknown".localize()
@ -383,7 +379,7 @@ public class PasswordStore {
let latestCommitTime = blameHunks.map({
$0.finalSignature?.time?.timeIntervalSince1970 ?? 0
}).max() else {
return "Unknown".localize()
return "Unknown".localize()
}
let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime)
if Date().timeIntervalSince(lastCommitDate) <= 60 {
@ -391,10 +387,9 @@ public class PasswordStore {
}
return PasswordStore.dateFormatter.string(from: lastCommitDate)
}
public func updateRemoteRepo() {
}
public func updateRemoteRepo() {}
private func gitAdd(path: String) throws {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -402,7 +397,7 @@ public class PasswordStore {
try storeRepository.index().addFile(path)
try storeRepository.index().write()
}
private func gitRm(path: String) throws {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -414,7 +409,7 @@ public class PasswordStore {
try storeRepository.index().removeFile(path)
try storeRepository.index().write()
}
private func deleteDirectoryTree(at url: URL) throws {
var tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
var count = try fm.contentsOfDirectory(atPath: tempURL.path).count
@ -424,12 +419,12 @@ public class PasswordStore {
count = try fm.contentsOfDirectory(atPath: tempURL.path).count
}
}
private func createDirectoryTree(at url: URL) throws {
let tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
try fm.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil)
}
private func gitMv(from: String, to: String) throws {
let fromURL = storeURL.appendingPathComponent(from)
let toURL = storeURL.appendingPathComponent(to)
@ -437,7 +432,7 @@ public class PasswordStore {
try gitAdd(path: to)
try gitRm(path: from)
}
private func gitCommit(message: String) throws -> GTCommit? {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -453,7 +448,7 @@ public class PasswordStore {
let commit = try storeRepository.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
return commit
}
private func getLocalBranch(withName branchName: String) throws -> GTBranch? {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -462,7 +457,7 @@ public class PasswordStore {
let branches = try storeRepository.branches(withPrefix: reference)
return branches.first
}
public func pushRepository(credential: GitCredential, requestCredentialPassword: @escaping (GitCredential.Credential, String?) -> String?, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -477,12 +472,12 @@ public class PasswordStore {
throw AppError.GitPushNotSuccessful
}
}
private func addPasswordEntities(password: Password) throws -> PasswordEntity? {
guard !passwordExisted(password: password) else {
throw AppError.PasswordDuplicated
}
var passwordURL = password.url
var previousPathLength = Int.max
var paths: [String] = []
@ -490,20 +485,20 @@ public class PasswordStore {
paths.append(passwordURL.path)
passwordURL = passwordURL.deletingLastPathComponent()
// 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
}
previousPathLength = passwordURL.path.count
}
paths.reverse()
var parentPasswordEntity: PasswordEntity? = nil
var parentPasswordEntity: PasswordEntity?
for path in paths {
let isDir = !path.hasSuffix(".gpg")
if let passwordEntity = getPasswordEntity(by: path, isDir: isDir) {
passwordEntity.synced = false
parentPasswordEntity = passwordEntity
} else {
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: self.context) as! PasswordEntity
let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity
let pathURL = URL(string: path.stringByAddingPercentEncodingForRFC3986()!)!
if isDir {
passwordEntity.name = pathURL.lastPathComponent
@ -518,72 +513,73 @@ public class PasswordStore {
}
}
self.saveUpdatedContext()
saveUpdatedContext()
return parentPasswordEntity
}
public func add(password: Password, keyID: String? = nil) throws -> PasswordEntity? {
try createDirectoryTree(at: password.url)
let saveURL = storeURL.appendingPathComponent(password.url.path)
try self.encrypt(password: password, keyID: keyID).write(to: saveURL)
try encrypt(password: password, keyID: keyID).write(to: saveURL)
try gitAdd(path: password.url.path)
let _ = try gitCommit(message: "AddPassword.".localize(password.url.deletingPathExtension().path))
_ = try gitCommit(message: "AddPassword.".localize(password.url.deletingPathExtension().path))
let newPasswordEntity = try addPasswordEntities(password: password)
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
return newPasswordEntity
}
public func delete(passwordEntity: PasswordEntity) throws {
let deletedFileURL = try passwordEntity.getURL()
try gitRm(path: deletedFileURL.path)
try deletePasswordEntities(passwordEntity: passwordEntity)
try deleteDirectoryTree(at: deletedFileURL)
let _ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!))
_ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!))
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
}
public func edit(passwordEntity: PasswordEntity, password: Password, keyID: String? = nil) throws -> PasswordEntity? {
var newPasswordEntity: PasswordEntity? = passwordEntity
let url = try passwordEntity.getURL()
if password.changed&PasswordChange.content.rawValue != 0 {
if password.changed & PasswordChange.content.rawValue != 0 {
let saveURL = storeURL.appendingPathComponent(url.path)
try self.encrypt(password: password, keyID: keyID).write(to: saveURL)
try encrypt(password: password, keyID: keyID).write(to: saveURL)
try gitAdd(path: url.path)
let _ = try gitCommit(message: "EditPassword.".localize(url.deletingPathExtension().path.removingPercentEncoding!))
_ = try gitCommit(message: "EditPassword.".localize(url.deletingPathExtension().path.removingPercentEncoding!))
newPasswordEntity = passwordEntity
newPasswordEntity?.synced = false
self.saveUpdatedContext()
saveUpdatedContext()
}
if password.changed&PasswordChange.path.rawValue != 0 {
if password.changed & PasswordChange.path.rawValue != 0 {
let deletedFileURL = url
// add
try createDirectoryTree(at: password.url)
newPasswordEntity = try addPasswordEntities(password: password)
// mv
try gitMv(from: deletedFileURL.path, to: password.url.path)
// delete
try deleteDirectoryTree(at: deletedFileURL)
try deletePasswordEntities(passwordEntity: passwordEntity)
let _ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!))
_ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!))
}
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
return newPasswordEntity
}
private func deletePasswordEntities(passwordEntity: PasswordEntity) throws {
var current: PasswordEntity? = passwordEntity
while current != nil && (current!.children!.count == 0 || !current!.isDir) {
// swiftformat:disable:next isEmpty
while current != nil, current!.children!.count == 0 || !current!.isDir {
let parent = current!.parent
self.context.delete(current!)
context.delete(current!)
current = parent
}
self.saveUpdatedContext()
saveUpdatedContext()
}
public func saveUpdatedContext() {
do {
if context.hasChanges {
@ -593,11 +589,11 @@ public class PasswordStore {
fatalError("FailureToSaveContext".localize(error))
}
}
public func deleteCoreData(entityName: String) {
let deleteFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest)
do {
try context.execute(deleteRequest)
try context.save()
@ -606,7 +602,7 @@ public class PasswordStore {
print(error)
}
}
public func updateImage(passwordEntity: PasswordEntity, image: Data?) {
guard let image = image else {
return
@ -625,33 +621,33 @@ public class PasswordStore {
}
}
}
public func erase() {
// Delete files.
try? fm.removeItem(at: storeURL)
try? fm.removeItem(at: tempStoreURL)
// Delete PGP key, SSH key and other secrets from the keychain.
AppKeychain.shared.removeAllContent()
// Delete core data.
deleteCoreData(entityName: "PasswordEntity")
// Delete default settings.
Defaults.removeAll()
// Clean up variables inside PasswordStore.
storeRepository = nil
// Delete cache explicitly.
PasscodeLock.shared.delete()
PGPAgent.shared.uninitKeys()
// Broadcast.
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.post(name: .passwordStoreErased, object: nil)
}
// return the number of discarded commits
public func reset() throws -> Int {
guard let storeRepository = storeRepository else {
@ -659,26 +655,25 @@ public class PasswordStore {
}
// get a list of local commits
if let localCommits = try getLocalCommits(),
localCommits.count > 0 {
!localCommits.isEmpty {
// get the oldest local commit
guard let firstLocalCommit = localCommits.last,
firstLocalCommit.parents.count == 1,
let newHead = firstLocalCommit.parents.first else {
throw AppError.GitReset
throw AppError.GitReset
}
try storeRepository.reset(to: newHead, resetType: .hard)
self.setAllSynced()
self.updatePasswordEntityCoreData()
setAllSynced()
updatePasswordEntityCoreData()
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil)
return localCommits.count
} else {
return 0 // no new commit
return 0 // no new commit
}
}
private func getLocalCommits() throws -> [GTCommit]? {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSet
@ -692,7 +687,7 @@ public class PasswordStore {
guard remoteBranch.oid != nil else {
throw AppError.RepositoryRemoteBranchNotFound(remoteBranchName)
}
// get a list of local commits
return try storeRepository.localCommitsRelative(toRemoteBranch: remoteBranch)
}
@ -708,13 +703,13 @@ public class PasswordStore {
let url = try passwordEntity.getURL()
return Password(name: passwordEntity.getName(), url: url, plainText: plainText)
}
public func encrypt(password: Password, keyID: String? = nil) throws -> Data {
let encryptedDataPath = storeURL.appendingPathComponent(password.url.path)
let keyID = keyID ?? findGPGID(from: encryptedDataPath)
return try PGPAgent.shared.encrypt(plainData: password.plainData, keyID: keyID)
}
public func removeGitSSHKeys() {
try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath)
Defaults.remove(\.gitSSHKeySource)
@ -727,8 +722,8 @@ public class PasswordStore {
public func findGPGID(from url: URL) -> String {
var path = url
while !FileManager.default.fileExists(atPath: path.appendingPathComponent(".gpg-id").path)
&& path.path != "file:///" {
while !FileManager.default.fileExists(atPath: path.appendingPathComponent(".gpg-id").path),
path.path != "file:///" {
path = path.deletingLastPathComponent()
}
path = path.appendingPathComponent(".gpg-id")

View file

@ -14,7 +14,7 @@ public class PasswordTableEntry: NSObject {
public let isDir: Bool
public let synced: Bool
public let categoryText: String
public init(_ entity: PasswordEntity) {
self.passwordEntity = entity
self.title = entity.name!
@ -22,23 +22,22 @@ public class PasswordTableEntry: NSObject {
self.synced = entity.synced
self.categoryText = entity.getCategoryText()
}
public func match(_ searchText: String) -> Bool {
return PasswordTableEntry.match(nameWithCategory: passwordEntity.nameWithCategory, searchText: searchText)
PasswordTableEntry.match(nameWithCategory: passwordEntity.nameWithCategory, searchText: searchText)
}
public static func match(nameWithCategory: String, searchText: String) -> Bool {
let titleSplit = nameWithCategory.split{ !($0.isLetter || $0.isNumber || $0 == ".") }
let titleSplit = nameWithCategory.split { !($0.isLetter || $0.isNumber || $0 == ".") }
for str in titleSplit {
if (str.localizedCaseInsensitiveContains(searchText)) {
if str.localizedCaseInsensitiveContains(searchText) {
return true
}
if (searchText.localizedCaseInsensitiveContains(str)) {
if searchText.localizedCaseInsensitiveContains(str) {
return true
}
}
return false
}
}