Move files and Defaults to the shared container

This commit is contained in:
Yishi Lin 2017-06-11 02:09:45 +08:00
parent 8f91c4c516
commit 850dc75820
5 changed files with 82 additions and 24 deletions

View file

@ -10,6 +10,7 @@
94BA784B85E071D25EE89B59 /* libPods-pass.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADCE7A5C3CCC67D7D21BB3C4 /* libPods-pass.a */; };
A217ACE21E9AB17C00A1A6CF /* OTPScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217ACE11E9AB17C00A1A6CF /* OTPScannerController.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 */; };
A26700271EEC466A00176B8A /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A26700261EEC466A00176B8A /* ActionViewController.swift */; };
A267002A1EEC466A00176B8A /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A26700281EEC466A00176B8A /* MainInterface.storyboard */; };
@ -198,6 +199,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A26075721EEC6B8D005DB03E /* SwiftyUserDefaults.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -738,6 +740,10 @@
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = passextension/passextension.entitlements;
DEVELOPMENT_TEAM = 4WDM8E95VU;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = passextension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
@ -755,6 +761,10 @@
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = passextension/passextension.entitlements;
DEVELOPMENT_TEAM = 4WDM8E95VU;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = passextension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";

View file

@ -113,7 +113,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
error conditions that could cause the creation of the store to fail.
*/
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? {
// 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.

View file

@ -9,6 +9,8 @@
import Foundation
import SwiftyUserDefaults
var Defaults = UserDefaults(suiteName: Globals.groupIdentifier)!
extension DefaultsKeys {
static let pgpKeySource = DefaultsKey<String?>("pgpKeySource")
static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL")

View file

@ -10,15 +10,26 @@ import Foundation
import UIKit
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"
// 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 let repositoryPath = "\(libraryPath)/password-store"
static var passcodeConfiguration = PasscodeLockConfiguration()
static let passwordDefaultLength = ["Random": (min: 4, max: 64, def: 16),

View file

@ -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 {
return self.fetchPasswordEntityCoreData(withDir: false).count
}
var sizeOfRepositoryByteCount : UInt64 {
let fm = FileManager.default
var size = UInt64(0)
do {
if fm.fileExists(atPath: self.storeURL.path) {
@ -89,8 +115,11 @@ class PasswordStore {
private init() {
// File migration to group
migration()
do {
if FileManager.default.fileExists(atPath: storeURL.path) {
if fm.fileExists(atPath: storeURL.path) {
try storeRepository = GTRepository.init(url: storeURL)
}
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 {
case `public`, secret
}
@ -160,7 +203,6 @@ class PasswordStore {
private func importKey(from keyPath: String) -> PGPKey? {
let fm = FileManager.default
if fm.fileExists(atPath: keyPath) {
if let keys = pgp.importKeys(fromFile: keyPath, allowDuplicates: false) as? [PGPKey] {
return keys.first
@ -230,7 +272,6 @@ class PasswordStore {
let credentialProvider = try credential.credentialProvider()
let options = [GTRepositoryCloneOptionsCredentialProvider: credentialProvider]
storeRepository = try GTRepository.clone(from: remoteRepoURL, toWorkingDirectory: tempStoreURL, options: options, transferProgressBlock:transferProgressBlock)
let fm = FileManager.default
if fm.fileExists(atPath: storeURL.path) {
try fm.removeItem(at: storeURL)
}
@ -271,7 +312,6 @@ class PasswordStore {
private func updatePasswordEntityCoreData() {
deleteCoreData(entityName: "PasswordEntity")
let fm = FileManager.default
do {
var q = try fm.contentsOfDirectory(atPath: self.storeURL.path).filter{
!$0.hasPrefix(".")
@ -443,8 +483,8 @@ class PasswordStore {
throw AppError.RepositoryNotSetError
}
let url = storeURL.appendingPathComponent(path)
if FileManager.default.fileExists(atPath: url.path) {
try FileManager.default.removeItem(at: url)
if fm.fileExists(atPath: url.path) {
try fm.removeItem(at: url)
}
try storeRepository.index().removeFile(path)
try storeRepository.index().write()
@ -452,7 +492,6 @@ class PasswordStore {
private func deleteDirectoryTree(at url: URL) throws {
var tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path)
let fm = FileManager.default
var count = try fm.contentsOfDirectory(atPath: tempURL.path).count
while count == 0 {
try fm.removeItem(at: tempURL)
@ -463,13 +502,12 @@ class PasswordStore {
private func createDirectoryTree(at url: URL) throws {
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 {
let fromURL = storeURL.appendingPathComponent(from)
let toURL = storeURL.appendingPathComponent(to)
let fm = FileManager.default
guard fm.fileExists(atPath: fromURL.path) else {
print("\(from) not exist")
return
@ -779,8 +817,6 @@ class PasswordStore {
return encryptedData
}
func removePGPKeys() {
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
@ -803,12 +839,10 @@ class PasswordStore {
}
func gitSSHKeyExists() -> Bool {
let fm = FileManager.default
return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
}
func pgpKeyExists() -> Bool {
let fm = FileManager.default
return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath)
}
}