mirror of
				https://github.com/maxgoedjen/secretive.git
				synced 2025-10-31 07:20:57 +00:00 
			
		
		
		
	Agent Tests (#74)
This commit is contained in:
		
							parent
							
								
									1f7ebcfe75
								
							
						
					
					
						commit
						4dcc9b113d
					
				| @ -28,7 +28,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { | |||||||
|     func applicationDidFinishLaunching(_ aNotification: Notification) { |     func applicationDidFinishLaunching(_ aNotification: Notification) { | ||||||
|         os_log(.debug, "SecretAgent finished launching") |         os_log(.debug, "SecretAgent finished launching") | ||||||
|         DispatchQueue.main.async { |         DispatchQueue.main.async { | ||||||
|             self.socketController.handler = self.agent.handle(fileHandle:) |             self.socketController.handler = self.agent.handle(reader:writer:) | ||||||
|         } |         } | ||||||
|         notifier.prompt() |         notifier.prompt() | ||||||
|         updateSink = updater.$update.sink { update in |         updateSink = updater.$update.sink { update in | ||||||
|  | |||||||
| @ -21,28 +21,34 @@ public class Agent { | |||||||
| 
 | 
 | ||||||
| extension Agent { | extension Agent { | ||||||
| 
 | 
 | ||||||
|     public func handle(fileHandle: FileHandle) { |     public func handle(reader: FileHandleReader, writer: FileHandleWriter) { | ||||||
|         os_log(.debug, "Agent handling new data") |         os_log(.debug, "Agent handling new data") | ||||||
|         let data = fileHandle.availableData |         let data = reader.availableData | ||||||
|         guard !data.isEmpty else { return } |         guard !data.isEmpty else { return } | ||||||
|         let requestTypeInt = data[4] |         let requestTypeInt = data[4] | ||||||
|         guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { return } |         guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { | ||||||
|  |             writer.write(OpenSSHKeyWriter().lengthAndData(of: SSHAgent.ResponseType.agentFailure.data)) | ||||||
|  |             os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription) | ||||||
|  |             return | ||||||
|  |         } | ||||||
|         os_log(.debug, "Agent handling request of type %@", requestType.debugDescription) |         os_log(.debug, "Agent handling request of type %@", requestType.debugDescription) | ||||||
|         let subData = Data(data[5...]) |         let subData = Data(data[5...]) | ||||||
|         handle(requestType: requestType, data: subData, fileHandle: fileHandle) |         let response = handle(requestType: requestType, data: subData, reader: reader) | ||||||
|  |         writer.write(response) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     func handle(requestType: SSHAgent.RequestType, data: Data, fileHandle: FileHandle) { |     func handle(requestType: SSHAgent.RequestType, data: Data, reader: FileHandleReader) -> Data { | ||||||
|         var response = Data() |         var response = Data() | ||||||
|         do { |         do { | ||||||
|             switch requestType { |             switch requestType { | ||||||
|             case .requestIdentities: |             case .requestIdentities: | ||||||
|                 response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data) |                 response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data) | ||||||
|                 response.append(try identities()) |                 response.append(identities()) | ||||||
|                 os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) |                 os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) | ||||||
|             case .signRequest: |             case .signRequest: | ||||||
|  |                 let provenance = requestTracer.provenance(from: reader) | ||||||
|                 response.append(SSHAgent.ResponseType.agentSignResponse.data) |                 response.append(SSHAgent.ResponseType.agentSignResponse.data) | ||||||
|                 response.append(try sign(data: data, from: fileHandle.fileDescriptor)) |                 response.append(try sign(data: data, provenance: provenance)) | ||||||
|                 os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription) |                 os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription) | ||||||
|             } |             } | ||||||
|         } catch { |         } catch { | ||||||
| @ -51,14 +57,14 @@ extension Agent { | |||||||
|             os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription) |             os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription) | ||||||
|         } |         } | ||||||
|         let full = OpenSSHKeyWriter().lengthAndData(of: response) |         let full = OpenSSHKeyWriter().lengthAndData(of: response) | ||||||
|         fileHandle.write(full) |         return full | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| extension Agent { | extension Agent { | ||||||
| 
 | 
 | ||||||
|     func identities() throws -> Data { |     func identities() -> Data { | ||||||
|         // TODO: RESTORE ONCE XCODE 11.4 IS GM |         // TODO: RESTORE ONCE XCODE 11.4 IS GM | ||||||
|         let secrets = storeList.stores.flatMap { $0.secrets } |         let secrets = storeList.stores.flatMap { $0.secrets } | ||||||
| //        let secrets = storeList.stores.flatMap(\.secrets) | //        let secrets = storeList.stores.flatMap(\.secrets) | ||||||
| @ -76,7 +82,7 @@ extension Agent { | |||||||
|         return countData + keyData |         return countData + keyData | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     func sign(data: Data, from pid: Int32) throws -> Data { |     func sign(data: Data, provenance: SigningRequestProvenance) throws -> Data { | ||||||
|         let reader = OpenSSHReader(data: data) |         let reader = OpenSSHReader(data: data) | ||||||
|         let hash = reader.readNextChunk() |         let hash = reader.readNextChunk() | ||||||
|         guard let (store, secret) = secret(matching: hash) else { |         guard let (store, secret) = secret(matching: hash) else { | ||||||
| @ -84,7 +90,6 @@ extension Agent { | |||||||
|             throw AgentError.noMatchingKey |             throw AgentError.noMatchingKey | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let provenance = requestTracer.provenance(from: pid) |  | ||||||
|         if let witness = witness { |         if let witness = witness { | ||||||
|             try witness.speakNowOrForeverHoldYourPeace(forAccessTo: secret, by: provenance) |             try witness.speakNowOrForeverHoldYourPeace(forAccessTo: secret, by: provenance) | ||||||
|         } |         } | ||||||
| @ -103,7 +108,7 @@ extension Agent { | |||||||
|         case (.ellipticCurve, 384): |         case (.ellipticCurve, 384): | ||||||
|             rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation |             rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation | ||||||
|         default: |         default: | ||||||
|             fatalError() |             throw AgentError.unsupportedKeyType | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -154,6 +159,7 @@ extension Agent { | |||||||
|     enum AgentError: Error { |     enum AgentError: Error { | ||||||
|         case unhandledType |         case unhandledType | ||||||
|         case noMatchingKey |         case noMatchingKey | ||||||
|  |         case unsupportedKeyType | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								SecretAgentKit/FileHandleProtocols.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								SecretAgentKit/FileHandleProtocols.swift
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | import Foundation | ||||||
|  | 
 | ||||||
|  | public protocol FileHandleReader { | ||||||
|  | 
 | ||||||
|  |     var availableData: Data { get } | ||||||
|  |     var fileDescriptor: Int32 { get } | ||||||
|  |     var pidOfConnectedProcess: Int32 { get } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | public protocol FileHandleWriter { | ||||||
|  | 
 | ||||||
|  |     func write(_ data: Data) | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extension FileHandle: FileHandleReader, FileHandleWriter { | ||||||
|  | 
 | ||||||
|  |     public var pidOfConnectedProcess: Int32 { | ||||||
|  |         let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1) | ||||||
|  |         var len = socklen_t(MemoryLayout<Int32>.size) | ||||||
|  |         getsockopt(fileDescriptor, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len) | ||||||
|  |         return pidPointer.load(as: Int32.self) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -12,7 +12,7 @@ extension SSHAgent { | |||||||
|             switch self { |             switch self { | ||||||
|             case .requestIdentities: |             case .requestIdentities: | ||||||
|                 return "RequestIdentities" |                 return "RequestIdentities" | ||||||
|             default: |             case .signRequest: | ||||||
|                 return "SignRequest" |                 return "SignRequest" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import Foundation | import Foundation | ||||||
| import AppKit | import AppKit | ||||||
| 
 | 
 | ||||||
| public struct SigningRequestProvenance { | public struct SigningRequestProvenance: Equatable { | ||||||
| 
 | 
 | ||||||
|     public var chain: [Process] |     public var chain: [Process] | ||||||
|     public init(root: Process) { |     public init(root: Process) { | ||||||
| @ -24,7 +24,7 @@ extension SigningRequestProvenance { | |||||||
| 
 | 
 | ||||||
| extension SigningRequestProvenance { | extension SigningRequestProvenance { | ||||||
| 
 | 
 | ||||||
|     public struct Process { |     public struct Process: Equatable { | ||||||
| 
 | 
 | ||||||
|         public let pid: Int32 |         public let pid: Int32 | ||||||
|         public let name: String |         public let name: String | ||||||
|  | |||||||
| @ -4,12 +4,8 @@ import Security | |||||||
| 
 | 
 | ||||||
| struct SigningRequestTracer { | struct SigningRequestTracer { | ||||||
| 
 | 
 | ||||||
|     func provenance(from pid: Int32) -> SigningRequestProvenance { |     func provenance(from fileHandleReader: FileHandleReader) -> SigningRequestProvenance { | ||||||
|         let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1) |         let firstInfo = process(from: fileHandleReader.pidOfConnectedProcess) | ||||||
|         var len = socklen_t(MemoryLayout<Int32>.size) |  | ||||||
|         getsockopt(pid, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len) |  | ||||||
|         let pid = pidPointer.load(as: Int32.self) |  | ||||||
|         let firstInfo = process(from: pid) |  | ||||||
| 
 | 
 | ||||||
|         var provenance = SigningRequestProvenance(root: firstInfo) |         var provenance = SigningRequestProvenance(root: firstInfo) | ||||||
|         while NSRunningApplication(processIdentifier: provenance.origin.pid) == nil && provenance.origin.parentPID != nil { |         while NSRunningApplication(processIdentifier: provenance.origin.pid) == nil && provenance.origin.parentPID != nil { | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ public class SocketController { | |||||||
| 
 | 
 | ||||||
|     fileprivate var fileHandle: FileHandle? |     fileprivate var fileHandle: FileHandle? | ||||||
|     fileprivate var port: SocketPort? |     fileprivate var port: SocketPort? | ||||||
|     public var handler: ((FileHandle) -> Void)? |     public var handler: ((FileHandleReader, FileHandleWriter) -> Void)? | ||||||
| 
 | 
 | ||||||
|     public init(path: String) { |     public init(path: String) { | ||||||
|         os_log(.debug, "Socket controller setting up at %@", path) |         os_log(.debug, "Socket controller setting up at %@", path) | ||||||
| @ -52,7 +52,7 @@ public class SocketController { | |||||||
|     @objc func handleConnectionAccept(notification: Notification) { |     @objc func handleConnectionAccept(notification: Notification) { | ||||||
|         os_log(.debug, "Socket controller accepted connection") |         os_log(.debug, "Socket controller accepted connection") | ||||||
|         guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return } |         guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return } | ||||||
|         handler?(new) |         handler?(new, new) | ||||||
|         new.waitForDataInBackgroundAndNotify() |         new.waitForDataInBackgroundAndNotify() | ||||||
|         fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!]) |         fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!]) | ||||||
|     } |     } | ||||||
| @ -61,7 +61,7 @@ public class SocketController { | |||||||
|         os_log(.debug, "Socket controller has new data available") |         os_log(.debug, "Socket controller has new data available") | ||||||
|         guard let new = notification.object as? FileHandle else { return } |         guard let new = notification.object as? FileHandle else { return } | ||||||
|         os_log(.debug, "Socket controller received new file handle") |         os_log(.debug, "Socket controller received new file handle") | ||||||
|         handler?(new) |         handler?(new, new) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										162
									
								
								SecretAgentKitTests/AgentTests.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								SecretAgentKitTests/AgentTests.swift
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,162 @@ | |||||||
|  | import Foundation | ||||||
|  | import XCTest | ||||||
|  | import CryptoKit | ||||||
|  | @testable import SecretKit | ||||||
|  | @testable import SecretAgentKit | ||||||
|  | 
 | ||||||
|  | class AgentTests: XCTestCase { | ||||||
|  | 
 | ||||||
|  |     let stubWriter = StubFileHandleWriter() | ||||||
|  | 
 | ||||||
|  |     // MARK: Identity Listing | ||||||
|  | 
 | ||||||
|  |     func testEmptyStores() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestIdentities) | ||||||
|  |         let agent = Agent(storeList: SecretStoreList()) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertEqual(stubWriter.data, Constants.Responses.requestIdentitiesEmpty) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     func testIdentitiesList() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestIdentities) | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret]) | ||||||
|  |         let agent = Agent(storeList: list) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertEqual(stubWriter.data, Constants.Responses.requestIdentitiesMultiple) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // MARK: Signatures | ||||||
|  | 
 | ||||||
|  |     func testNoMatchingIdentities() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignatureWithNoneMatching) | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret]) | ||||||
|  |         let agent = Agent(storeList: list) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  | //        XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     func testSignature() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature) | ||||||
|  |         let requestReader = OpenSSHReader(data: Constants.Requests.requestSignature[5...]) | ||||||
|  |         _ = requestReader.readNextChunk() | ||||||
|  |         let dataToSign = requestReader.readNextChunk() | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret]) | ||||||
|  |         let agent = Agent(storeList: list) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         let outer = OpenSSHReader(data: stubWriter.data[5...]) | ||||||
|  |         let payload = outer.readNextChunk() | ||||||
|  |         let inner = OpenSSHReader(data: payload) | ||||||
|  |         _ = inner.readNextChunk() | ||||||
|  |         let signedData = inner.readNextChunk() | ||||||
|  |         let rsData = OpenSSHReader(data: signedData) | ||||||
|  |         let r = rsData.readNextChunk() | ||||||
|  |         let s = rsData.readNextChunk() | ||||||
|  |         var rs = r | ||||||
|  |         rs.append(s) | ||||||
|  |         let signature = try! P256.Signing.ECDSASignature(rawRepresentation: rs) | ||||||
|  |         let valid = try! P256.Signing.PublicKey(x963Representation: Constants.Secrets.ecdsa256Secret.publicKey).isValidSignature(signature, for: dataToSign) | ||||||
|  |         XCTAssertTrue(valid) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // MARK: Witness protocol | ||||||
|  | 
 | ||||||
|  |     func testWitnessObjectionStopsRequest() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature) | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret]) | ||||||
|  |         let witness = StubWitness(speakNow: { _,_  in | ||||||
|  |             return true | ||||||
|  |         }, witness: { _, _ in }) | ||||||
|  |         let agent = Agent(storeList: list, witness: witness) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     func testWitnessSignature() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature) | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret]) | ||||||
|  |         var witnessed = false | ||||||
|  |         let witness = StubWitness(speakNow: { _, trace  in | ||||||
|  |             return false | ||||||
|  |         }, witness: { _, trace in | ||||||
|  |             witnessed = true | ||||||
|  |         }) | ||||||
|  |         let agent = Agent(storeList: list, witness: witness) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertTrue(witnessed) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     func testRequestTracing() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature) | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret]) | ||||||
|  |         var speakNowTrace: SigningRequestProvenance! = nil | ||||||
|  |         var witnessTrace: SigningRequestProvenance! = nil | ||||||
|  |         let witness = StubWitness(speakNow: { _, trace  in | ||||||
|  |             speakNowTrace = trace | ||||||
|  |             return false | ||||||
|  |         }, witness: { _, trace in | ||||||
|  |             witnessTrace = trace | ||||||
|  |         }) | ||||||
|  |         let agent = Agent(storeList: list, witness: witness) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertEqual(witnessTrace, speakNowTrace) | ||||||
|  |         XCTAssertEqual(witnessTrace.origin.name, "Finder") | ||||||
|  |         XCTAssertEqual(witnessTrace.origin.validSignature, true) | ||||||
|  |         XCTAssertEqual(witnessTrace.origin.parentPID, 1) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // MARK: Exception Handling | ||||||
|  | 
 | ||||||
|  |     func testSignatureException() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature) | ||||||
|  |         let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret]) | ||||||
|  |         let store = list.stores.first?.base as! Stub.Store | ||||||
|  |         store.shouldThrow = true | ||||||
|  |         let agent = Agent(storeList: list) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // MARK: Unsupported | ||||||
|  | 
 | ||||||
|  |     func testUnhandledAdd() { | ||||||
|  |         let stubReader = StubFileHandleReader(availableData: Constants.Requests.addIdentity) | ||||||
|  |         let agent = Agent(storeList: SecretStoreList()) | ||||||
|  |         agent.handle(reader: stubReader, writer: stubWriter) | ||||||
|  |         XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extension AgentTests { | ||||||
|  | 
 | ||||||
|  |     func storeList(with secrets: [Stub.Secret]) -> SecretStoreList { | ||||||
|  |         let store = Stub.Store() | ||||||
|  |         store.secrets.append(contentsOf: secrets) | ||||||
|  |         let storeList = SecretStoreList() | ||||||
|  |         storeList.add(store: store) | ||||||
|  |         return storeList | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     enum Constants { | ||||||
|  | 
 | ||||||
|  |         enum Requests { | ||||||
|  |             static let requestIdentities = Data(base64Encoded: "AAAAAQs=")! | ||||||
|  |             static let addIdentity = Data(base64Encoded: "AAAAARE=")! | ||||||
|  |             static let requestSignatureWithNoneMatching = Data(base64Encoded: "AAABhA0AAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAO8AAAAgbqmrqPUtJ8mmrtaSVexjMYyXWNqjHSnoto7zgv86xvcyAAAAA2dpdAAAAA5zc2gtY29ubmVjdGlvbgAAAAlwdWJsaWNrZXkBAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAAA=")! | ||||||
|  |             static let requestSignature = Data(base64Encoded: "AAABRA0AAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08AAADPAAAAIBIFsbCZ4/dhBmLNGHm0GKj7EJ4N8k/jXRxlyg+LFIYzMgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAAA==")! | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         enum Responses { | ||||||
|  |             static let requestIdentitiesEmpty = Data(base64Encoded: "AAAABQwAAAAA")! | ||||||
|  |             static let requestIdentitiesMultiple = Data(base64Encoded: "AAABKwwAAAACAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0")! | ||||||
|  |             static let requestFailure = Data(base64Encoded: "AAAAAQU=")! | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         enum Secrets { | ||||||
|  |             static let ecdsa256Secret =  Stub.Secret(keySize: 256, publicKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08=")!, privateKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy09nw780wy/TSfUmzj15iJkV234AaCLNl+H8qFL6qK8VIg==")!) | ||||||
|  |             static let ecdsa384Secret =  Stub.Secret(keySize: 384, publicKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDA==")!, privateKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDHNapAOzrt9E+9QC4/KYoXS7Uw4pmdAz53uIj02tttiq3c0ZyIQ7XoscWWRqRrz8Kw==")!) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,11 +0,0 @@ | |||||||
| import XCTest |  | ||||||
| @testable import SecretAgentKit |  | ||||||
| 
 |  | ||||||
| class SecretAgentKitTests: XCTestCase { |  | ||||||
| 
 |  | ||||||
|     func testExample() throws { |  | ||||||
|         // This is an example of a functional test case. |  | ||||||
|         // Use XCTAssert and related functions to verify your tests produce the correct results. |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
							
								
								
									
										14
									
								
								SecretAgentKitTests/StubFileHandleReader.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								SecretAgentKitTests/StubFileHandleReader.swift
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | import SecretAgentKit | ||||||
|  | import AppKit | ||||||
|  | 
 | ||||||
|  | struct StubFileHandleReader: FileHandleReader { | ||||||
|  | 
 | ||||||
|  |     let availableData: Data | ||||||
|  |     var fileDescriptor: Int32 { | ||||||
|  |         NSWorkspace.shared.runningApplications.filter({ $0.localizedName == "Finder" }).first!.processIdentifier | ||||||
|  |     } | ||||||
|  |     var pidOfConnectedProcess: Int32 { | ||||||
|  |         fileDescriptor | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								SecretAgentKitTests/StubFileHandleWriter.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								SecretAgentKitTests/StubFileHandleWriter.swift
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | import SecretAgentKit | ||||||
|  | 
 | ||||||
|  | class StubFileHandleWriter: FileHandleWriter { | ||||||
|  | 
 | ||||||
|  |     var data = Data() | ||||||
|  | 
 | ||||||
|  |     func write(_ data: Data) { | ||||||
|  |         self.data.append(data) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										113
									
								
								SecretAgentKitTests/StubStore.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								SecretAgentKitTests/StubStore.swift
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | |||||||
|  | import SecretKit | ||||||
|  | import CryptoKit | ||||||
|  | 
 | ||||||
|  | struct Stub {} | ||||||
|  | 
 | ||||||
|  | extension Stub { | ||||||
|  | 
 | ||||||
|  |     public class Store: SecretStore { | ||||||
|  | 
 | ||||||
|  |         public let isAvailable = true | ||||||
|  |         public let id = UUID() | ||||||
|  |         public let name = "Stub" | ||||||
|  |         public var secrets: [Secret] = [] | ||||||
|  |         public var shouldThrow = false | ||||||
|  | 
 | ||||||
|  |         public init() { | ||||||
|  | //            try! create(size: 256) | ||||||
|  | //            try! create(size: 384) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public func create(size: Int) throws { | ||||||
|  |             let flags: SecAccessControlCreateFlags = [] | ||||||
|  |             let access = | ||||||
|  |                 SecAccessControlCreateWithFlags(kCFAllocatorDefault, | ||||||
|  |                                                 kSecAttrAccessibleWhenUnlockedThisDeviceOnly, | ||||||
|  |                                                 flags, | ||||||
|  |                                                 nil) as Any | ||||||
|  | 
 | ||||||
|  |             let attributes = [ | ||||||
|  |                 kSecAttrLabel: name, | ||||||
|  |                 kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, | ||||||
|  |                 kSecAttrKeySizeInBits: size, | ||||||
|  |                 kSecPrivateKeyAttrs: [ | ||||||
|  |                     kSecAttrIsPermanent: true, | ||||||
|  |                     kSecAttrAccessControl: access | ||||||
|  |                 ] | ||||||
|  |                 ] as CFDictionary | ||||||
|  | 
 | ||||||
|  |             var privateKey: SecKey! = nil | ||||||
|  |             var publicKey: SecKey! = nil | ||||||
|  |             SecKeyGeneratePair(attributes, &publicKey, &privateKey) | ||||||
|  |             let publicAttributes = SecKeyCopyAttributes(publicKey) as! [CFString: Any] | ||||||
|  |             let privateAttributes = SecKeyCopyAttributes(privateKey) as! [CFString: Any] | ||||||
|  |             let publicData = (publicAttributes[kSecValueData] as! Data) | ||||||
|  |             let privateData = (privateAttributes[kSecValueData] as! Data) | ||||||
|  |             let secret = Secret(keySize: size, publicKey: publicData, privateKey: privateData) | ||||||
|  |             print(secret) | ||||||
|  |             print("Public Key OpenSSH: \(OpenSSHKeyWriter().openSSHString(secret: secret))") | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public func sign(data: Data, with secret: Secret) throws -> Data { | ||||||
|  |             guard !shouldThrow else { | ||||||
|  |                 throw NSError() | ||||||
|  |             } | ||||||
|  |             let privateKey = SecKeyCreateWithData(secret.privateKey as CFData, [ | ||||||
|  |                 kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, | ||||||
|  |                 kSecAttrKeySizeInBits: secret.keySize, | ||||||
|  |                 kSecAttrKeyClass: kSecAttrKeyClassPrivate | ||||||
|  |                 ] as CFDictionary | ||||||
|  |                 , nil)! | ||||||
|  |             let signatureAlgorithm: SecKeyAlgorithm | ||||||
|  |             switch secret.keySize { | ||||||
|  |             case 256: | ||||||
|  |                 signatureAlgorithm = .ecdsaSignatureMessageX962SHA256 | ||||||
|  |             case 384: | ||||||
|  |                 signatureAlgorithm = .ecdsaSignatureMessageX962SHA384 | ||||||
|  |             default: | ||||||
|  |                 fatalError() | ||||||
|  |             } | ||||||
|  |             return SecKeyCreateSignature(privateKey, signatureAlgorithm, data as CFData, nil)! as Data | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extension Stub { | ||||||
|  | 
 | ||||||
|  |     struct Secret: SecretKit.Secret, CustomDebugStringConvertible { | ||||||
|  | 
 | ||||||
|  |         let id = UUID().uuidString.data(using: .utf8)! | ||||||
|  |         let name = UUID().uuidString | ||||||
|  |         let algorithm = Algorithm.ellipticCurve | ||||||
|  | 
 | ||||||
|  |         let keySize: Int | ||||||
|  |         let publicKey: Data | ||||||
|  |         let privateKey: Data | ||||||
|  | 
 | ||||||
|  |         init(keySize: Int, publicKey: Data, privateKey: Data) { | ||||||
|  |             self.keySize = keySize | ||||||
|  |             self.publicKey = publicKey | ||||||
|  |             self.privateKey = privateKey | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         var debugDescription: String { | ||||||
|  |             """ | ||||||
|  |             Key Size \(keySize) | ||||||
|  |             Private: \(privateKey.base64EncodedString()) | ||||||
|  |             Public: \(publicKey.base64EncodedString()) | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | extension Stub.Store { | ||||||
|  | 
 | ||||||
|  |     struct StubError: Error { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								SecretAgentKitTests/StubWitness.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								SecretAgentKitTests/StubWitness.swift
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | import SecretKit | ||||||
|  | import SecretAgentKit | ||||||
|  | 
 | ||||||
|  | struct StubWitness { | ||||||
|  | 
 | ||||||
|  |     let speakNow: (AnySecret, SigningRequestProvenance) -> Bool | ||||||
|  |     let witness: (AnySecret, SigningRequestProvenance) -> () | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extension StubWitness: SigningWitness { | ||||||
|  | 
 | ||||||
|  |     func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws { | ||||||
|  |         let objection = speakNow(secret, provenance) | ||||||
|  |         if objection { | ||||||
|  |             throw TheresMyChance() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws { | ||||||
|  |         witness(secret, provenance) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extension StubWitness { | ||||||
|  | 
 | ||||||
|  |     struct TheresMyChance: Error { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -7,7 +7,7 @@ public protocol Secret: Identifiable, Hashable { | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| public enum Algorithm { | public enum Algorithm: Hashable { | ||||||
|     case ellipticCurve |     case ellipticCurve | ||||||
|     public init(secAttr: NSNumber) { |     public init(secAttr: NSNumber) { | ||||||
|         let secAttrString = secAttr.stringValue as CFString |         let secAttrString = secAttr.stringValue as CFString | ||||||
|  | |||||||
| @ -45,6 +45,11 @@ | |||||||
| 		507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.swift */; }; | 		507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.swift */; }; | ||||||
| 		507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; }; | 		507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; }; | ||||||
| 		507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; }; | 		507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; }; | ||||||
|  | 		507EE34224281E12003C4FE3 /* FileHandleProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */; }; | ||||||
|  | 		507EE34624281F89003C4FE3 /* StubFileHandleReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */; }; | ||||||
|  | 		507EE34824281FB8003C4FE3 /* StubFileHandleWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34724281FB8003C4FE3 /* StubFileHandleWriter.swift */; }; | ||||||
|  | 		507EE34A2428263B003C4FE3 /* StubStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE3492428263B003C4FE3 /* StubStore.swift */; }; | ||||||
|  | 		507EE34E2428784F003C4FE3 /* StubWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34D2428784F003C4FE3 /* StubWitness.swift */; }; | ||||||
| 		508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; }; | 		508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; }; | ||||||
| 		508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; }; | 		508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; }; | ||||||
| 		508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; }; | 		508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; }; | ||||||
| @ -56,7 +61,7 @@ | |||||||
| 		5099A02B23FE352C0062B6F2 /* SmartCardSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02A23FE352C0062B6F2 /* SmartCardSecret.swift */; }; | 		5099A02B23FE352C0062B6F2 /* SmartCardSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02A23FE352C0062B6F2 /* SmartCardSecret.swift */; }; | ||||||
| 		5099A02E23FE56E10062B6F2 /* OpenSSHKeyWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02D23FE56E10062B6F2 /* OpenSSHKeyWriter.swift */; }; | 		5099A02E23FE56E10062B6F2 /* OpenSSHKeyWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02D23FE56E10062B6F2 /* OpenSSHKeyWriter.swift */; }; | ||||||
| 		5099A075240242BA0062B6F2 /* SecretAgentKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; }; | 		5099A075240242BA0062B6F2 /* SecretAgentKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; }; | ||||||
| 		5099A07C240242BA0062B6F2 /* SecretAgentKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A07B240242BA0062B6F2 /* SecretAgentKitTests.swift */; }; | 		5099A07C240242BA0062B6F2 /* AgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A07B240242BA0062B6F2 /* AgentTests.swift */; }; | ||||||
| 		5099A07E240242BA0062B6F2 /* SecretAgentKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5099A06E240242BA0062B6F2 /* SecretAgentKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; | 		5099A07E240242BA0062B6F2 /* SecretAgentKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5099A06E240242BA0062B6F2 /* SecretAgentKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; | ||||||
| 		5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */; }; | 		5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */; }; | ||||||
| 		50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; }; | 		50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; }; | ||||||
| @ -238,6 +243,11 @@ | |||||||
| 		507CE4EF2420A4C50029F750 /* SigningWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningWitness.swift; sourceTree = "<group>"; }; | 		507CE4EF2420A4C50029F750 /* SigningWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningWitness.swift; sourceTree = "<group>"; }; | ||||||
| 		507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestProvenance.swift; sourceTree = "<group>"; }; | 		507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestProvenance.swift; sourceTree = "<group>"; }; | ||||||
| 		507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; }; | 		507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; }; | ||||||
|  | 		507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileHandleProtocols.swift; sourceTree = "<group>"; }; | ||||||
|  | 		507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFileHandleReader.swift; sourceTree = "<group>"; }; | ||||||
|  | 		507EE34724281FB8003C4FE3 /* StubFileHandleWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFileHandleWriter.swift; sourceTree = "<group>"; }; | ||||||
|  | 		507EE3492428263B003C4FE3 /* StubStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubStore.swift; sourceTree = "<group>"; }; | ||||||
|  | 		507EE34D2428784F003C4FE3 /* StubWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubWitness.swift; sourceTree = "<group>"; }; | ||||||
| 		508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; }; | 		508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; }; | ||||||
| 		508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; | 		508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; | ||||||
| 		508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; }; | 		508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; }; | ||||||
| @ -252,7 +262,7 @@ | |||||||
| 		5099A06E240242BA0062B6F2 /* SecretAgentKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecretAgentKit.h; sourceTree = "<group>"; }; | 		5099A06E240242BA0062B6F2 /* SecretAgentKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecretAgentKit.h; sourceTree = "<group>"; }; | ||||||
| 		5099A06F240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | 		5099A06F240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | ||||||
| 		5099A074240242BA0062B6F2 /* SecretAgentKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecretAgentKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | 		5099A074240242BA0062B6F2 /* SecretAgentKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecretAgentKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||||
| 		5099A07B240242BA0062B6F2 /* SecretAgentKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretAgentKitTests.swift; sourceTree = "<group>"; }; | 		5099A07B240242BA0062B6F2 /* AgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentTests.swift; sourceTree = "<group>"; }; | ||||||
| 		5099A07D240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | 		5099A07D240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | ||||||
| 		5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHAgentProtocol.swift; sourceTree = "<group>"; }; | 		5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHAgentProtocol.swift; sourceTree = "<group>"; }; | ||||||
| 		50A3B78A24026B7500D209EA /* SecretAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecretAgent.app; sourceTree = BUILT_PRODUCTS_DIR; }; | 		50A3B78A24026B7500D209EA /* SecretAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecretAgent.app; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||||
| @ -529,6 +539,7 @@ | |||||||
| 				507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */, | 				507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */, | ||||||
| 				507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */, | 				507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */, | ||||||
| 				50A3B79F24026B9900D209EA /* Agent.swift */, | 				50A3B79F24026B9900D209EA /* Agent.swift */, | ||||||
|  | 				507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */, | ||||||
| 				5099A06F240242BA0062B6F2 /* Info.plist */, | 				5099A06F240242BA0062B6F2 /* Info.plist */, | ||||||
| 			); | 			); | ||||||
| 			path = SecretAgentKit; | 			path = SecretAgentKit; | ||||||
| @ -537,7 +548,11 @@ | |||||||
| 		5099A07A240242BA0062B6F2 /* SecretAgentKitTests */ = { | 		5099A07A240242BA0062B6F2 /* SecretAgentKitTests */ = { | ||||||
| 			isa = PBXGroup; | 			isa = PBXGroup; | ||||||
| 			children = ( | 			children = ( | ||||||
| 				5099A07B240242BA0062B6F2 /* SecretAgentKitTests.swift */, | 				5099A07B240242BA0062B6F2 /* AgentTests.swift */, | ||||||
|  | 				507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */, | ||||||
|  | 				507EE34724281FB8003C4FE3 /* StubFileHandleWriter.swift */, | ||||||
|  | 				507EE34D2428784F003C4FE3 /* StubWitness.swift */, | ||||||
|  | 				507EE3492428263B003C4FE3 /* StubStore.swift */, | ||||||
| 				5099A07D240242BA0062B6F2 /* Info.plist */, | 				5099A07D240242BA0062B6F2 /* Info.plist */, | ||||||
| 			); | 			); | ||||||
| 			path = SecretAgentKitTests; | 			path = SecretAgentKitTests; | ||||||
| @ -957,6 +972,7 @@ | |||||||
| 			isa = PBXSourcesBuildPhase; | 			isa = PBXSourcesBuildPhase; | ||||||
| 			buildActionMask = 2147483647; | 			buildActionMask = 2147483647; | ||||||
| 			files = ( | 			files = ( | ||||||
|  | 				507EE34224281E12003C4FE3 /* FileHandleProtocols.swift in Sources */, | ||||||
| 				507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */, | 				507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */, | ||||||
| 				5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */, | 				5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */, | ||||||
| 				507CE4ED2420A3C70029F750 /* Agent.swift in Sources */, | 				507CE4ED2420A3C70029F750 /* Agent.swift in Sources */, | ||||||
| @ -970,7 +986,11 @@ | |||||||
| 			isa = PBXSourcesBuildPhase; | 			isa = PBXSourcesBuildPhase; | ||||||
| 			buildActionMask = 2147483647; | 			buildActionMask = 2147483647; | ||||||
| 			files = ( | 			files = ( | ||||||
| 				5099A07C240242BA0062B6F2 /* SecretAgentKitTests.swift in Sources */, | 				507EE34E2428784F003C4FE3 /* StubWitness.swift in Sources */, | ||||||
|  | 				507EE34624281F89003C4FE3 /* StubFileHandleReader.swift in Sources */, | ||||||
|  | 				507EE34A2428263B003C4FE3 /* StubStore.swift in Sources */, | ||||||
|  | 				5099A07C240242BA0062B6F2 /* AgentTests.swift in Sources */, | ||||||
|  | 				507EE34824281FB8003C4FE3 /* StubFileHandleWriter.swift in Sources */, | ||||||
| 			); | 			); | ||||||
| 			runOnlyForDeploymentPostprocessing = 0; | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
| 		}; | 		}; | ||||||
| @ -1627,8 +1647,8 @@ | |||||||
| 			isa = XCBuildConfiguration; | 			isa = XCBuildConfiguration; | ||||||
| 			buildSettings = { | 			buildSettings = { | ||||||
| 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | ||||||
| 				CODE_SIGN_IDENTITY = "-"; | 				CODE_SIGN_IDENTITY = "Developer ID Application"; | ||||||
| 				CODE_SIGN_STYLE = Automatic; | 				CODE_SIGN_STYLE = Manual; | ||||||
| 				COMBINE_HIDPI_IMAGES = YES; | 				COMBINE_HIDPI_IMAGES = YES; | ||||||
| 				DEVELOPMENT_TEAM = Z72PRUAWF6; | 				DEVELOPMENT_TEAM = Z72PRUAWF6; | ||||||
| 				INFOPLIST_FILE = SecretKitTests/Info.plist; | 				INFOPLIST_FILE = SecretKitTests/Info.plist; | ||||||
| @ -1639,6 +1659,7 @@ | |||||||
| 				); | 				); | ||||||
| 				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; | 				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; | ||||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				PROVISIONING_PROFILE_SPECIFIER = ""; | ||||||
| 				SWIFT_VERSION = 5.0; | 				SWIFT_VERSION = 5.0; | ||||||
| 			}; | 			}; | ||||||
| 			name = Test; | 			name = Test; | ||||||
| @ -1677,7 +1698,8 @@ | |||||||
| 			isa = XCBuildConfiguration; | 			isa = XCBuildConfiguration; | ||||||
| 			buildSettings = { | 			buildSettings = { | ||||||
| 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | ||||||
| 				CODE_SIGN_IDENTITY = "-"; | 				CODE_SIGN_IDENTITY = "Developer ID Application"; | ||||||
|  | 				CODE_SIGN_STYLE = Manual; | ||||||
| 				COMBINE_HIDPI_IMAGES = YES; | 				COMBINE_HIDPI_IMAGES = YES; | ||||||
| 				DEVELOPMENT_TEAM = Z72PRUAWF6; | 				DEVELOPMENT_TEAM = Z72PRUAWF6; | ||||||
| 				INFOPLIST_FILE = SecretAgentKitTests/Info.plist; | 				INFOPLIST_FILE = SecretAgentKitTests/Info.plist; | ||||||
| @ -1688,6 +1710,7 @@ | |||||||
| 				); | 				); | ||||||
| 				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; | 				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; | ||||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				PROVISIONING_PROFILE_SPECIFIER = ""; | ||||||
| 				SWIFT_VERSION = 5.0; | 				SWIFT_VERSION = 5.0; | ||||||
| 			}; | 			}; | ||||||
| 			name = Test; | 			name = Test; | ||||||
| @ -1755,6 +1778,7 @@ | |||||||
| 			isa = XCBuildConfiguration; | 			isa = XCBuildConfiguration; | ||||||
| 			buildSettings = { | 			buildSettings = { | ||||||
| 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | ||||||
|  | 				CODE_SIGN_STYLE = Automatic; | ||||||
| 				COMBINE_HIDPI_IMAGES = YES; | 				COMBINE_HIDPI_IMAGES = YES; | ||||||
| 				DEVELOPMENT_TEAM = Z72PRUAWF6; | 				DEVELOPMENT_TEAM = Z72PRUAWF6; | ||||||
| 				INFOPLIST_FILE = SecretAgentKitTests/Info.plist; | 				INFOPLIST_FILE = SecretAgentKitTests/Info.plist; | ||||||
| @ -1773,6 +1797,7 @@ | |||||||
| 			isa = XCBuildConfiguration; | 			isa = XCBuildConfiguration; | ||||||
| 			buildSettings = { | 			buildSettings = { | ||||||
| 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; | ||||||
|  | 				CODE_SIGN_STYLE = Automatic; | ||||||
| 				COMBINE_HIDPI_IMAGES = YES; | 				COMBINE_HIDPI_IMAGES = YES; | ||||||
| 				DEVELOPMENT_TEAM = Z72PRUAWF6; | 				DEVELOPMENT_TEAM = Z72PRUAWF6; | ||||||
| 				INFOPLIST_FILE = SecretAgentKitTests/Info.plist; | 				INFOPLIST_FILE = SecretAgentKitTests/Info.plist; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user