mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-09-15 08:50:57 +00:00
Move downloader and socket input parsing to xpc services (#675)
* XPC updater POC * WIP * obo * WIP * Working * . * . * . * Cleanup * Cleanup * Throw restrict * Remove dead protocol. * . * Fix ECDSA test. * Scripts
This commit is contained in:
parent
cf5ae49ebc
commit
63b42bd9df
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -24,6 +24,8 @@ jobs:
|
|||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_26.0.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_26.0.app
|
||||||
- name: Test
|
- name: Test
|
||||||
|
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme PackageTests test
|
||||||
|
# SPM doesn't seem to pick up on the tests currently?
|
||||||
run: swift test --build-system swiftbuild --package-path Sources/Packages
|
run: swift test --build-system swiftbuild --package-path Sources/Packages
|
||||||
build:
|
build:
|
||||||
permissions:
|
permissions:
|
||||||
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -12,6 +12,8 @@ jobs:
|
|||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_26.0.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_26.0.app
|
||||||
- name: Test Main Packages
|
- name: Test Main Packages
|
||||||
run: swift test --build-system swiftbuild --package-path Sources/Packages
|
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme PackageTests test
|
||||||
|
# SPM doesn't seem to pick up on the tests currently?
|
||||||
|
# run: swift test --build-system swiftbuild --package-path Sources/Packages
|
||||||
- name: Test SecretKit Packages
|
- name: Test SecretKit Packages
|
||||||
run: swift test --build-system swiftbuild
|
run: swift test --build-system swiftbuild
|
||||||
|
11
Sources/AgentRequestParser/Info.plist
Normal file
11
Sources/AgentRequestParser/Info.plist
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>XPCService</key>
|
||||||
|
<dict>
|
||||||
|
<key>ServiceType</key>
|
||||||
|
<string>Application</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
55
Sources/AgentRequestParser/main.swift
Normal file
55
Sources/AgentRequestParser/main.swift
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import XPC
|
||||||
|
import SecretAgentKit
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent.AgentRequestParser", category: "Parser")
|
||||||
|
|
||||||
|
func handleRequest(_ request: XPCListener.IncomingSessionRequest) -> XPCListener.IncomingSessionRequest.Decision {
|
||||||
|
logger.log("Parser received inbound request")
|
||||||
|
return request.accept { xpcMessage in
|
||||||
|
xpcMessage.handoffReply(to: .global(qos: .userInteractive)) {
|
||||||
|
logger.log("Parser accepted inbound request")
|
||||||
|
handle(with: xpcMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle(with xpcMessage: XPCReceivedMessage) {
|
||||||
|
do {
|
||||||
|
let parser = SSHAgentInputParser()
|
||||||
|
let result = try parser.parse(data: xpcMessage.wrappedDecode())
|
||||||
|
logger.log("Parser parsed message as type \(result.debugDescription)")
|
||||||
|
xpcMessage.reply(result)
|
||||||
|
} catch {
|
||||||
|
logger.error("Parser failed with error \(error)")
|
||||||
|
xpcMessage.reply(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension XPCReceivedMessage {
|
||||||
|
|
||||||
|
func wrappedDecode() throws(SSHAgentInputParser.AgentParsingError) -> Data {
|
||||||
|
do {
|
||||||
|
return try decode(as: Data.self)
|
||||||
|
} catch {
|
||||||
|
throw SSHAgentInputParser.AgentParsingError.invalidData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if #available(macOS 26.0, *) {
|
||||||
|
_ = try XPCListener(
|
||||||
|
service: "com.maxgoedjen.Secretive.AgentRequestParser",
|
||||||
|
requirement: .isFromSameTeam(),
|
||||||
|
incomingSessionHandler: handleRequest(_:)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
_ = try XPCListener(service: "com.maxgoedjen.Secretive.AgentRequestParser", incomingSessionHandler: handleRequest(_:))
|
||||||
|
}
|
||||||
|
logger.log("Parser initialized")
|
||||||
|
dispatchMain()
|
||||||
|
} catch {
|
||||||
|
logger.error("Failed to create parser, error: \(error)")
|
||||||
|
}
|
@ -13,12 +13,24 @@
|
|||||||
},
|
},
|
||||||
"testTargets" : [
|
"testTargets" : [
|
||||||
{
|
{
|
||||||
"enabled" : false,
|
|
||||||
"parallelizable" : true,
|
|
||||||
"target" : {
|
"target" : {
|
||||||
"containerPath" : "container:Secretive.xcodeproj",
|
"containerPath" : "container:Packages",
|
||||||
"identifier" : "50617D9323FCE48E0099B055",
|
"identifier" : "BriefTests",
|
||||||
"name" : "SecretiveTests"
|
"name" : "BriefTests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target" : {
|
||||||
|
"containerPath" : "container:Packages",
|
||||||
|
"identifier" : "SecretKitTests",
|
||||||
|
"name" : "SecretKitTests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target" : {
|
||||||
|
"containerPath" : "container:Packages",
|
||||||
|
"identifier" : "SecretAgentKitTests",
|
||||||
|
"name" : "SecretAgentKitTests"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -21,13 +21,16 @@ let package = Package(
|
|||||||
targets: ["SmartCardSecretKit"]),
|
targets: ["SmartCardSecretKit"]),
|
||||||
.library(
|
.library(
|
||||||
name: "SecretAgentKit",
|
name: "SecretAgentKit",
|
||||||
targets: ["SecretAgentKit"]),
|
targets: ["SecretAgentKit", "XPCWrappers"]),
|
||||||
.library(
|
.library(
|
||||||
name: "SecretAgentKitHeaders",
|
name: "SecretAgentKitHeaders",
|
||||||
targets: ["SecretAgentKitHeaders"]),
|
targets: ["SecretAgentKitHeaders"]),
|
||||||
.library(
|
.library(
|
||||||
name: "Brief",
|
name: "Brief",
|
||||||
targets: ["Brief"]),
|
targets: ["Brief"]),
|
||||||
|
.library(
|
||||||
|
name: "XPCWrappers",
|
||||||
|
targets: ["XPCWrappers"]),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
],
|
],
|
||||||
@ -70,7 +73,7 @@ let package = Package(
|
|||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "Brief",
|
name: "Brief",
|
||||||
dependencies: [],
|
dependencies: ["XPCWrappers"],
|
||||||
resources: [localization],
|
resources: [localization],
|
||||||
swiftSettings: swiftSettings,
|
swiftSettings: swiftSettings,
|
||||||
),
|
),
|
||||||
@ -78,6 +81,10 @@ let package = Package(
|
|||||||
name: "BriefTests",
|
name: "BriefTests",
|
||||||
dependencies: ["Brief"],
|
dependencies: ["Brief"],
|
||||||
),
|
),
|
||||||
|
.target(
|
||||||
|
name: "XPCWrappers",
|
||||||
|
swiftSettings: swiftSettings,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Observation
|
import Observation
|
||||||
|
import XPCWrappers
|
||||||
|
|
||||||
/// A concrete implementation of ``UpdaterProtocol`` which considers the current release and OS version.
|
/// A concrete implementation of ``UpdaterProtocol`` which considers the current release and OS version.
|
||||||
@Observable public final class Updater: UpdaterProtocol, Sendable {
|
@Observable public final class Updater: UpdaterProtocol, Sendable {
|
||||||
@ -33,27 +34,25 @@ import Observation
|
|||||||
) {
|
) {
|
||||||
self.osVersion = osVersion
|
self.osVersion = osVersion
|
||||||
self.currentVersion = currentVersion
|
self.currentVersion = currentVersion
|
||||||
|
Task {
|
||||||
if checkOnLaunch {
|
if checkOnLaunch {
|
||||||
// Don't do a launch check if the user hasn't seen the setup prompt explaining updater yet.
|
try await checkForUpdates()
|
||||||
Task {
|
|
||||||
await checkForUpdates()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Task {
|
|
||||||
while !Task.isCancelled {
|
while !Task.isCancelled {
|
||||||
try? await Task.sleep(for: .seconds(Int(checkFrequency)))
|
try? await Task.sleep(for: .seconds(Int(checkFrequency)))
|
||||||
await checkForUpdates()
|
try await checkForUpdates()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manually trigger an update check.
|
/// Manually trigger an update check.
|
||||||
public func checkForUpdates() async {
|
public func checkForUpdates() async throws {
|
||||||
guard let (data, _) = try? await URLSession.shared.data(from: Constants.updateURL) else { return }
|
let session = try XPCTypedSession<[Release], Never>(serviceName: "com.maxgoedjen.Secretive.ReleasesDownloader")
|
||||||
guard let releases = try? JSONDecoder().decode([Release].self, from: data) else { return }
|
await evaluate(releases: try await session.send())
|
||||||
await evaluate(releases: releases)
|
session.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Ignores a specified release. `update` will be nil if the user has ignored the latest available release.
|
/// Ignores a specified release. `update` will be nil if the user has ignored the latest available release.
|
||||||
/// - Parameter release: The release to ignore.
|
/// - Parameter release: The release to ignore.
|
||||||
public func ignore(release: Release) async {
|
public func ignore(release: Release) async {
|
||||||
@ -100,11 +99,3 @@ extension Updater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Updater {
|
|
||||||
|
|
||||||
enum Constants {
|
|
||||||
static let updateURL = URL(string: "https://api.github.com/repos/maxgoedjen/secretive/releases")!
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -31,49 +31,29 @@ public final class Agent: Sendable {
|
|||||||
|
|
||||||
extension Agent {
|
extension Agent {
|
||||||
|
|
||||||
/// Handles an incoming request.
|
public func handle(request: SSHAgent.Request, provenance: SigningRequestProvenance) async -> Data {
|
||||||
/// - 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 {
|
|
||||||
// Depending on the launch context (such as after macOS update), the agent may need to reload secrets before acting
|
// Depending on the launch context (such as after macOS update), the agent may need to reload secrets before acting
|
||||||
await reloadSecretsIfNeccessary()
|
await reloadSecretsIfNeccessary()
|
||||||
var response = Data()
|
var response = Data()
|
||||||
do {
|
do {
|
||||||
switch requestType {
|
switch request {
|
||||||
case .requestIdentities:
|
case .requestIdentities:
|
||||||
response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data)
|
response.append(SSHAgent.Response.agentIdentitiesAnswer.data)
|
||||||
response.append(await identities())
|
response.append(await identities())
|
||||||
logger.debug("Agent returned \(SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)")
|
logger.debug("Agent returned \(SSHAgent.Response.agentIdentitiesAnswer.debugDescription)")
|
||||||
case .signRequest:
|
case .signRequest(let context):
|
||||||
response.append(SSHAgent.ResponseType.agentSignResponse.data)
|
response.append(SSHAgent.Response.agentSignResponse.data)
|
||||||
response.append(try await sign(data: data, provenance: provenance))
|
response.append(try await sign(data: context.dataToSign, keyBlob: context.keyBlob, provenance: provenance))
|
||||||
logger.debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)")
|
logger.debug("Agent returned \(SSHAgent.Response.agentSignResponse.debugDescription)")
|
||||||
|
case .unknown(let value):
|
||||||
|
logger.error("Agent received unknown request of type \(value).")
|
||||||
default:
|
default:
|
||||||
logger.debug("Agent received valid request of type \(requestType.debugDescription), but not currently supported.")
|
logger.debug("Agent received valid request of type \(request.debugDescription), but not currently supported.")
|
||||||
response.append(SSHAgent.ResponseType.agentFailure.data)
|
throw UnhandledRequestError()
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
response = SSHAgent.ResponseType.agentFailure.data
|
response = SSHAgent.Response.agentFailure.data
|
||||||
logger.debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription)")
|
logger.debug("Agent returned \(SSHAgent.Response.agentFailure.debugDescription)")
|
||||||
}
|
}
|
||||||
return response.lengthAndData
|
return response.lengthAndData
|
||||||
}
|
}
|
||||||
@ -113,27 +93,16 @@ extension Agent {
|
|||||||
/// - data: The data to sign.
|
/// - data: The data to sign.
|
||||||
/// - provenance: A ``SecretKit.SigningRequestProvenance`` object describing the origin of the request.
|
/// - provenance: A ``SecretKit.SigningRequestProvenance`` object describing the origin of the request.
|
||||||
/// - Returns: An OpenSSH formatted Data payload containing the signed data response.
|
/// - Returns: An OpenSSH formatted Data payload containing the signed data response.
|
||||||
func sign(data: Data, provenance: SigningRequestProvenance) async throws -> Data {
|
func sign(data: Data, keyBlob: Data, provenance: SigningRequestProvenance) async throws -> Data {
|
||||||
let reader = OpenSSHReader(data: data)
|
guard let (secret, store) = await secret(matching: keyBlob) else {
|
||||||
let payloadHash = try reader.readNextChunk()
|
let keyBlobHex = keyBlob.compactMap { ("0" + String($0, radix: 16, uppercase: false)).suffix(2) }.joined()
|
||||||
let hash: Data
|
logger.debug("Agent did not have a key matching \(keyBlobHex)")
|
||||||
|
|
||||||
// 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
|
|
||||||
} else {
|
|
||||||
hash = payloadHash
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let (secret, store) = await secret(matching: hash) else {
|
|
||||||
logger.debug("Agent did not have a key matching \(hash as NSData)")
|
|
||||||
throw NoMatchingKeyError()
|
throw NoMatchingKeyError()
|
||||||
}
|
}
|
||||||
|
|
||||||
try await witness?.speakNowOrForeverHoldYourPeace(forAccessTo: secret, from: store, by: provenance)
|
try await witness?.speakNowOrForeverHoldYourPeace(forAccessTo: secret, from: store, by: provenance)
|
||||||
|
|
||||||
let dataToSign = try reader.readNextChunk()
|
let rawRepresentation = try await store.sign(data: data, with: secret, for: provenance)
|
||||||
let rawRepresentation = try await store.sign(data: dataToSign, with: secret, for: provenance)
|
|
||||||
let signedData = signatureWriter.data(secret: secret, signature: rawRepresentation)
|
let signedData = signatureWriter.data(secret: secret, signature: rawRepresentation)
|
||||||
|
|
||||||
try await witness?.witness(accessTo: secret, from: store, by: provenance)
|
try await witness?.witness(accessTo: secret, from: store, by: provenance)
|
||||||
@ -172,16 +141,16 @@ extension Agent {
|
|||||||
|
|
||||||
extension Agent {
|
extension Agent {
|
||||||
|
|
||||||
struct InvalidDataProvidedError: Error {}
|
|
||||||
struct NoMatchingKeyError: Error {}
|
struct NoMatchingKeyError: Error {}
|
||||||
|
struct UnhandledRequestError: Error {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SSHAgent.ResponseType {
|
extension SSHAgent.Response {
|
||||||
|
|
||||||
var data: Data {
|
var data: Data {
|
||||||
var raw = self.rawValue
|
var raw = self.rawValue
|
||||||
return Data(bytes: &raw, count: UInt8.bitWidth/8)
|
return Data(bytes: &raw, count: MemoryLayout<UInt8>.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import Foundation
|
|||||||
extension FileHandle {
|
extension FileHandle {
|
||||||
|
|
||||||
public var pidOfConnectedProcess: Int32 {
|
public var pidOfConnectedProcess: Int32 {
|
||||||
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
|
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: MemoryLayout<Int32>.size, alignment: 1)
|
||||||
var len = socklen_t(MemoryLayout<Int32>.size)
|
var len = socklen_t(MemoryLayout<Int32>.size)
|
||||||
getsockopt(fileDescriptor, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len)
|
getsockopt(fileDescriptor, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len)
|
||||||
return pidPointer.load(as: Int32.self)
|
return pidPointer.load(as: Int32.self)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import OSLog
|
import OSLog
|
||||||
|
import SecretKit
|
||||||
|
|
||||||
/// Manages storage and lookup for OpenSSH certificates.
|
/// Manages storage and lookup for OpenSSH certificates.
|
||||||
public actor OpenSSHCertificateHandler: Sendable {
|
public actor OpenSSHCertificateHandler: Sendable {
|
||||||
@ -25,33 +26,6 @@ public actor OpenSSHCertificateHandler: Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconstructs a public key from a ``Data``, if that ``Data`` contains an OpenSSH certificate hash. Currently only ecdsa certificates are supported
|
|
||||||
/// - Parameter certBlock: The openssh certificate to extract the public key from
|
|
||||||
/// - Returns: A ``Data`` object containing the public key in OpenSSH wire format if the ``Data`` is an OpenSSH certificate hash, otherwise nil.
|
|
||||||
public func publicKeyHash(from hash: Data) -> Data? {
|
|
||||||
let reader = OpenSSHReader(data: hash)
|
|
||||||
do {
|
|
||||||
let certType = String(decoding: try reader.readNextChunk(), as: UTF8.self)
|
|
||||||
switch certType {
|
|
||||||
case "ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
|
||||||
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
|
||||||
"ecdsa-sha2-nistp521-cert-v01@openssh.com":
|
|
||||||
_ = try reader.readNextChunk() // nonce
|
|
||||||
let curveIdentifier = try reader.readNextChunk()
|
|
||||||
let publicKey = try reader.readNextChunk()
|
|
||||||
|
|
||||||
let openSSHIdentifier = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "")
|
|
||||||
return openSSHIdentifier.lengthAndData +
|
|
||||||
curveIdentifier.lengthAndData +
|
|
||||||
publicKey.lengthAndData
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
||||||
/// - Parameter secret: The secret to search for a certificate with
|
/// - Parameter secret: The secret to search for a certificate with
|
||||||
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
|
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
|
@ -1,42 +1,47 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Reads OpenSSH protocol data.
|
/// Reads OpenSSH protocol data.
|
||||||
public final class OpenSSHReader {
|
final class OpenSSHReader {
|
||||||
|
|
||||||
var remaining: Data
|
var remaining: Data
|
||||||
|
|
||||||
/// Initialize the reader with an OpenSSH data payload.
|
/// Initialize the reader with an OpenSSH data payload.
|
||||||
/// - Parameter data: The data to read.
|
/// - Parameter data: The data to read.
|
||||||
public init(data: Data) {
|
init(data: Data) {
|
||||||
remaining = Data(data)
|
remaining = Data(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the next chunk of data from the playload.
|
/// Reads the next chunk of data from the playload.
|
||||||
/// - Returns: The next chunk of data.
|
/// - Returns: The next chunk of data.
|
||||||
public func readNextChunk(convertEndianness: Bool = true) throws -> Data {
|
func readNextChunk(convertEndianness: Bool = true) throws(OpenSSHReaderError) -> Data {
|
||||||
let littleEndianLength = try readNextBytes(as: UInt32.self)
|
let littleEndianLength = try readNextBytes(as: UInt32.self)
|
||||||
let length = convertEndianness ? Int(littleEndianLength.bigEndian) : Int(littleEndianLength)
|
let length = convertEndianness ? Int(littleEndianLength.bigEndian) : Int(littleEndianLength)
|
||||||
guard remaining.count >= length else { throw EndOfData() }
|
guard remaining.count >= length else { throw .beyondBounds }
|
||||||
let dataRange = 0..<length
|
let dataRange = 0..<length
|
||||||
let ret = Data(remaining[dataRange])
|
let ret = Data(remaining[dataRange])
|
||||||
remaining.removeSubrange(dataRange)
|
remaining.removeSubrange(dataRange)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
public func readNextBytes<T>(as: T.Type) throws -> T {
|
func readNextBytes<T>(as: T.Type) throws(OpenSSHReaderError) -> T {
|
||||||
let size = MemoryLayout<T>.size
|
let size = MemoryLayout<T>.size
|
||||||
guard remaining.count >= size else { throw EndOfData() }
|
guard remaining.count >= size else { throw .beyondBounds }
|
||||||
let lengthRange = 0..<size
|
let lengthRange = 0..<size
|
||||||
let lengthChunk = remaining[lengthRange]
|
let lengthChunk = remaining[lengthRange]
|
||||||
remaining.removeSubrange(lengthRange)
|
remaining.removeSubrange(lengthRange)
|
||||||
return lengthChunk.bytes.unsafeLoad(as: T.self)
|
return lengthChunk.bytes.unsafeLoad(as: T.self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readNextChunkAsString(convertEndianness: Bool = true) throws(OpenSSHReaderError) -> String {
|
||||||
public func readNextChunkAsString() throws -> String {
|
try String(decoding: readNextChunk(convertEndianness: convertEndianness), as: UTF8.self)
|
||||||
try String(decoding: readNextChunk(), as: UTF8.self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct EndOfData: Error {}
|
func readNextChunkAsSubReader(convertEndianness: Bool = true) throws(OpenSSHReaderError) -> OpenSSHReader {
|
||||||
|
OpenSSHReader(data: try readNextChunk(convertEndianness: convertEndianness))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum OpenSSHReaderError: Error, Codable {
|
||||||
|
case beyondBounds
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
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) throws(AgentParsingError) -> SSHAgent.Request {
|
||||||
|
logger.debug("Parsing new data")
|
||||||
|
guard data.count > 4 else {
|
||||||
|
throw .invalidData
|
||||||
|
}
|
||||||
|
let specifiedLength = (data[0..<4].bytes.unsafeLoad(as: UInt32.self).bigEndian) + 4
|
||||||
|
let rawRequestInt = data[4]
|
||||||
|
let remainingDataRange = 5..<min(Int(specifiedLength), data.count)
|
||||||
|
lazy var body: Data = { Data(data[remainingDataRange]) }()
|
||||||
|
switch rawRequestInt {
|
||||||
|
case SSHAgent.Request.requestIdentities.protocolID:
|
||||||
|
return .requestIdentities
|
||||||
|
case SSHAgent.Request.signRequest(.empty).protocolID:
|
||||||
|
do {
|
||||||
|
return .signRequest(try signatureRequestContext(from: body))
|
||||||
|
} catch {
|
||||||
|
throw .openSSHReader(error)
|
||||||
|
}
|
||||||
|
case SSHAgent.Request.addIdentity.protocolID:
|
||||||
|
return .addIdentity
|
||||||
|
case SSHAgent.Request.removeIdentity.protocolID:
|
||||||
|
return .removeIdentity
|
||||||
|
case SSHAgent.Request.removeAllIdentities.protocolID:
|
||||||
|
return .removeAllIdentities
|
||||||
|
case SSHAgent.Request.addIDConstrained.protocolID:
|
||||||
|
return .addIDConstrained
|
||||||
|
case SSHAgent.Request.addSmartcardKey.protocolID:
|
||||||
|
return .addSmartcardKey
|
||||||
|
case SSHAgent.Request.removeSmartcardKey.protocolID:
|
||||||
|
return .removeSmartcardKey
|
||||||
|
case SSHAgent.Request.lock.protocolID:
|
||||||
|
return .lock
|
||||||
|
case SSHAgent.Request.unlock.protocolID:
|
||||||
|
return .unlock
|
||||||
|
case SSHAgent.Request.addSmartcardKeyConstrained.protocolID:
|
||||||
|
return .addSmartcardKeyConstrained
|
||||||
|
case SSHAgent.Request.protocolExtension.protocolID:
|
||||||
|
return .protocolExtension
|
||||||
|
default:
|
||||||
|
return .unknown(rawRequestInt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SSHAgentInputParser {
|
||||||
|
|
||||||
|
func signatureRequestContext(from data: Data) throws(OpenSSHReaderError) -> SSHAgent.Request.SignatureRequestContext {
|
||||||
|
let reader = OpenSSHReader(data: data)
|
||||||
|
let rawKeyBlob = try reader.readNextChunk()
|
||||||
|
let keyBlob = certificatePublicKeyBlob(from: rawKeyBlob) ?? rawKeyBlob
|
||||||
|
let dataToSign = try reader.readNextChunk()
|
||||||
|
return SSHAgent.Request.SignatureRequestContext(keyBlob: keyBlob, dataToSign: dataToSign)
|
||||||
|
}
|
||||||
|
|
||||||
|
func certificatePublicKeyBlob(from hash: Data) -> Data? {
|
||||||
|
let reader = OpenSSHReader(data: hash)
|
||||||
|
do {
|
||||||
|
let certType = String(decoding: try reader.readNextChunk(), as: UTF8.self)
|
||||||
|
switch certType {
|
||||||
|
case "ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
||||||
|
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
||||||
|
"ecdsa-sha2-nistp521-cert-v01@openssh.com":
|
||||||
|
_ = try reader.readNextChunk() // nonce
|
||||||
|
let curveIdentifier = try reader.readNextChunk()
|
||||||
|
let publicKey = try reader.readNextChunk()
|
||||||
|
let openSSHIdentifier = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "")
|
||||||
|
return openSSHIdentifier.lengthAndData +
|
||||||
|
curveIdentifier.lengthAndData +
|
||||||
|
publicKey.lengthAndData
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension SSHAgentInputParser {
|
||||||
|
|
||||||
|
public enum AgentParsingError: Error, Codable {
|
||||||
|
case unknownRequest
|
||||||
|
case unhandledRequest
|
||||||
|
case invalidData
|
||||||
|
case openSSHReader(OpenSSHReaderError)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,21 +6,39 @@ public enum SSHAgent {}
|
|||||||
extension 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
|
/// 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, Sendable {
|
||||||
|
|
||||||
case requestIdentities = 11
|
case requestIdentities
|
||||||
case signRequest = 13
|
case signRequest(SignatureRequestContext)
|
||||||
case addIdentity = 17
|
case addIdentity
|
||||||
case removeIdentity = 18
|
case removeIdentity
|
||||||
case removeAllIdentities = 19
|
case removeAllIdentities
|
||||||
case addIDConstrained = 25
|
case addIDConstrained
|
||||||
case addSmartcardKey = 20
|
case addSmartcardKey
|
||||||
case removeSmartcardKey = 21
|
case removeSmartcardKey
|
||||||
case lock = 22
|
case lock
|
||||||
case unlock = 23
|
case unlock
|
||||||
case addSmartcardKeyConstrained = 26
|
case addSmartcardKeyConstrained
|
||||||
case protocolExtension = 27
|
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 {
|
public var debugDescription: String {
|
||||||
switch self {
|
switch self {
|
||||||
@ -36,12 +54,28 @@ extension SSHAgent {
|
|||||||
case .unlock: "SSH_AGENTC_UNLOCK"
|
case .unlock: "SSH_AGENTC_UNLOCK"
|
||||||
case .addSmartcardKeyConstrained: "SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED"
|
case .addSmartcardKeyConstrained: "SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED"
|
||||||
case .protocolExtension: "SSH_AGENTC_EXTENSION"
|
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
|
/// 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 agentFailure = 5
|
||||||
case agentSuccess = 6
|
case agentSuccess = 6
|
||||||
|
@ -13,9 +13,8 @@ extension SigningRequestTracer {
|
|||||||
/// Generates a ``SecretKit.SigningRequestProvenance`` from a ``FileHandle``.
|
/// Generates a ``SecretKit.SigningRequestProvenance`` from a ``FileHandle``.
|
||||||
/// - Parameter fileHandle: The reader involved in processing the request.
|
/// - Parameter fileHandle: The reader involved in processing the request.
|
||||||
/// - Returns: A ``SecretKit.SigningRequestProvenance`` describing the origin of the request.
|
/// - Returns: A ``SecretKit.SigningRequestProvenance`` describing the origin of the request.
|
||||||
func provenance(from fileHandleReader: FileHandle) -> SigningRequestProvenance {
|
func provenance(from fileHandle: FileHandle) -> SigningRequestProvenance {
|
||||||
let firstInfo = process(from: fileHandleReader.pidOfConnectedProcess)
|
let firstInfo = process(from: fileHandle.pidOfConnectedProcess)
|
||||||
|
|
||||||
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 {
|
||||||
provenance.chain.append(process(from: provenance.origin.parentPID!))
|
provenance.chain.append(process(from: provenance.origin.parentPID!))
|
||||||
|
49
Sources/Packages/Sources/XPCWrappers/XPCWrappers.swift
Normal file
49
Sources/Packages/Sources/XPCWrappers/XPCWrappers.swift
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct XPCTypedSession<ResponseType: Codable & Sendable, ErrorType: Error & Codable>: Sendable {
|
||||||
|
|
||||||
|
private let session: XPCSession
|
||||||
|
|
||||||
|
public init(serviceName: String, warmup: Bool = false) throws {
|
||||||
|
if #available(macOS 26.0, *) {
|
||||||
|
session = try XPCSession(xpcService: serviceName, requirement: .isFromSameTeam())
|
||||||
|
} else {
|
||||||
|
session = try XPCSession(xpcService: serviceName)
|
||||||
|
}
|
||||||
|
if warmup {
|
||||||
|
Task { [self] in
|
||||||
|
_ = try? await send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func send(_ message: some Encodable = Data()) async throws -> ResponseType {
|
||||||
|
try await withCheckedThrowingContinuation { continuation in
|
||||||
|
do {
|
||||||
|
try session.send(message) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let message):
|
||||||
|
if let result = try? message.decode(as: ResponseType.self) {
|
||||||
|
continuation.resume(returning: result)
|
||||||
|
} else if let error = try? message.decode(as: ErrorType.self) {
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
} else {
|
||||||
|
continuation.resume(throwing: UnknownMessageError())
|
||||||
|
}
|
||||||
|
case .failure(let error):
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func complete() {
|
||||||
|
session.cancel(reason: "Done")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct UnknownMessageError: Error, Codable {}
|
@ -8,19 +8,22 @@ import CryptoKit
|
|||||||
|
|
||||||
// MARK: Identity Listing
|
// MARK: Identity Listing
|
||||||
|
|
||||||
|
|
||||||
// let testProvenance = SigningRequestProvenance(root: .init(pid: 0, processName: "Test", appName: "Test", iconURL: nil, path: /, validSignature: true, parentPID: nil))
|
|
||||||
|
|
||||||
@Test func emptyStores() async throws {
|
@Test func emptyStores() async throws {
|
||||||
let agent = Agent(storeList: SecretStoreList())
|
let agent = Agent(storeList: SecretStoreList())
|
||||||
let response = try await agent.handle(data: Constants.Requests.requestIdentities, provenance: .test)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestIdentities)
|
||||||
|
let response = await agent.handle(request: request, provenance: .test)
|
||||||
#expect(response == Constants.Responses.requestIdentitiesEmpty)
|
#expect(response == Constants.Responses.requestIdentitiesEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func identitiesList() async throws {
|
@Test func identitiesList() async throws {
|
||||||
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||||
let agent = Agent(storeList: list)
|
let agent = Agent(storeList: list)
|
||||||
let response = try await agent.handle(data: Constants.Requests.requestIdentities, provenance: .test)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestIdentities)
|
||||||
|
let response = await agent.handle(request: request, provenance: .test)
|
||||||
|
|
||||||
|
let actual = OpenSSHReader(data: response)
|
||||||
|
let expected = OpenSSHReader(data: Constants.Responses.requestIdentitiesMultiple)
|
||||||
|
print(actual, expected)
|
||||||
#expect(response == Constants.Responses.requestIdentitiesMultiple)
|
#expect(response == Constants.Responses.requestIdentitiesMultiple)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,40 +32,42 @@ import CryptoKit
|
|||||||
@Test func noMatchingIdentities() async throws {
|
@Test func noMatchingIdentities() async throws {
|
||||||
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||||
let agent = Agent(storeList: list)
|
let agent = Agent(storeList: list)
|
||||||
let response = try await agent.handle(data: Constants.Requests.requestSignatureWithNoneMatching, provenance: .test)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignatureWithNoneMatching)
|
||||||
|
let response = await agent.handle(request: request, provenance: .test)
|
||||||
#expect(response == Constants.Responses.requestFailure)
|
#expect(response == Constants.Responses.requestFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test func ecdsaSignature() async throws {
|
@Test func ecdsaSignature() async throws {
|
||||||
// let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||||
// let requestReader = OpenSSHReader(data: Constants.Requests.requestSignature[5...])
|
guard case SSHAgent.Request.signRequest(let context) = request else { return }
|
||||||
// _ = requestReader.readNextChunk()
|
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||||
// let dataToSign = requestReader.readNextChunk()
|
let agent = Agent(storeList: list)
|
||||||
// let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
let response = await agent.handle(request: request, provenance: .test)
|
||||||
// let agent = Agent(storeList: list)
|
let responseReader = OpenSSHReader(data: response)
|
||||||
// await agent.handle(reader: stubReader, writer: stubWriter)
|
let length = try responseReader.readNextBytes(as: UInt32.self).bigEndian
|
||||||
// let outer = OpenSSHReader(data: stubWriter.data[5...])
|
let type = try responseReader.readNextBytes(as: UInt8.self).bigEndian
|
||||||
// let payload = outer.readNextChunk()
|
#expect(length == response.count - MemoryLayout<UInt32>.size)
|
||||||
// let inner = OpenSSHReader(data: payload)
|
#expect(type == SSHAgent.Response.agentSignResponse.rawValue)
|
||||||
// _ = inner.readNextChunk()
|
let outer = OpenSSHReader(data: responseReader.remaining)
|
||||||
// let signedData = inner.readNextChunk()
|
let inner = try outer.readNextChunkAsSubReader()
|
||||||
// let rsData = OpenSSHReader(data: signedData)
|
_ = try inner.readNextChunk()
|
||||||
// var r = rsData.readNextChunk()
|
let rsData = try inner.readNextChunkAsSubReader()
|
||||||
// var s = rsData.readNextChunk()
|
var r = try rsData.readNextChunk()
|
||||||
// // This is fine IRL, but it freaks out CryptoKit
|
var s = try rsData.readNextChunk()
|
||||||
// if r[0] == 0 {
|
// This is fine IRL, but it freaks out CryptoKit
|
||||||
// r.removeFirst()
|
if r[0] == 0 {
|
||||||
// }
|
r.removeFirst()
|
||||||
// if s[0] == 0 {
|
}
|
||||||
// s.removeFirst()
|
if s[0] == 0 {
|
||||||
// }
|
s.removeFirst()
|
||||||
// var rs = r
|
}
|
||||||
// rs.append(s)
|
var rs = r
|
||||||
// let signature = try P256.Signing.ECDSASignature(rawRepresentation: rs)
|
rs.append(s)
|
||||||
// // Correct signature
|
let signature = try P256.Signing.ECDSASignature(rawRepresentation: rs)
|
||||||
// #expect(try P256.Signing.PublicKey(x963Representation: Constants.Secrets.ecdsa256Secret.publicKey)
|
// Correct signature
|
||||||
// .isValidSignature(signature, for: dataToSign))
|
#expect(try P256.Signing.PublicKey(x963Representation: Constants.Secrets.ecdsa256Secret.publicKey)
|
||||||
// }
|
.isValidSignature(signature, for: context.dataToSign))
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Witness protocol
|
// MARK: Witness protocol
|
||||||
|
|
||||||
@ -72,7 +77,7 @@ import CryptoKit
|
|||||||
return true
|
return true
|
||||||
}, witness: { _, _ in })
|
}, witness: { _, _ in })
|
||||||
let agent = Agent(storeList: list, witness: witness)
|
let agent = Agent(storeList: list, witness: witness)
|
||||||
let response = try await agent.handle(data: Constants.Requests.requestSignature, provenance: .test)
|
let response = await agent.handle(request: .signRequest(.empty), provenance: .test)
|
||||||
#expect(response == Constants.Responses.requestFailure)
|
#expect(response == Constants.Responses.requestFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +90,8 @@ import CryptoKit
|
|||||||
witnessed = true
|
witnessed = true
|
||||||
})
|
})
|
||||||
let agent = Agent(storeList: list, witness: witness)
|
let agent = Agent(storeList: list, witness: witness)
|
||||||
_ = try await agent.handle(data: Constants.Requests.requestSignature, provenance: .test)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||||
|
_ = await agent.handle(request: request, provenance: .test)
|
||||||
#expect(witnessed)
|
#expect(witnessed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +106,8 @@ import CryptoKit
|
|||||||
witnessTrace = trace
|
witnessTrace = trace
|
||||||
})
|
})
|
||||||
let agent = Agent(storeList: list, witness: witness)
|
let agent = Agent(storeList: list, witness: witness)
|
||||||
_ = try await agent.handle(data: Constants.Requests.requestSignature, provenance: .test)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||||
|
_ = await agent.handle(request: request, provenance: .test)
|
||||||
#expect(witnessTrace == speakNowTrace)
|
#expect(witnessTrace == speakNowTrace)
|
||||||
#expect(witnessTrace == .test)
|
#expect(witnessTrace == .test)
|
||||||
}
|
}
|
||||||
@ -112,7 +119,8 @@ import CryptoKit
|
|||||||
let store = await list.stores.first?.base as! Stub.Store
|
let store = await list.stores.first?.base as! Stub.Store
|
||||||
store.shouldThrow = true
|
store.shouldThrow = true
|
||||||
let agent = Agent(storeList: list)
|
let agent = Agent(storeList: list)
|
||||||
let response = try await agent.handle(data: Constants.Requests.requestSignature, provenance: .test)
|
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||||
|
let response = await agent.handle(request: request, provenance: .test)
|
||||||
#expect(response == Constants.Responses.requestFailure)
|
#expect(response == Constants.Responses.requestFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +128,7 @@ import CryptoKit
|
|||||||
|
|
||||||
@Test func unhandledAdd() async throws {
|
@Test func unhandledAdd() async throws {
|
||||||
let agent = Agent(storeList: SecretStoreList())
|
let agent = Agent(storeList: SecretStoreList())
|
||||||
let response = try await agent.handle(data: Constants.Requests.addIdentity, provenance: .test)
|
let response = await agent.handle(request: .addIdentity, provenance: .test)
|
||||||
#expect(response == Constants.Responses.requestFailure)
|
#expect(response == Constants.Responses.requestFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,14 +154,13 @@ extension AgentTests {
|
|||||||
|
|
||||||
enum Requests {
|
enum Requests {
|
||||||
static let requestIdentities = Data(base64Encoded: "AAAAAQs=")!
|
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 requestSignatureWithNoneMatching = Data(base64Encoded: "AAABhA0AAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAO8AAAAgbqmrqPUtJ8mmrtaSVexjMYyXWNqjHSnoto7zgv86xvcyAAAAA2dpdAAAAA5zc2gtY29ubmVjdGlvbgAAAAlwdWJsaWNrZXkBAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAAA=")!
|
||||||
static let requestSignature = Data(base64Encoded: "AAABRA0AAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08AAADPAAAAIBIFsbCZ4/dhBmLNGHm0GKj7EJ4N8k/jXRxlyg+LFIYzMgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAAA==")!
|
static let requestSignature = Data(base64Encoded: "AAABRA0AAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08AAADPAAAAIBIFsbCZ4/dhBmLNGHm0GKj7EJ4N8k/jXRxlyg+LFIYzMgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAAA==")!
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Responses {
|
enum Responses {
|
||||||
static let requestIdentitiesEmpty = Data(base64Encoded: "AAAABQwAAAAA")!
|
static let requestIdentitiesEmpty = Data(base64Encoded: "AAAABQwAAAAA")!
|
||||||
static let requestIdentitiesMultiple = Data(base64Encoded: "AAABKwwAAAACAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0")!
|
static let requestIdentitiesMultiple = Data(base64Encoded: "AAABLwwAAAACAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAFWVjZHNhLTI1NkBleGFtcGxlLmNvbQAAAIgAAAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEEspLMDmreMJverQkqKC9zF9ZUasn5uSWkbRlz1jNTCtuyH1KKm+VImL6wdAj47SbzwM6lEEC24AdfrR64P9i/bnS2i83v/4wQVtcZn+Et13QGgWlZst8lxCPzTookaVwMAAAAFWVjZHNhLTM4NEBleGFtcGxlLmNvbQ==")!
|
||||||
static let requestFailure = Data(base64Encoded: "AAAAAQU=")!
|
static let requestFailure = Data(base64Encoded: "AAAAAQU=")!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Testing
|
import Testing
|
||||||
@testable import SecretKit
|
@testable import SecretAgentKit
|
||||||
@testable import SecureEnclaveSecretKit
|
@testable import SecureEnclaveSecretKit
|
||||||
@testable import SmartCardSecretKit
|
@testable import SmartCardSecretKit
|
||||||
|
|
@ -82,7 +82,7 @@ extension Stub {
|
|||||||
let privateKey: Data
|
let privateKey: Data
|
||||||
|
|
||||||
init(keySize: Int, publicKey: Data, privateKey: Data) {
|
init(keySize: Int, publicKey: Data, privateKey: Data) {
|
||||||
self.attributes = Attributes(keyType: .init(algorithm: .ecdsa, size: keySize), authentication: .notRequired)
|
self.attributes = Attributes(keyType: .init(algorithm: .ecdsa, size: keySize), authentication: .notRequired, publicKeyAttribution: "ecdsa-\(keySize)@example.com")
|
||||||
self.publicKey = publicKey
|
self.publicKey = publicKey
|
||||||
self.privateKey = privateKey
|
self.privateKey = privateKey
|
||||||
}
|
}
|
||||||
|
11
Sources/ReleasesDownloader/Info.plist
Normal file
11
Sources/ReleasesDownloader/Info.plist
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>XPCService</key>
|
||||||
|
<dict>
|
||||||
|
<key>ServiceType</key>
|
||||||
|
<string>Application</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
44
Sources/ReleasesDownloader/main.swift
Normal file
44
Sources/ReleasesDownloader/main.swift
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import XPC
|
||||||
|
import OSLog
|
||||||
|
import Brief
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.ReleasesDownloader", category: "ReleasesDownloader")
|
||||||
|
|
||||||
|
enum Constants {
|
||||||
|
static let updateURL = URL(string: "https://api.github.com/repos/maxgoedjen/secretive/releases")!
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleRequest(_ request: XPCListener.IncomingSessionRequest) -> XPCListener.IncomingSessionRequest.Decision {
|
||||||
|
logger.log("ReleasesDownloader received inbound request")
|
||||||
|
return request.accept { xpcDictionary in
|
||||||
|
xpcDictionary.handoffReply(to: .global(qos: .userInteractive)) {
|
||||||
|
logger.log("ReleasesDownloader accepted inbound request")
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let (data, _) = try await URLSession.shared.data(from: Constants.updateURL)
|
||||||
|
let releases = try JSONDecoder().decode([Release].self, from: data)
|
||||||
|
xpcDictionary.reply(releases)
|
||||||
|
} catch {
|
||||||
|
logger.error("ReleasesDownloader failed with unknown error \(error)")
|
||||||
|
xpcDictionary.reply([] as [Release])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if #available(macOS 26.0, *) {
|
||||||
|
_ = try XPCListener(
|
||||||
|
service: "com.maxgoedjen.Secretive.ReleasesDownloader",
|
||||||
|
requirement: .isFromSameTeam(),
|
||||||
|
incomingSessionHandler: handleRequest(_:)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
_ = try XPCListener(service: "com.maxgoedjen.Secretive.ReleasesDownloader", incomingSessionHandler: handleRequest(_:))
|
||||||
|
}
|
||||||
|
logger.log("ReleasesDownloader initialized")
|
||||||
|
dispatchMain()
|
||||||
|
} catch {
|
||||||
|
logger.error("Failed to create ReleasesDownloader, error: \(error)")
|
||||||
|
}
|
@ -34,11 +34,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
logger.debug("SecretAgent finished launching")
|
logger.debug("SecretAgent finished launching")
|
||||||
Task {
|
Task {
|
||||||
|
let inputParser = try XPCAgentInputParser()
|
||||||
for await session in socketController.sessions {
|
for await session in socketController.sessions {
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
for await message in session.messages {
|
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)
|
try await session.write(agentResponse)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
23
Sources/SecretAgent/XPCInputParser.swift
Normal file
23
Sources/SecretAgent/XPCInputParser.swift
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import Foundation
|
||||||
|
import SecretAgentKit
|
||||||
|
import Brief
|
||||||
|
import XPCWrappers
|
||||||
|
|
||||||
|
/// Delegates all agent input parsing to an XPC service which wraps OpenSSH
|
||||||
|
public final class XPCAgentInputParser: SSHAgentInputParserProtocol {
|
||||||
|
|
||||||
|
private let session: XPCTypedSession<SSHAgent.Request, SSHAgentInputParser.AgentParsingError>
|
||||||
|
|
||||||
|
public init() throws {
|
||||||
|
session = try XPCTypedSession(serviceName: "com.maxgoedjen.Secretive.AgentRequestParser", warmup: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func parse(data: Data) async throws -> SSHAgent.Request {
|
||||||
|
try await session.send(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
session.complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,10 +21,18 @@
|
|||||||
5008C23E2E525D8900507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; };
|
5008C23E2E525D8900507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; };
|
||||||
5008C2402E52792400507AC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
|
5008C2402E52792400507AC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
|
||||||
5008C2412E52D18700507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; };
|
5008C2412E52D18700507AC2 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 5008C23D2E525D8200507AC2 /* Localizable.xcstrings */; };
|
||||||
|
500F04EB2E6CDEB0001CF06E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500F04E82E6CDEB0001CF06E /* main.swift */; };
|
||||||
|
500F04EF2E6CDEF4001CF06E /* SecretAgentKit in Frameworks */ = {isa = PBXBuildFile; productRef = 500F04EE2E6CDEF4001CF06E /* SecretAgentKit */; };
|
||||||
|
500F04F02E6CDF20001CF06E /* AgentRequestParser.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 500F04D72E6CDEAB001CF06E /* AgentRequestParser.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; };
|
501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; };
|
||||||
501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; };
|
50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; };
|
||||||
50153E22250DECA300525160 /* SecretListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E21250DECA300525160 /* SecretListItemView.swift */; };
|
50153E22250DECA300525160 /* SecretListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E21250DECA300525160 /* SecretListItemView.swift */; };
|
||||||
|
501577C82E6BC5B4004A37D0 /* ReleasesDownloader.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
501577CF2E6BC5D4004A37D0 /* ReleasesDownloader.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
501577DA2E6BC5F3004A37D0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501577D62E6BC5F3004A37D0 /* main.swift */; };
|
||||||
|
501577DF2E6BC647004A37D0 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501577DE2E6BC647004A37D0 /* Brief */; };
|
||||||
|
501578132E6C0479004A37D0 /* XPCInputParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501578122E6C0479004A37D0 /* XPCInputParser.swift */; };
|
||||||
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
|
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
|
||||||
504788EC2E680DC800B4556F /* URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788EB2E680DC400B4556F /* URLs.swift */; };
|
504788EC2E680DC800B4556F /* URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788EB2E680DC400B4556F /* URLs.swift */; };
|
||||||
504788F22E681F3A00B4556F /* Instructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F12E681F3A00B4556F /* Instructions.swift */; };
|
504788F22E681F3A00B4556F /* Instructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504788F12E681F3A00B4556F /* Instructions.swift */; };
|
||||||
@ -64,6 +72,13 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
500F04F12E6CDF20001CF06E /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 500F04D62E6CDEAB001CF06E;
|
||||||
|
remoteInfo = AgentRequestParser;
|
||||||
|
};
|
||||||
50142166278126B500BBAA70 /* PBXContainerItemProxy */ = {
|
50142166278126B500BBAA70 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
|
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
@ -71,9 +86,53 @@
|
|||||||
remoteGlobalIDString = 50A3B78924026B7500D209EA;
|
remoteGlobalIDString = 50A3B78924026B7500D209EA;
|
||||||
remoteInfo = SecretAgent;
|
remoteInfo = SecretAgent;
|
||||||
};
|
};
|
||||||
|
501577C62E6BC5B4004A37D0 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 501577BC2E6BC5B4004A37D0;
|
||||||
|
remoteInfo = ReleasesDownloader;
|
||||||
|
};
|
||||||
|
501577D02E6BC5D4004A37D0 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 501577BC2E6BC5B4004A37D0;
|
||||||
|
remoteInfo = ReleasesDownloader;
|
||||||
|
};
|
||||||
|
501577D32E6BC5DD004A37D0 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 501577BC2E6BC5B4004A37D0;
|
||||||
|
remoteInfo = ReleasesDownloader;
|
||||||
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
501577C92E6BC5B4004A37D0 /* Embed XPC Services */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices";
|
||||||
|
dstSubfolderSpec = 16;
|
||||||
|
files = (
|
||||||
|
501577C82E6BC5B4004A37D0 /* ReleasesDownloader.xpc in Embed XPC Services */,
|
||||||
|
);
|
||||||
|
name = "Embed XPC Services";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
501577D22E6BC5D4004A37D0 /* Embed XPC Services */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices";
|
||||||
|
dstSubfolderSpec = 16;
|
||||||
|
files = (
|
||||||
|
500F04F02E6CDF20001CF06E /* AgentRequestParser.xpc in Embed XPC Services */,
|
||||||
|
501577CF2E6BC5D4004A37D0 /* ReleasesDownloader.xpc in Embed XPC Services */,
|
||||||
|
);
|
||||||
|
name = "Embed XPC Services";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
50617DBF23FCE4AB0099B055 /* Embed Frameworks */ = {
|
50617DBF23FCE4AB0099B055 /* Embed Frameworks */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -112,8 +171,15 @@
|
|||||||
50033AC227813F1700253856 /* BundleIDs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleIDs.swift; sourceTree = "<group>"; };
|
50033AC227813F1700253856 /* BundleIDs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleIDs.swift; sourceTree = "<group>"; };
|
||||||
5003EF39278005C800DF2006 /* Packages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Packages; sourceTree = "<group>"; };
|
5003EF39278005C800DF2006 /* Packages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Packages; sourceTree = "<group>"; };
|
||||||
5008C23D2E525D8200507AC2 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = Packages/Resources/Localizable.xcstrings; sourceTree = SOURCE_ROOT; };
|
5008C23D2E525D8200507AC2 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = Packages/Resources/Localizable.xcstrings; sourceTree = SOURCE_ROOT; };
|
||||||
|
500F04D72E6CDEAB001CF06E /* AgentRequestParser.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = AgentRequestParser.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
500F04E72E6CDEB0001CF06E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
500F04E82E6CDEB0001CF06E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||||
50153E1F250AFCB200525160 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
|
50153E1F250AFCB200525160 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
|
||||||
50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
|
50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
|
||||||
|
501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = ReleasesDownloader.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
501577D52E6BC5F3004A37D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
501577D62E6BC5F3004A37D0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||||
|
501578122E6C0479004A37D0 /* XPCInputParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XPCInputParser.swift; sourceTree = "<group>"; };
|
||||||
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
|
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
|
||||||
504788EB2E680DC400B4556F /* URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLs.swift; sourceTree = "<group>"; };
|
504788EB2E680DC400B4556F /* URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLs.swift; sourceTree = "<group>"; };
|
||||||
504788F12E681F3A00B4556F /* Instructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instructions.swift; sourceTree = "<group>"; };
|
504788F12E681F3A00B4556F /* Instructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instructions.swift; sourceTree = "<group>"; };
|
||||||
@ -161,6 +227,22 @@
|
|||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
500F04D42E6CDEAB001CF06E /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
500F04EF2E6CDEF4001CF06E /* SecretAgentKit in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
501577BA2E6BC5B4004A37D0 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
501577DF2E6BC647004A37D0 /* Brief in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
50617D7C23FCE48D0099B055 /* Frameworks */ = {
|
50617D7C23FCE48D0099B055 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -195,6 +277,24 @@
|
|||||||
path = Helpers;
|
path = Helpers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
500F04E92E6CDEB0001CF06E /* AgentRequestParser */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
500F04E72E6CDEB0001CF06E /* Info.plist */,
|
||||||
|
500F04E82E6CDEB0001CF06E /* main.swift */,
|
||||||
|
);
|
||||||
|
path = AgentRequestParser;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
501577D92E6BC5F3004A37D0 /* ReleasesDownloader */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
501577D52E6BC5F3004A37D0 /* Info.plist */,
|
||||||
|
501577D62E6BC5F3004A37D0 /* main.swift */,
|
||||||
|
);
|
||||||
|
path = ReleasesDownloader;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
504788ED2E681EB200B4556F /* Styles */ = {
|
504788ED2E681EB200B4556F /* Styles */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -251,6 +351,8 @@
|
|||||||
5003EF39278005C800DF2006 /* Packages */,
|
5003EF39278005C800DF2006 /* Packages */,
|
||||||
50617D8123FCE48E0099B055 /* Secretive */,
|
50617D8123FCE48E0099B055 /* Secretive */,
|
||||||
50A3B78B24026B7500D209EA /* SecretAgent */,
|
50A3B78B24026B7500D209EA /* SecretAgent */,
|
||||||
|
501577D92E6BC5F3004A37D0 /* ReleasesDownloader */,
|
||||||
|
500F04E92E6CDEB0001CF06E /* AgentRequestParser */,
|
||||||
508A58AF241E144C0069DC07 /* Config */,
|
508A58AF241E144C0069DC07 /* Config */,
|
||||||
50617D8023FCE48E0099B055 /* Products */,
|
50617D8023FCE48E0099B055 /* Products */,
|
||||||
5099A08B240243730062B6F2 /* Frameworks */,
|
5099A08B240243730062B6F2 /* Frameworks */,
|
||||||
@ -262,6 +364,8 @@
|
|||||||
children = (
|
children = (
|
||||||
50617D7F23FCE48E0099B055 /* Secretive.app */,
|
50617D7F23FCE48E0099B055 /* Secretive.app */,
|
||||||
50A3B78A24026B7500D209EA /* SecretAgent.app */,
|
50A3B78A24026B7500D209EA /* SecretAgent.app */,
|
||||||
|
501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */,
|
||||||
|
500F04D72E6CDEAB001CF06E /* AgentRequestParser.xpc */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -339,6 +443,7 @@
|
|||||||
children = (
|
children = (
|
||||||
50020BAF24064869003D4025 /* AppDelegate.swift */,
|
50020BAF24064869003D4025 /* AppDelegate.swift */,
|
||||||
5018F54E24064786002EB505 /* Notifier.swift */,
|
5018F54E24064786002EB505 /* Notifier.swift */,
|
||||||
|
501578122E6C0479004A37D0 /* XPCInputParser.swift */,
|
||||||
50A3B79524026B7600D209EA /* Main.storyboard */,
|
50A3B79524026B7600D209EA /* Main.storyboard */,
|
||||||
50A3B79824026B7600D209EA /* Info.plist */,
|
50A3B79824026B7600D209EA /* Info.plist */,
|
||||||
508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */,
|
508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */,
|
||||||
@ -359,6 +464,46 @@
|
|||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
500F04D62E6CDEAB001CF06E /* AgentRequestParser */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 500F04E22E6CDEAB001CF06E /* Build configuration list for PBXNativeTarget "AgentRequestParser" */;
|
||||||
|
buildPhases = (
|
||||||
|
500F04D32E6CDEAB001CF06E /* Sources */,
|
||||||
|
500F04D42E6CDEAB001CF06E /* Frameworks */,
|
||||||
|
500F04D52E6CDEAB001CF06E /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = AgentRequestParser;
|
||||||
|
packageProductDependencies = (
|
||||||
|
500F04EE2E6CDEF4001CF06E /* SecretAgentKit */,
|
||||||
|
);
|
||||||
|
productName = AgentRequestParser;
|
||||||
|
productReference = 500F04D72E6CDEAB001CF06E /* AgentRequestParser.xpc */;
|
||||||
|
productType = "com.apple.product-type.xpc-service";
|
||||||
|
};
|
||||||
|
501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 501577CE2E6BC5B4004A37D0 /* Build configuration list for PBXNativeTarget "ReleasesDownloader" */;
|
||||||
|
buildPhases = (
|
||||||
|
501577B92E6BC5B4004A37D0 /* Sources */,
|
||||||
|
501577BA2E6BC5B4004A37D0 /* Frameworks */,
|
||||||
|
501577BB2E6BC5B4004A37D0 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = ReleasesDownloader;
|
||||||
|
packageProductDependencies = (
|
||||||
|
501577DE2E6BC647004A37D0 /* Brief */,
|
||||||
|
);
|
||||||
|
productName = ReleasesDownloader;
|
||||||
|
productReference = 501577BD2E6BC5B4004A37D0 /* ReleasesDownloader.xpc */;
|
||||||
|
productType = "com.apple.product-type.xpc-service";
|
||||||
|
};
|
||||||
50617D7E23FCE48D0099B055 /* Secretive */ = {
|
50617D7E23FCE48D0099B055 /* Secretive */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 50617D9D23FCE48E0099B055 /* Build configuration list for PBXNativeTarget "Secretive" */;
|
buildConfigurationList = 50617D9D23FCE48E0099B055 /* Build configuration list for PBXNativeTarget "Secretive" */;
|
||||||
@ -368,11 +513,13 @@
|
|||||||
50617D7D23FCE48D0099B055 /* Resources */,
|
50617D7D23FCE48D0099B055 /* Resources */,
|
||||||
50617DBF23FCE4AB0099B055 /* Embed Frameworks */,
|
50617DBF23FCE4AB0099B055 /* Embed Frameworks */,
|
||||||
50C385AF240E438B00AF2719 /* CopyFiles */,
|
50C385AF240E438B00AF2719 /* CopyFiles */,
|
||||||
|
501577C92E6BC5B4004A37D0 /* Embed XPC Services */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
50142167278126B500BBAA70 /* PBXTargetDependency */,
|
50142167278126B500BBAA70 /* PBXTargetDependency */,
|
||||||
|
501577C72E6BC5B4004A37D0 /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Secretive;
|
name = Secretive;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
@ -393,10 +540,14 @@
|
|||||||
50A3B78724026B7500D209EA /* Frameworks */,
|
50A3B78724026B7500D209EA /* Frameworks */,
|
||||||
50A3B78824026B7500D209EA /* Resources */,
|
50A3B78824026B7500D209EA /* Resources */,
|
||||||
50A5C18E240E4B4B00E2996C /* Embed Frameworks */,
|
50A5C18E240E4B4B00E2996C /* Embed Frameworks */,
|
||||||
|
501577D22E6BC5D4004A37D0 /* Embed XPC Services */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
501577D12E6BC5D4004A37D0 /* PBXTargetDependency */,
|
||||||
|
501577D42E6BC5DD004A37D0 /* PBXTargetDependency */,
|
||||||
|
500F04F22E6CDF20001CF06E /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = SecretAgent;
|
name = SecretAgent;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
@ -417,10 +568,16 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastSwiftUpdateCheck = 1220;
|
LastSwiftUpdateCheck = 2600;
|
||||||
LastUpgradeCheck = 2600;
|
LastUpgradeCheck = 2600;
|
||||||
ORGANIZATIONNAME = "Max Goedjen";
|
ORGANIZATIONNAME = "Max Goedjen";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
500F04D62E6CDEAB001CF06E = {
|
||||||
|
CreatedOnToolsVersion = 26.0;
|
||||||
|
};
|
||||||
|
501577BC2E6BC5B4004A37D0 = {
|
||||||
|
CreatedOnToolsVersion = 26.0;
|
||||||
|
};
|
||||||
50617D7E23FCE48D0099B055 = {
|
50617D7E23FCE48D0099B055 = {
|
||||||
CreatedOnToolsVersion = 11.3;
|
CreatedOnToolsVersion = 11.3;
|
||||||
};
|
};
|
||||||
@ -453,11 +610,27 @@
|
|||||||
targets = (
|
targets = (
|
||||||
50617D7E23FCE48D0099B055 /* Secretive */,
|
50617D7E23FCE48D0099B055 /* Secretive */,
|
||||||
50A3B78924026B7500D209EA /* SecretAgent */,
|
50A3B78924026B7500D209EA /* SecretAgent */,
|
||||||
|
501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */,
|
||||||
|
500F04D62E6CDEAB001CF06E /* AgentRequestParser */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
500F04D52E6CDEAB001CF06E /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
501577BB2E6BC5B4004A37D0 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
50617D7D23FCE48D0099B055 /* Resources */ = {
|
50617D7D23FCE48D0099B055 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -485,6 +658,22 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
500F04D32E6CDEAB001CF06E /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
500F04EB2E6CDEB0001CF06E /* main.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
501577B92E6BC5B4004A37D0 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
501577DA2E6BC5F3004A37D0 /* main.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
50617D7B23FCE48D0099B055 /* Sources */ = {
|
50617D7B23FCE48D0099B055 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -530,17 +719,38 @@
|
|||||||
files = (
|
files = (
|
||||||
50020BB024064869003D4025 /* AppDelegate.swift in Sources */,
|
50020BB024064869003D4025 /* AppDelegate.swift in Sources */,
|
||||||
5018F54F24064786002EB505 /* Notifier.swift in Sources */,
|
5018F54F24064786002EB505 /* Notifier.swift in Sources */,
|
||||||
|
501578132E6C0479004A37D0 /* XPCInputParser.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
|
500F04F22E6CDF20001CF06E /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 500F04D62E6CDEAB001CF06E /* AgentRequestParser */;
|
||||||
|
targetProxy = 500F04F12E6CDF20001CF06E /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
50142167278126B500BBAA70 /* PBXTargetDependency */ = {
|
50142167278126B500BBAA70 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = 50A3B78924026B7500D209EA /* SecretAgent */;
|
target = 50A3B78924026B7500D209EA /* SecretAgent */;
|
||||||
targetProxy = 50142166278126B500BBAA70 /* PBXContainerItemProxy */;
|
targetProxy = 50142166278126B500BBAA70 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
501577C72E6BC5B4004A37D0 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */;
|
||||||
|
targetProxy = 501577C62E6BC5B4004A37D0 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
501577D12E6BC5D4004A37D0 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */;
|
||||||
|
targetProxy = 501577D02E6BC5D4004A37D0 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
501577D42E6BC5DD004A37D0 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 501577BC2E6BC5B4004A37D0 /* ReleasesDownloader */;
|
||||||
|
targetProxy = 501577D32E6BC5DD004A37D0 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
@ -555,6 +765,223 @@
|
|||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
500F04E32E6CDEAB001CF06E /* 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;
|
||||||
|
};
|
||||||
|
500F04E42E6CDEAB001CF06E /* 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;
|
||||||
|
};
|
||||||
|
500F04E52E6CDEAB001CF06E /* 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;
|
||||||
|
};
|
||||||
|
501577CA2E6BC5B4004A37D0 /* 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;
|
||||||
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
||||||
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CALENDARS = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CAMERA = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CONTACTS = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_LOCATION = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_PRINTING = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_USB = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = ReleasesDownloader/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = ReleasesDownloader;
|
||||||
|
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.ReleasesDownloader;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
501577CB2E6BC5B4004A37D0 /* Test */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "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;
|
||||||
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
||||||
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CALENDARS = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CAMERA = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CONTACTS = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_LOCATION = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_PRINTING = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_USB = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = ReleasesDownloader/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = ReleasesDownloader;
|
||||||
|
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.ReleasesDownloader;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
501577CC2E6BC5B4004A37D0 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Z72PRUAWF6;
|
||||||
|
ENABLE_APP_SANDBOX = YES;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
||||||
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CALENDARS = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CAMERA = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_CONTACTS = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_LOCATION = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_PRINTING = NO;
|
||||||
|
ENABLE_RESOURCE_ACCESS_USB = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = ReleasesDownloader/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = ReleasesDownloader;
|
||||||
|
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.ReleasesDownloader;
|
||||||
|
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 */ = {
|
50617D9B23FCE48E0099B055 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
|
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
|
||||||
@ -712,7 +1139,7 @@
|
|||||||
ENABLE_ENHANCED_SECURITY = YES;
|
ENABLE_ENHANCED_SECURITY = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_POINTER_AUTHENTICATION = YES;
|
ENABLE_POINTER_AUTHENTICATION = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
@ -752,7 +1179,7 @@
|
|||||||
ENABLE_ENHANCED_SECURITY = YES;
|
ENABLE_ENHANCED_SECURITY = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_POINTER_AUTHENTICATION = YES;
|
ENABLE_POINTER_AUTHENTICATION = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
@ -864,7 +1291,7 @@
|
|||||||
ENABLE_ENHANCED_SECURITY = YES;
|
ENABLE_ENHANCED_SECURITY = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = NO;
|
ENABLE_HARDENED_RUNTIME = NO;
|
||||||
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_POINTER_AUTHENTICATION = YES;
|
ENABLE_POINTER_AUTHENTICATION = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
@ -898,7 +1325,7 @@
|
|||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
||||||
@ -933,7 +1360,7 @@
|
|||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
||||||
@ -969,7 +1396,7 @@
|
|||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
|
||||||
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
|
||||||
@ -995,6 +1422,26 @@
|
|||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
500F04E22E6CDEAB001CF06E /* Build configuration list for PBXNativeTarget "AgentRequestParser" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
500F04E32E6CDEAB001CF06E /* Debug */,
|
||||||
|
500F04E42E6CDEAB001CF06E /* Test */,
|
||||||
|
500F04E52E6CDEAB001CF06E /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
501577CE2E6BC5B4004A37D0 /* Build configuration list for PBXNativeTarget "ReleasesDownloader" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
501577CA2E6BC5B4004A37D0 /* Debug */,
|
||||||
|
501577CB2E6BC5B4004A37D0 /* Test */,
|
||||||
|
501577CC2E6BC5B4004A37D0 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
50617D7A23FCE48D0099B055 /* Build configuration list for PBXProject "Secretive" */ = {
|
50617D7A23FCE48D0099B055 /* Build configuration list for PBXProject "Secretive" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
@ -1060,10 +1507,18 @@
|
|||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = SmartCardSecretKit;
|
productName = SmartCardSecretKit;
|
||||||
};
|
};
|
||||||
|
500F04EE2E6CDEF4001CF06E /* SecretAgentKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = SecretAgentKit;
|
||||||
|
};
|
||||||
501421612781262300BBAA70 /* Brief */ = {
|
501421612781262300BBAA70 /* Brief */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = Brief;
|
productName = Brief;
|
||||||
};
|
};
|
||||||
|
501577DE2E6BC647004A37D0 /* Brief */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = Brief;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 50617D7723FCE48D0099B055 /* Project object */;
|
rootObject = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2600"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<TestPlans>
|
||||||
|
<TestPlanReference
|
||||||
|
reference = "container:Config/Secretive.xctestplan">
|
||||||
|
</TestPlanReference>
|
||||||
|
</TestPlans>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
Loading…
Reference in New Issue
Block a user