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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import SecretAgentKit
|
||||||
|
|
||||||
|
class StubFileHandleWriter: FileHandleWriter {
|
||||||
|
|
||||||
|
var data = Data()
|
||||||
|
|
||||||
|
func write(_ data: Data) {
|
||||||
|
self.data.append(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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