diff --git a/passKit/Crypto/PGPAgent.swift b/passKit/Crypto/PGPAgent.swift index 66fbbed..f193515 100644 --- a/passKit/Crypto/PGPAgent.swift +++ b/passKit/Crypto/PGPAgent.swift @@ -34,6 +34,10 @@ public class PGPAgent { pgpInterface = nil } + public func isInitialized() -> Bool { + pgpInterface != nil + } + public func getKeyID() throws -> [String] { try checkAndInit() return pgpInterface?.keyID ?? [] diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index 495dce2..37f57f8 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -324,7 +324,7 @@ public class PasswordStore { PersistenceController.shared.save() } - public func deleteCoreData() { + private func deleteCoreData() { PasswordEntity.deleteAll(in: context) PersistenceController.shared.save() } diff --git a/passKitTests/Models/PasswordStoreTest.swift b/passKitTests/Models/PasswordStoreTest.swift index 40357fa..5e12555 100644 --- a/passKitTests/Models/PasswordStoreTest.swift +++ b/passKitTests/Models/PasswordStoreTest.swift @@ -13,7 +13,7 @@ import XCTest @testable import passKit final class PasswordStoreTest: XCTestCase { - private let remoteRepoURL: URL = Bundle(for: PasswordStoreTest.self).resourceURL!.appendingPathComponent("Fixtures/password-store.git") + private lazy var remoteRepoURL: URL = Bundle(for: type(of: self)).resourceURL!.appendingPathComponent("Fixtures/password-store.git") private let localRepoURL: URL = Globals.sharedContainerURL.appendingPathComponent("Library/password-store-test/") private var passwordStore: PasswordStore! = nil @@ -49,8 +49,68 @@ final class PasswordStoreTest: XCTestCase { XCTAssertEqual(dirEntity!.children.count, 1) } + func testEraseStoreData() throws { + try cloneRepository() + XCTAssertTrue(FileManager.default.fileExists(atPath: localRepoURL.path)) + XCTAssertGreaterThan(passwordStore.numberOfPasswords, 0) + XCTAssertNotNil(passwordStore.gitRepository) + + passwordStore.eraseStoreData() + + XCTAssertFalse(FileManager.default.fileExists(atPath: localRepoURL.path)) + XCTAssertEqual(passwordStore.numberOfPasswords, 0) + XCTAssertNil(passwordStore.gitRepository) + } + + func testErase() throws { + try cloneRepository() + try importPGPKeys() + Defaults.gitSignatureName = "Test User" + PasscodeLock.shared.save(passcode: "1234") + + XCTAssertGreaterThan(passwordStore.numberOfPasswords, 0) + XCTAssertTrue(AppKeychain.shared.contains(key: PGPKey.PUBLIC.getKeychainKey())) + XCTAssertEqual(Defaults.gitSignatureName, "Test User") + XCTAssertTrue(PasscodeLock.shared.hasPasscode) + XCTAssertTrue(PGPAgent.shared.isInitialized()) + + passwordStore.erase() + + XCTAssertEqual(passwordStore.numberOfPasswords, 0) + XCTAssertFalse(AppKeychain.shared.contains(key: PGPKey.PUBLIC.getKeychainKey())) + XCTAssertFalse(Defaults.hasKey(\.gitSignatureName)) + XCTAssertFalse(PasscodeLock.shared.hasPasscode) + XCTAssertFalse(PGPAgent.shared.isInitialized()) + } + + func testFetchPasswordEntityCoreDataByParent() throws { + try cloneRepository() + + let rootChildren = passwordStore.fetchPasswordEntityCoreData(parent: nil) + XCTAssertGreaterThan(rootChildren.count, 0) + rootChildren.forEach { entity in + XCTAssertTrue(entity.isDir) + } + + let personalDir = passwordStore.fetchPasswordEntity(with: "personal") + let personalChildren = passwordStore.fetchPasswordEntityCoreData(parent: personalDir) + XCTAssertEqual(personalChildren.count, 1) + XCTAssertEqual(personalChildren.first?.name, "github.com") + } + + func testFetchPasswordEntityCoreDataWithDir() throws { + try cloneRepository() + + let allPasswords = passwordStore.fetchPasswordEntityCoreData(withDir: false) + XCTAssertEqual(allPasswords.count, 4) + allPasswords.forEach { entity in + XCTAssertFalse(entity.isDir) + } + } + func testCloneAndDecryptMultiKeys() throws { try cloneRepository() + try importPGPKeys() Defaults.isEnableGPGIDOn = true defer { @@ -65,15 +125,10 @@ final class PasswordStoreTest: XCTestCase { XCTAssertEqual(keyID, id) } - let keychain = AppKeychain.shared - try KeyFileManager(keyType: PGPKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048_RSA4096.publicKeys) - try KeyFileManager(keyType: PGPKey.PRIVATE, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048_RSA4096.privateKeys) - try PGPAgent.shared.initKeys() - - let personal = try decrypt(passwordStore: passwordStore, path: "personal/github.com.gpg", passphrase: "passforios") + let personal = try decrypt(path: "personal/github.com.gpg") XCTAssertEqual(personal.plainText, "passwordforpersonal\n") - let work = try decrypt(passwordStore: passwordStore, path: "work/github.com.gpg", passphrase: "passforios") + let work = try decrypt(path: "work/github.com.gpg") XCTAssertEqual(work.plainText, "passwordforwork\n") let testPassword = Password(name: "test", path: "test.gpg", plainText: "testpassword") @@ -82,13 +137,22 @@ final class PasswordStoreTest: XCTestCase { XCTAssertEqual(testPasswordPlain.plainText, "testpassword") } - fileprivate func cloneRepository() throws { + // MARK: - Helpers + + private func cloneRepository() throws { try passwordStore.cloneRepository(remoteRepoURL: remoteRepoURL, branchName: "master") expectation(for: NSPredicate { _, _ in FileManager.default.fileExists(atPath: self.localRepoURL.path) }, evaluatedWith: nil) waitForExpectations(timeout: 3, handler: nil) } - fileprivate func decrypt(passwordStore: PasswordStore, path: String, passphrase _: String) throws -> Password { + private func importPGPKeys() throws { + let keychain = AppKeychain.shared + try KeyFileManager(keyType: PGPKey.PUBLIC, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048_RSA4096.publicKeys) + try KeyFileManager(keyType: PGPKey.PRIVATE, keyPath: "", keyHandler: keychain.add).importKey(from: RSA2048_RSA4096.privateKeys) + try PGPAgent.shared.initKeys() + } + + private func decrypt(path: String) throws -> Password { let entity = passwordStore.fetchPasswordEntity(with: path)! return try passwordStore.decrypt(passwordEntity: entity, requestPGPKeyPassphrase: requestPGPKeyPassphrase) }