Move files and Defaults to the shared container
This commit is contained in:
parent
8f91c4c516
commit
850dc75820
5 changed files with 82 additions and 24 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
94BA784B85E071D25EE89B59 /* libPods-pass.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */; };
|
94BA784B85E071D25EE89B59 /* libPods-pass.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */; };
|
||||||
A217ACE21E9AB17C00A1A6CF /* OTPScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */; };
|
A217ACE21E9AB17C00A1A6CF /* OTPScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */; };
|
||||||
A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */; };
|
A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */; };
|
||||||
|
A26075721EEC6B8D005DB03E /* SwiftyUserDefaults.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA049951E3357E000522E8F /* SwiftyUserDefaults.framework */; };
|
||||||
A262A58D1E68749C006B0890 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; };
|
A262A58D1E68749C006B0890 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; };
|
||||||
A26700271EEC466A00176B8A /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A26700261EEC466A00176B8A /* ActionViewController.swift */; };
|
A26700271EEC466A00176B8A /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A26700261EEC466A00176B8A /* ActionViewController.swift */; };
|
||||||
A267002A1EEC466A00176B8A /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A26700281EEC466A00176B8A /* MainInterface.storyboard */; };
|
A267002A1EEC466A00176B8A /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A26700281EEC466A00176B8A /* MainInterface.storyboard */; };
|
||||||
|
|
@ -198,6 +199,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
A26075721EEC6B8D005DB03E /* SwiftyUserDefaults.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -738,6 +740,10 @@
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_ENTITLEMENTS = passextension/passextension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = passextension/passextension.entitlements;
|
||||||
DEVELOPMENT_TEAM = 4WDM8E95VU;
|
DEVELOPMENT_TEAM = 4WDM8E95VU;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
||||||
|
);
|
||||||
INFOPLIST_FILE = passextension/Info.plist;
|
INFOPLIST_FILE = passextension/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
|
|
@ -755,6 +761,10 @@
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_ENTITLEMENTS = passextension/passextension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = passextension/passextension.entitlements;
|
||||||
DEVELOPMENT_TEAM = 4WDM8E95VU;
|
DEVELOPMENT_TEAM = 4WDM8E95VU;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
||||||
|
);
|
||||||
INFOPLIST_FILE = passextension/Info.plist;
|
INFOPLIST_FILE = passextension/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
error conditions that could cause the creation of the store to fail.
|
error conditions that could cause the creation of the store to fail.
|
||||||
*/
|
*/
|
||||||
let container = NSPersistentContainer(name: "pass")
|
let container = NSPersistentContainer(name: "pass")
|
||||||
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
let description = NSPersistentStoreDescription(url: Globals.sharedContainerURL)
|
||||||
|
container.loadPersistentStores(completionHandler: { (description, 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.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftyUserDefaults
|
import SwiftyUserDefaults
|
||||||
|
|
||||||
|
var Defaults = UserDefaults(suiteName: Globals.groupIdentifier)!
|
||||||
|
|
||||||
extension DefaultsKeys {
|
extension DefaultsKeys {
|
||||||
static let pgpKeySource = DefaultsKey<String?>("pgpKeySource")
|
static let pgpKeySource = DefaultsKey<String?>("pgpKeySource")
|
||||||
static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL")
|
static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL")
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,26 @@ import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class Globals {
|
class Globals {
|
||||||
static let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
|
|
||||||
static let libraryPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0];
|
|
||||||
static let pgpPublicKeyPath = "\(documentPath)/gpg_key.pub"
|
|
||||||
static let pgpPrivateKeyPath = "\(documentPath)/gpg_key"
|
|
||||||
|
|
||||||
static let gitSSHPrivateKeyPath = "\(documentPath)/ssh_key"
|
|
||||||
static let gitSSHPrivateKeyURL = URL(fileURLWithPath: gitSSHPrivateKeyPath)
|
|
||||||
|
|
||||||
static let repositoryPath = "\(libraryPath)/password-store"
|
// Legacy paths (not shared)
|
||||||
|
static let documentPathLegacy = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
|
||||||
|
static let libraryPathLegacy = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0];
|
||||||
|
static let pgpPublicKeyPathLegacy = "\(documentPathLegacy)/gpg_key.pub"
|
||||||
|
static let pgpPrivateKeyPathLegacy = "\(documentPathLegacy)/gpg_key"
|
||||||
|
static let gitSSHPrivateKeyPathLegacy = "\(documentPathLegacy)/ssh_key"
|
||||||
|
static let gitSSHPrivateKeyURLLegacy = URL(fileURLWithPath: gitSSHPrivateKeyPathLegacy)
|
||||||
|
static let repositoryPathLegacy = "\(libraryPathLegacy)/password-store"
|
||||||
|
|
||||||
|
static let groupIdentifier = "group." + Bundle.main.bundleIdentifier!
|
||||||
|
static let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier)!
|
||||||
|
static let documentPath = sharedContainerURL.appendingPathComponent("Keys").path
|
||||||
|
static let libraryPath = sharedContainerURL.appendingPathComponent("Repository").path
|
||||||
|
static let pgpPublicKeyPath = documentPath + "/gpg_key.pub"
|
||||||
|
static let pgpPrivateKeyPath = documentPath + "/gpg_key"
|
||||||
|
static let gitSSHPrivateKeyPath = documentPath + "/ssh_key"
|
||||||
|
static let gitSSHPrivateKeyURL = URL(fileURLWithPath: gitSSHPrivateKeyPath)
|
||||||
|
static let repositoryPath = libraryPath + "/password-store"
|
||||||
|
|
||||||
static var passcodeConfiguration = PasscodeLockConfiguration()
|
static var passcodeConfiguration = PasscodeLockConfiguration()
|
||||||
|
|
||||||
static let passwordDefaultLength = ["Random": (min: 4, max: 64, def: 16),
|
static let passwordDefaultLength = ["Random": (min: 4, max: 64, def: 16),
|
||||||
|
|
|
||||||
|
|
@ -68,14 +68,40 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
|
let fm = FileManager.default
|
||||||
|
lazy var context: NSManagedObjectContext = {
|
||||||
|
/*
|
||||||
|
The persistent container for the application. This implementation
|
||||||
|
creates and returns a container, having loaded the store for the
|
||||||
|
application to it. This property is optional since there are legitimate
|
||||||
|
error conditions that could cause the creation of the store to fail.
|
||||||
|
*/
|
||||||
|
let container = NSPersistentContainer(name: "pass")
|
||||||
|
let description = NSPersistentStoreDescription(url: Globals.sharedContainerURL)
|
||||||
|
container.loadPersistentStores(completionHandler: { (description, 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.
|
||||||
|
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
|
||||||
|
* The device is out of space.
|
||||||
|
* The store could not be migrated to the current model version.
|
||||||
|
Check the error message to determine what the actual problem was.
|
||||||
|
*/
|
||||||
|
fatalError("Unresolved error \(error), \(error.userInfo)")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return container.viewContext
|
||||||
|
}()
|
||||||
|
|
||||||
var numberOfPasswords : Int {
|
var numberOfPasswords : Int {
|
||||||
return self.fetchPasswordEntityCoreData(withDir: false).count
|
return self.fetchPasswordEntityCoreData(withDir: false).count
|
||||||
}
|
}
|
||||||
|
|
||||||
var sizeOfRepositoryByteCount : UInt64 {
|
var sizeOfRepositoryByteCount : UInt64 {
|
||||||
let fm = FileManager.default
|
|
||||||
var size = UInt64(0)
|
var size = UInt64(0)
|
||||||
do {
|
do {
|
||||||
if fm.fileExists(atPath: self.storeURL.path) {
|
if fm.fileExists(atPath: self.storeURL.path) {
|
||||||
|
|
@ -89,8 +115,11 @@ class PasswordStore {
|
||||||
|
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
|
// File migration to group
|
||||||
|
migration()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if FileManager.default.fileExists(atPath: storeURL.path) {
|
if fm.fileExists(atPath: storeURL.path) {
|
||||||
try storeRepository = GTRepository.init(url: storeURL)
|
try storeRepository = GTRepository.init(url: storeURL)
|
||||||
}
|
}
|
||||||
try initPGPKeys()
|
try initPGPKeys()
|
||||||
|
|
@ -99,6 +128,20 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func migration() {
|
||||||
|
let needMigration = fm.fileExists(atPath: Globals.documentPathLegacy) && !fm.fileExists(atPath: Globals.documentPath) && fm.fileExists(atPath: Globals.libraryPathLegacy) && !fm.fileExists(atPath: Globals.libraryPath)
|
||||||
|
guard needMigration == true else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
try fm.copyItem(atPath: Globals.documentPathLegacy, toPath: Globals.documentPath)
|
||||||
|
try fm.copyItem(atPath: Globals.libraryPathLegacy, toPath: Globals.libraryPath)
|
||||||
|
} catch {
|
||||||
|
print("Cannot migrate: \(error)")
|
||||||
|
}
|
||||||
|
updatePasswordEntityCoreData()
|
||||||
|
}
|
||||||
|
|
||||||
enum SSHKeyType {
|
enum SSHKeyType {
|
||||||
case `public`, secret
|
case `public`, secret
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +203,6 @@ class PasswordStore {
|
||||||
|
|
||||||
|
|
||||||
private func importKey(from keyPath: String) -> PGPKey? {
|
private func importKey(from keyPath: String) -> PGPKey? {
|
||||||
let fm = FileManager.default
|
|
||||||
if fm.fileExists(atPath: keyPath) {
|
if fm.fileExists(atPath: keyPath) {
|
||||||
if let keys = pgp.importKeys(fromFile: keyPath, allowDuplicates: false) as? [PGPKey] {
|
if let keys = pgp.importKeys(fromFile: keyPath, allowDuplicates: false) as? [PGPKey] {
|
||||||
return keys.first
|
return keys.first
|
||||||
|
|
@ -230,7 +272,6 @@ class PasswordStore {
|
||||||
let credentialProvider = try credential.credentialProvider()
|
let credentialProvider = try credential.credentialProvider()
|
||||||
let options = [GTRepositoryCloneOptionsCredentialProvider: credentialProvider]
|
let options = [GTRepositoryCloneOptionsCredentialProvider: credentialProvider]
|
||||||
storeRepository = try GTRepository.clone(from: remoteRepoURL, toWorkingDirectory: tempStoreURL, options: options, transferProgressBlock:transferProgressBlock)
|
storeRepository = try GTRepository.clone(from: remoteRepoURL, toWorkingDirectory: tempStoreURL, options: options, transferProgressBlock:transferProgressBlock)
|
||||||
let fm = FileManager.default
|
|
||||||
if fm.fileExists(atPath: storeURL.path) {
|
if fm.fileExists(atPath: storeURL.path) {
|
||||||
try fm.removeItem(at: storeURL)
|
try fm.removeItem(at: storeURL)
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +312,6 @@ class PasswordStore {
|
||||||
|
|
||||||
private func updatePasswordEntityCoreData() {
|
private func updatePasswordEntityCoreData() {
|
||||||
deleteCoreData(entityName: "PasswordEntity")
|
deleteCoreData(entityName: "PasswordEntity")
|
||||||
let fm = FileManager.default
|
|
||||||
do {
|
do {
|
||||||
var q = try fm.contentsOfDirectory(atPath: self.storeURL.path).filter{
|
var q = try fm.contentsOfDirectory(atPath: self.storeURL.path).filter{
|
||||||
!$0.hasPrefix(".")
|
!$0.hasPrefix(".")
|
||||||
|
|
@ -443,8 +483,8 @@ class PasswordStore {
|
||||||
throw AppError.RepositoryNotSetError
|
throw AppError.RepositoryNotSetError
|
||||||
}
|
}
|
||||||
let url = storeURL.appendingPathComponent(path)
|
let url = storeURL.appendingPathComponent(path)
|
||||||
if FileManager.default.fileExists(atPath: url.path) {
|
if fm.fileExists(atPath: url.path) {
|
||||||
try FileManager.default.removeItem(at: url)
|
try fm.removeItem(at: url)
|
||||||
}
|
}
|
||||||
try storeRepository.index().removeFile(path)
|
try storeRepository.index().removeFile(path)
|
||||||
try storeRepository.index().write()
|
try storeRepository.index().write()
|
||||||
|
|
@ -452,7 +492,6 @@ 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)
|
||||||
let fm = FileManager.default
|
|
||||||
var count = try fm.contentsOfDirectory(atPath: tempURL.path).count
|
var count = try fm.contentsOfDirectory(atPath: tempURL.path).count
|
||||||
while count == 0 {
|
while count == 0 {
|
||||||
try fm.removeItem(at: tempURL)
|
try fm.removeItem(at: tempURL)
|
||||||
|
|
@ -463,13 +502,12 @@ class PasswordStore {
|
||||||
|
|
||||||
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 FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil)
|
try fm.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)
|
||||||
let fm = FileManager.default
|
|
||||||
guard fm.fileExists(atPath: fromURL.path) else {
|
guard fm.fileExists(atPath: fromURL.path) else {
|
||||||
print("\(from) not exist")
|
print("\(from) not exist")
|
||||||
return
|
return
|
||||||
|
|
@ -779,8 +817,6 @@ class PasswordStore {
|
||||||
return encryptedData
|
return encryptedData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func removePGPKeys() {
|
func removePGPKeys() {
|
||||||
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||||
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||||
|
|
@ -803,12 +839,10 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitSSHKeyExists() -> Bool {
|
func gitSSHKeyExists() -> Bool {
|
||||||
let fm = FileManager.default
|
|
||||||
return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
|
return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pgpKeyExists() -> Bool {
|
func pgpKeyExists() -> Bool {
|
||||||
let fm = FileManager.default
|
|
||||||
return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath)
|
return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue