diff --git a/Sources/AgentRequestParser/AgentRequestParser.swift b/Sources/AgentRequestParser/AgentRequestParser.swift
new file mode 100644
index 0000000..4681360
--- /dev/null
+++ b/Sources/AgentRequestParser/AgentRequestParser.swift
@@ -0,0 +1,17 @@
+import Foundation
+import SecretAgentKit
+
+//@objc public protocol RemoteAgentInputParserProtocol {
+//
+// func parse(data: Data, with reply: (SSHAgent.Request?, (any Error)?) -> Void)
+//
+//}
+//
+//class AgentInputParser: NSObject, RemoteAgentInputParserProtocol {
+//
+// /// This implements the example protocol. Replace the body of this class with the implementation of this service's protocol.
+// @objc func performCalculation(firstNumber: Int, secondNumber: Int, with reply: @escaping (Int) -> Void) {
+// let response = firstNumber + secondNumber
+// reply(response)
+// }
+//}
diff --git a/Sources/AgentRequestParser/Info.plist b/Sources/AgentRequestParser/Info.plist
new file mode 100644
index 0000000..c123a5d
--- /dev/null
+++ b/Sources/AgentRequestParser/Info.plist
@@ -0,0 +1,11 @@
+
+
+
+
+ XPCService
+
+ ServiceType
+ Application
+
+
+
diff --git a/Sources/AgentRequestParser/main.swift b/Sources/AgentRequestParser/main.swift
new file mode 100644
index 0000000..7f1c989
--- /dev/null
+++ b/Sources/AgentRequestParser/main.swift
@@ -0,0 +1,40 @@
+////
+//// main.swift
+//// AgentRequestParser
+////
+//// Created by Max Goedjen on 9/5/25.
+//// Copyright © 2025 Max Goedjen. All rights reserved.
+////
+//
+//import Foundation
+//
+//class ServiceDelegate: NSObject, NSXPCListenerDelegate {
+//
+// /// This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection.
+// func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
+//
+// // Configure the connection.
+// // First, set the interface that the exported object implements.
+// newConnection.exportedInterface = NSXPCInterface(with: (any AgentRequestParserProtocol).self)
+//
+// // Next, set the object that the connection exports. All messages sent on the connection to this service will be sent to the exported object to handle. The connection retains the exported object.
+// let exportedObject = AgentRequestParser()
+// newConnection.exportedObject = exportedObject
+//
+// // Resuming the connection allows the system to deliver more incoming messages.
+// newConnection.resume()
+//
+// // Returning true from this method tells the system that you have accepted this connection. If you want to reject the connection for some reason, call invalidate() on the connection and return false.
+// return true
+// }
+//}
+//
+//// Create the delegate for the service.
+//let delegate = ServiceDelegate()
+//
+//// Set up the one NSXPCListener for this service. It will handle all incoming connections.
+//let listener = NSXPCListener.service()
+//listener.delegate = delegate
+//
+//// Resuming the serviceListener starts this service. This method does not return.
+//listener.resume()
diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift
index 302fa3d..c287470 100644
--- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift
+++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift
@@ -31,49 +31,27 @@ public final class Agent: Sendable {
extension Agent {
- /// Handles an incoming request.
- /// - Parameters:
- /// - data: The data to handle.
- /// - provenance: The origin of the request.
- /// - Returns: A response data payload.
- public func handle(data: Data, provenance: SigningRequestProvenance) async throws -> Data {
- logger.debug("Agent handling new data")
- guard data.count > 4 else {
- throw InvalidDataProvidedError()
- }
- let requestTypeInt = data[4]
- guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else {
- logger.debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription) for unknown request type \(requestTypeInt)")
- return SSHAgent.ResponseType.agentFailure.data.lengthAndData
- }
- logger.debug("Agent handling request of type \(requestType.debugDescription)")
- let subData = Data(data[5...])
- let response = await handle(requestType: requestType, data: subData, provenance: provenance)
- return response
- }
-
- private func handle(requestType: SSHAgent.RequestType, data: Data, provenance: SigningRequestProvenance) async -> Data {
+ public func handle(request: SSHAgent.Request, provenance: SigningRequestProvenance) async -> Data {
// Depending on the launch context (such as after macOS update), the agent may need to reload secrets before acting
await reloadSecretsIfNeccessary()
var response = Data()
do {
- switch requestType {
+ switch request {
case .requestIdentities:
- response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data)
+ response.append(SSHAgent.Response.agentIdentitiesAnswer.data)
response.append(await identities())
- logger.debug("Agent returned \(SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)")
- case .signRequest:
- response.append(SSHAgent.ResponseType.agentSignResponse.data)
- response.append(try await sign(data: data, provenance: provenance))
- logger.debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)")
+ logger.debug("Agent returned \(SSHAgent.Response.agentIdentitiesAnswer.debugDescription)")
+ case .signRequest(let context):
+ response.append(SSHAgent.Response.agentSignResponse.data)
+ response.append(try await sign(data: context.dataToSign, keyBlob: context.keyBlob, provenance: provenance))
+ logger.debug("Agent returned \(SSHAgent.Response.agentSignResponse.debugDescription)")
default:
- logger.debug("Agent received valid request of type \(requestType.debugDescription), but not currently supported.")
- response.append(SSHAgent.ResponseType.agentFailure.data)
-
+ logger.debug("Agent received valid request of type \(request.debugDescription), but not currently supported.")
+ throw UnhandledRequestError()
}
} catch {
- response = SSHAgent.ResponseType.agentFailure.data
- logger.debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription)")
+ response = SSHAgent.Response.agentFailure.data
+ logger.debug("Agent returned \(SSHAgent.Response.agentFailure.debugDescription)")
}
return response.lengthAndData
}
@@ -113,27 +91,23 @@ extension Agent {
/// - data: The data to sign.
/// - provenance: A ``SecretKit.SigningRequestProvenance`` object describing the origin of the request.
/// - Returns: An OpenSSH formatted Data payload containing the signed data response.
- func sign(data: Data, provenance: SigningRequestProvenance) async throws -> Data {
- let reader = OpenSSHReader(data: data)
- let payloadHash = try reader.readNextChunk()
- let hash: Data
-
+ func sign(data: Data, keyBlob: Data, provenance: SigningRequestProvenance) async throws -> Data {
// Check if hash is actually an openssh certificate and reconstruct the public key if it is
- if let certificatePublicKey = await certificateHandler.publicKeyHash(from: payloadHash) {
- hash = certificatePublicKey
+ let resolvedBlob: Data
+ if let certificatePublicKey = await certificateHandler.publicKeyHash(from: keyBlob) {
+ resolvedBlob = certificatePublicKey
} else {
- hash = payloadHash
+ resolvedBlob = keyBlob
}
- guard let (secret, store) = await secret(matching: hash) else {
- logger.debug("Agent did not have a key matching \(hash as NSData)")
+ guard let (secret, store) = await secret(matching: resolvedBlob) else {
+ logger.debug("Agent did not have a key matching \(resolvedBlob as NSData)")
throw NoMatchingKeyError()
}
try await witness?.speakNowOrForeverHoldYourPeace(forAccessTo: secret, from: store, by: provenance)
- let dataToSign = try reader.readNextChunk()
- let rawRepresentation = try await store.sign(data: dataToSign, with: secret, for: provenance)
+ let rawRepresentation = try await store.sign(data: data, with: secret, for: provenance)
let signedData = signatureWriter.data(secret: secret, signature: rawRepresentation)
try await witness?.witness(accessTo: secret, from: store, by: provenance)
@@ -172,16 +146,16 @@ extension Agent {
extension Agent {
- struct InvalidDataProvidedError: Error {}
struct NoMatchingKeyError: Error {}
+ struct UnhandledRequestError: Error {}
}
-extension SSHAgent.ResponseType {
+extension SSHAgent.Response {
var data: Data {
var raw = self.rawValue
- return Data(bytes: &raw, count: UInt8.bitWidth/8)
+ return Data(bytes: &raw, count: MemoryLayout.size)
}
}
diff --git a/Sources/Packages/Sources/SecretAgentKit/FileHandleProtocols.swift b/Sources/Packages/Sources/SecretAgentKit/FileHandleProtocols.swift
index 3da0181..f95865e 100644
--- a/Sources/Packages/Sources/SecretAgentKit/FileHandleProtocols.swift
+++ b/Sources/Packages/Sources/SecretAgentKit/FileHandleProtocols.swift
@@ -1,26 +1,6 @@
import Foundation
-/// Protocol abstraction of the reading aspects of FileHandle.
-public protocol FileHandleReader: Sendable {
-
- /// Gets data that is available for reading.
- var availableData: Data { get }
- /// A file descriptor of the handle.
- var fileDescriptor: Int32 { get }
- /// The process ID of the process coonnected to the other end of the FileHandle.
- var pidOfConnectedProcess: Int32 { get }
-
-}
-
-/// Protocol abstraction of the writing aspects of FileHandle.
-public protocol FileHandleWriter: Sendable {
-
- /// Writes data to the handle.
- func write(_ data: Data)
-
-}
-
-extension FileHandle: FileHandleReader, FileHandleWriter {
+extension FileHandle {
public var pidOfConnectedProcess: Int32 {
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: MemoryLayout.size, alignment: 1)
diff --git a/Sources/Packages/Sources/SecretAgentKit/SSHAgentInputParser.swift b/Sources/Packages/Sources/SecretAgentKit/SSHAgentInputParser.swift
new file mode 100644
index 0000000..dc939cd
--- /dev/null
+++ b/Sources/Packages/Sources/SecretAgentKit/SSHAgentInputParser.swift
@@ -0,0 +1,76 @@
+import Foundation
+import OSLog
+import SecretKit
+
+public protocol SSHAgentInputParserProtocol: Sendable {
+ func parse(data: Data) async throws -> SSHAgent.Request
+}
+
+public struct SSHAgentInputParser: SSHAgentInputParserProtocol {
+
+ private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "InputParser")
+
+ public init() {
+
+ }
+
+ public func parse(data: Data) async throws -> SSHAgent.Request {
+ logger.debug("Parsing new data")
+ guard data.count > 4 else {
+ throw InvalidDataProvidedError()
+ }
+ let specifiedLength = (data[0..<4].bytes.unsafeLoad(as: UInt32.self).bigEndian) + 4
+ let rawRequestInt = data[4]
+ let remainingDataRange = 4.. SSHAgent.Request.SignatureRequestContext {
+ let reader = OpenSSHReader(data: data)
+ let keyBlob = try reader.readNextChunk()
+ let dataToSign = try reader.readNextChunk()
+ return SSHAgent.Request.SignatureRequestContext(keyBlob: keyBlob, dataToSign: dataToSign)
+ }
+
+}
+
+
+extension SSHAgentInputParser {
+
+ struct AgentUnknownRequestError: Error {}
+ struct AgentUnhandledRequestError: Error {}
+ struct InvalidDataProvidedError: Error {}
+
+}
diff --git a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift b/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift
index 30b4747..02b6454 100644
--- a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift
+++ b/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift
@@ -6,21 +6,39 @@ public enum SSHAgent {}
extension SSHAgent {
/// The type of the SSH Agent Request, as described in https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent#section-5.1
- public enum RequestType: UInt8, CustomDebugStringConvertible {
+ public enum Request: CustomDebugStringConvertible, Codable {
- case requestIdentities = 11
- case signRequest = 13
- case addIdentity = 17
- case removeIdentity = 18
- case removeAllIdentities = 19
- case addIDConstrained = 25
- case addSmartcardKey = 20
- case removeSmartcardKey = 21
- case lock = 22
- case unlock = 23
- case addSmartcardKeyConstrained = 26
- case protocolExtension = 27
+ case requestIdentities
+ case signRequest(SignatureRequestContext)
+ case addIdentity
+ case removeIdentity
+ case removeAllIdentities
+ case addIDConstrained
+ case addSmartcardKey
+ case removeSmartcardKey
+ case lock
+ case unlock
+ case addSmartcardKeyConstrained
+ case protocolExtension
+ case unknown(UInt8)
+ public var protocolID: UInt8 {
+ switch self {
+ case .requestIdentities: 11
+ case .signRequest: 13
+ case .addIdentity: 17
+ case .removeIdentity: 18
+ case .removeAllIdentities: 19
+ case .addIDConstrained: 25
+ case .addSmartcardKey: 20
+ case .removeSmartcardKey: 21
+ case .lock: 22
+ case .unlock: 23
+ case .addSmartcardKeyConstrained: 26
+ case .protocolExtension: 27
+ case .unknown(let value): value
+ }
+ }
public var debugDescription: String {
switch self {
@@ -36,12 +54,28 @@ extension SSHAgent {
case .unlock: "SSH_AGENTC_UNLOCK"
case .addSmartcardKeyConstrained: "SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED"
case .protocolExtension: "SSH_AGENTC_EXTENSION"
+ case .unknown: "UNKNOWN_MESSAGE"
}
}
+
+ public struct SignatureRequestContext: Sendable, Codable {
+ public let keyBlob: Data
+ public let dataToSign: Data
+
+ public init(keyBlob: Data, dataToSign: Data) {
+ self.keyBlob = keyBlob
+ self.dataToSign = dataToSign
+ }
+
+ public static var empty: SignatureRequestContext {
+ SignatureRequestContext(keyBlob: Data(), dataToSign: Data())
+ }
+ }
+
}
/// The type of the SSH Agent Response, as described in https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent#section-5.1
- public enum ResponseType: UInt8, CustomDebugStringConvertible {
+ public enum Response: UInt8, CustomDebugStringConvertible {
case agentFailure = 5
case agentSuccess = 6
diff --git a/Sources/Packages/Sources/SecretAgentKit/SigningRequestTracer.swift b/Sources/Packages/Sources/SecretAgentKit/SigningRequestTracer.swift
index aa8e295..3cfdd88 100644
--- a/Sources/Packages/Sources/SecretAgentKit/SigningRequestTracer.swift
+++ b/Sources/Packages/Sources/SecretAgentKit/SigningRequestTracer.swift
@@ -13,9 +13,8 @@ extension SigningRequestTracer {
/// Generates a ``SecretKit.SigningRequestProvenance`` from a ``FileHandleReader``.
/// - Parameter fileHandleReader: The reader involved in processing the request.
/// - Returns: A ``SecretKit.SigningRequestProvenance`` describing the origin of the request.
- func provenance(from fileHandleReader: FileHandleReader) -> SigningRequestProvenance {
- let firstInfo = process(from: fileHandleReader.pidOfConnectedProcess)
-
+ func provenance(from fileHandle: FileHandle) -> SigningRequestProvenance {
+ let firstInfo = process(from: fileHandle.pidOfConnectedProcess)
var provenance = SigningRequestProvenance(root: firstInfo)
while NSRunningApplication(processIdentifier: provenance.origin.pid) == nil && provenance.origin.parentPID != nil {
provenance.chain.append(process(from: provenance.origin.parentPID!))
diff --git a/Sources/SecretAgent/AppDelegate.swift b/Sources/SecretAgent/AppDelegate.swift
index ee4b799..89d9df7 100644
--- a/Sources/SecretAgent/AppDelegate.swift
+++ b/Sources/SecretAgent/AppDelegate.swift
@@ -36,9 +36,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
Task {
for await session in socketController.sessions {
Task {
+ let inputParser = SSHAgentInputParser()
do {
for await message in session.messages {
- let agentResponse = try await agent.handle(data: message, provenance: session.provenance)
+ let request = try await inputParser.parse(data: message)
+ let agentResponse = await agent.handle(request: request, provenance: session.provenance)
try await session.write(agentResponse)
}
} catch {
diff --git a/Sources/SecretAgent/XPCInputParser.swift b/Sources/SecretAgent/XPCInputParser.swift
new file mode 100644
index 0000000..50bb7f0
--- /dev/null
+++ b/Sources/SecretAgent/XPCInputParser.swift
@@ -0,0 +1,10 @@
+import Foundation
+import SecretAgentKit
+
+struct XPCAgentInputParser: SSHAgentInputParserProtocol {
+
+ func parse(data: Data) async throws -> SSHAgent.Request {
+ fatalError()
+ }
+
+}
diff --git a/Sources/Secretive.xcodeproj/project.pbxproj b/Sources/Secretive.xcodeproj/project.pbxproj
index e202ef7..c4d0ae4 100644
--- a/Sources/Secretive.xcodeproj/project.pbxproj
+++ b/Sources/Secretive.xcodeproj/project.pbxproj
@@ -30,6 +30,11 @@
501577DA2E6BC5F3004A37D0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501577D62E6BC5F3004A37D0 /* main.swift */; };
501577DB2E6BC5F3004A37D0 /* ReleasesDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501577D72E6BC5F3004A37D0 /* ReleasesDownloader.swift */; };
501577DF2E6BC647004A37D0 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501577DE2E6BC647004A37D0 /* Brief */; };
+ 501578032E6C019F004A37D0 /* AgentRequestParser.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 501577F82E6C019F004A37D0 /* AgentRequestParser.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ 5015780F2E6C01F1004A37D0 /* AgentRequestParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501578092E6C01F1004A37D0 /* AgentRequestParser.swift */; };
+ 501578112E6C01F1004A37D0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5015780C2E6C01F1004A37D0 /* main.swift */; };
+ 501578132E6C0479004A37D0 /* XPCInputParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501578122E6C0479004A37D0 /* XPCInputParser.swift */; };
+ 501578152E6C0558004A37D0 /* SecretAgentKit in Frameworks */ = {isa = PBXBuildFile; productRef = 501578142E6C0558004A37D0 /* SecretAgentKit */; };
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
504788EC2E680DC800B4556F /* URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788EB2E680DC400B4556F /* URLs.swift */; };
504788F22E681F3A00B4556F /* Instructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F12E681F3A00B4556F /* Instructions.swift */; };
@@ -97,6 +102,13 @@
remoteGlobalIDString = 501577BC2E6BC5B4004A37D0;
remoteInfo = ReleasesDownloader;
};
+ 501578012E6C019F004A37D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 501577F72E6C019F004A37D0;
+ remoteInfo = AgentRequestParser;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -106,6 +118,7 @@
dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices";
dstSubfolderSpec = 16;
files = (
+ 501578032E6C019F004A37D0 /* AgentRequestParser.xpc in Embed XPC Services */,
501577C82E6BC5B4004A37D0 /* ReleasesDownloader.xpc in Embed XPC Services */,
);
name = "Embed XPC Services";
@@ -166,6 +179,11 @@
501577D52E6BC5F3004A37D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
501577D62E6BC5F3004A37D0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
501577D72E6BC5F3004A37D0 /* ReleasesDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleasesDownloader.swift; sourceTree = ""; };
+ 501577F82E6C019F004A37D0 /* AgentRequestParser.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = AgentRequestParser.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
+ 501578092E6C01F1004A37D0 /* AgentRequestParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentRequestParser.swift; sourceTree = ""; };
+ 5015780B2E6C01F1004A37D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 5015780C2E6C01F1004A37D0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
+ 501578122E6C0479004A37D0 /* XPCInputParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XPCInputParser.swift; sourceTree = ""; };
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = ""; };
504788EB2E680DC400B4556F /* URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLs.swift; sourceTree = ""; };
504788F12E681F3A00B4556F /* Instructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instructions.swift; sourceTree = ""; };
@@ -221,6 +239,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 501577F52E6C019F004A37D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 501578152E6C0558004A37D0 /* SecretAgentKit in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
50617D7C23FCE48D0099B055 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -265,6 +291,16 @@
path = ReleasesDownloader;
sourceTree = "";
};
+ 5015780D2E6C01F1004A37D0 /* AgentRequestParser */ = {
+ isa = PBXGroup;
+ children = (
+ 501578092E6C01F1004A37D0 /* AgentRequestParser.swift */,
+ 5015780B2E6C01F1004A37D0 /* Info.plist */,
+ 5015780C2E6C01F1004A37D0 /* main.swift */,
+ );
+ path = AgentRequestParser;
+ sourceTree = "";
+ };
504788ED2E681EB200B4556F /* Styles */ = {
isa = PBXGroup;
children = (
@@ -321,6 +357,7 @@
5003EF39278005C800DF2006 /* Packages */,
50617D8123FCE48E0099B055 /* Secretive */,
50A3B78B24026B7500D209EA /* SecretAgent */,
+ 5015780D2E6C01F1004A37D0 /* AgentRequestParser */,
501577D92E6BC5F3004A37D0 /* ReleasesDownloader */,
508A58AF241E144C0069DC07 /* Config */,
50617D8023FCE48E0099B055 /* Products */,
@@ -334,6 +371,7 @@
50617D7F23FCE48E0099B055 /* Secretive.app */,
50A3B78A24026B7500D209EA /* SecretAgent.app */,
501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */,
+ 501577F82E6C019F004A37D0 /* AgentRequestParser.xpc */,
);
name = Products;
sourceTree = "";
@@ -411,6 +449,7 @@
children = (
50020BAF24064869003D4025 /* AppDelegate.swift */,
5018F54E24064786002EB505 /* Notifier.swift */,
+ 501578122E6C0479004A37D0 /* XPCInputParser.swift */,
50A3B79524026B7600D209EA /* Main.storyboard */,
50A3B79824026B7600D209EA /* Info.plist */,
508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */,
@@ -451,6 +490,26 @@
productReference = 501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */;
productType = "com.apple.product-type.xpc-service";
};
+ 501577F72E6C019F004A37D0 /* AgentRequestParser */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 501578052E6C019F004A37D0 /* Build configuration list for PBXNativeTarget "AgentRequestParser" */;
+ buildPhases = (
+ 501577F42E6C019F004A37D0 /* Sources */,
+ 501577F52E6C019F004A37D0 /* Frameworks */,
+ 501577F62E6C019F004A37D0 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = AgentRequestParser;
+ packageProductDependencies = (
+ 501578142E6C0558004A37D0 /* SecretAgentKit */,
+ );
+ productName = AgentRequestParser;
+ productReference = 501577F82E6C019F004A37D0 /* AgentRequestParser.xpc */;
+ productType = "com.apple.product-type.xpc-service";
+ };
50617D7E23FCE48D0099B055 /* Secretive */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50617D9D23FCE48E0099B055 /* Build configuration list for PBXNativeTarget "Secretive" */;
@@ -467,6 +526,7 @@
dependencies = (
50142167278126B500BBAA70 /* PBXTargetDependency */,
501577C72E6BC5B4004A37D0 /* PBXTargetDependency */,
+ 501578022E6C019F004A37D0 /* PBXTargetDependency */,
);
name = Secretive;
packageProductDependencies = (
@@ -521,6 +581,9 @@
501577BC2E6BC5B4004A37D0 = {
CreatedOnToolsVersion = 26.0;
};
+ 501577F72E6C019F004A37D0 = {
+ CreatedOnToolsVersion = 26.0;
+ };
50617D7E23FCE48D0099B055 = {
CreatedOnToolsVersion = 11.3;
};
@@ -554,6 +617,7 @@
50617D7E23FCE48D0099B055 /* Secretive */,
50A3B78924026B7500D209EA /* SecretAgent */,
501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */,
+ 501577F72E6C019F004A37D0 /* AgentRequestParser */,
);
};
/* End PBXProject section */
@@ -566,6 +630,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 501577F62E6C019F004A37D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
50617D7D23FCE48D0099B055 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -602,6 +673,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 501577F42E6C019F004A37D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5015780F2E6C01F1004A37D0 /* AgentRequestParser.swift in Sources */,
+ 501578112E6C01F1004A37D0 /* main.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
50617D7B23FCE48D0099B055 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -647,6 +727,7 @@
files = (
50020BB024064869003D4025 /* AppDelegate.swift in Sources */,
5018F54F24064786002EB505 /* Notifier.swift in Sources */,
+ 501578132E6C0479004A37D0 /* XPCInputParser.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -673,6 +754,11 @@
target = 501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */;
targetProxy = 501577D32E6BC5DD004A37D0 /* PBXContainerItemProxy */;
};
+ 501578022E6C019F004A37D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 501577F72E6C019F004A37D0 /* AgentRequestParser */;
+ targetProxy = 501578012E6C019F004A37D0 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -714,7 +800,7 @@
INFOPLIST_KEY_CFBundleDisplayName = ReleasesDownloader;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved.";
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MACOSX_DEPLOYMENT_TARGET = 26.0;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.ReleasesDownloader;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -756,7 +842,7 @@
INFOPLIST_KEY_CFBundleDisplayName = ReleasesDownloader;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved.";
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MACOSX_DEPLOYMENT_TARGET = 26.0;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.ReleasesDownloader;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -798,7 +884,7 @@
INFOPLIST_KEY_CFBundleDisplayName = ReleasesDownloader;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved.";
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MACOSX_DEPLOYMENT_TARGET = 26.0;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.ReleasesDownloader;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -812,6 +898,98 @@
};
name = Release;
};
+ 501578062E6C019F004A37D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = Z72PRUAWF6;
+ ENABLE_APP_SANDBOX = YES;
+ ENABLE_HARDENED_RUNTIME = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = AgentRequestParser/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = AgentRequestParser;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved.";
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.AgentRequestParser;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ REGISTER_APP_GROUPS = YES;
+ SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 501578072E6C019F004A37D0 /* Test */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ ENABLE_APP_SANDBOX = YES;
+ ENABLE_HARDENED_RUNTIME = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = AgentRequestParser/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = AgentRequestParser;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved.";
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.AgentRequestParser;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ REGISTER_APP_GROUPS = YES;
+ SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Test;
+ };
+ 501578082E6C019F004A37D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CODE_SIGN_IDENTITY = "Developer ID Application";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = Z72PRUAWF6;
+ ENABLE_APP_SANDBOX = YES;
+ ENABLE_HARDENED_RUNTIME = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = AgentRequestParser/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = AgentRequestParser;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved.";
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.AgentRequestParser;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ REGISTER_APP_GROUPS = YES;
+ SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
50617D9B23FCE48E0099B055 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
@@ -1262,6 +1440,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 501578052E6C019F004A37D0 /* Build configuration list for PBXNativeTarget "AgentRequestParser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 501578062E6C019F004A37D0 /* Debug */,
+ 501578072E6C019F004A37D0 /* Test */,
+ 501578082E6C019F004A37D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
50617D7A23FCE48D0099B055 /* Build configuration list for PBXProject "Secretive" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -1335,6 +1523,10 @@
isa = XCSwiftPackageProductDependency;
productName = Brief;
};
+ 501578142E6C0558004A37D0 /* SecretAgentKit */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = SecretAgentKit;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50617D7723FCE48D0099B055 /* Project object */;