mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-07-02 02:03:36 +00:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
fe16e4d9c4 | |||
1caf65c68d | |||
85eb4983bc | |||
5a2d3ecc2e | |||
32f0ed88f4 | |||
d35c58509b | |||
f810b185f0 | |||
5ef1fe996b | |||
2b5fdf541d |
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@ -45,9 +45,12 @@ jobs:
|
|||||||
- name: Update Build Number
|
- name: Update Build Number
|
||||||
env:
|
env:
|
||||||
TAG_NAME: ${{ github.ref }}
|
TAG_NAME: ${{ github.ref }}
|
||||||
|
RUN_ID: ${{ github.run_id }}
|
||||||
run: |
|
run: |
|
||||||
export CLEAN_TAG=$(echo $TAG_NAME | sed -e 's/refs\/tags\/v//')
|
export CLEAN_TAG=$(echo $TAG_NAME | sed -e 's/refs\/tags\/v//')
|
||||||
sed -i '' -e "s/CI_VERSION = 0.0.0/CI_VERSION = $CLEAN_TAG/g" Config/Config.xcconfig
|
sed -i '' -e "s/GITHUB_CI_VERSION/$CLEAN_TAG/g" Config/Config.xcconfig
|
||||||
|
sed -i '' -e "s/GITHUB_BUILD_NUMBER/1.$RUN_ID/g" Config/Config.xcconfig
|
||||||
|
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Secretive/Credits.rtf
|
||||||
- name: Build
|
- name: Build
|
||||||
run: xcrun xcodebuild -project Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
run: xcrun xcodebuild -project Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
||||||
- name: Create ZIPs
|
- name: Create ZIPs
|
||||||
|
@ -1 +1,2 @@
|
|||||||
CI_VERSION = 0.0.0
|
CI_VERSION = GITHUB_CI_VERSION
|
||||||
|
CI_BUILD_NUMBER = GITHUB_BUILD_NUMBER
|
||||||
|
@ -14,7 +14,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
}()
|
}()
|
||||||
let notifier = Notifier()
|
let notifier = Notifier()
|
||||||
lazy var agent: Agent = {
|
lazy var agent: Agent = {
|
||||||
Agent(storeList: storeList/*, notifier: notifier*/)
|
Agent(storeList: storeList, witness: notifier)
|
||||||
}()
|
}()
|
||||||
lazy var socketController: SocketController = {
|
lazy var socketController: SocketController = {
|
||||||
let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String
|
let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String
|
||||||
|
@ -11,11 +11,11 @@ class Notifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func notify(accessTo secret: AnySecret) {
|
func notify(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) {
|
||||||
let notificationCenter = UNUserNotificationCenter.current()
|
let notificationCenter = UNUserNotificationCenter.current()
|
||||||
let notificationContent = UNMutableNotificationContent()
|
let notificationContent = UNMutableNotificationContent()
|
||||||
notificationContent.title = "Signed Request"
|
notificationContent.title = "Signed Request"
|
||||||
notificationContent.body = "\(secret.name) was used to sign a request."
|
notificationContent.body = "\(secret.name) was used to sign a request from \(provenance.origin.name)."
|
||||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
|
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
|
||||||
notificationCenter.add(request, withCompletionHandler: nil)
|
notificationCenter.add(request, withCompletionHandler: nil)
|
||||||
}
|
}
|
||||||
@ -24,8 +24,11 @@ class Notifier {
|
|||||||
|
|
||||||
extension Notifier: SigningWitness {
|
extension Notifier: SigningWitness {
|
||||||
|
|
||||||
func witness(accessTo secret: AnySecret) throws {
|
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
|
||||||
notify(accessTo: secret)
|
}
|
||||||
|
|
||||||
|
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
|
||||||
|
notify(accessTo: secret, by: provenance)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,15 @@ import Foundation
|
|||||||
import CryptoKit
|
import CryptoKit
|
||||||
import OSLog
|
import OSLog
|
||||||
import SecretKit
|
import SecretKit
|
||||||
|
import SecretAgentKit
|
||||||
|
import AppKit
|
||||||
|
|
||||||
public class Agent {
|
public class Agent {
|
||||||
|
|
||||||
fileprivate let storeList: SecretStoreList
|
fileprivate let storeList: SecretStoreList
|
||||||
fileprivate let witness: SigningWitness?
|
fileprivate let witness: SigningWitness?
|
||||||
fileprivate let writer = OpenSSHKeyWriter()
|
fileprivate let writer = OpenSSHKeyWriter()
|
||||||
|
fileprivate let requestTracer = SigningRequestTracer()
|
||||||
|
|
||||||
public init(storeList: SecretStoreList, witness: SigningWitness? = nil) {
|
public init(storeList: SecretStoreList, witness: SigningWitness? = nil) {
|
||||||
os_log(.debug, "Agent is running")
|
os_log(.debug, "Agent is running")
|
||||||
@ -40,7 +43,7 @@ extension Agent {
|
|||||||
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)
|
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)
|
||||||
case .signRequest:
|
case .signRequest:
|
||||||
response.append(SSHAgent.ResponseType.agentSignResponse.data)
|
response.append(SSHAgent.ResponseType.agentSignResponse.data)
|
||||||
response.append(try sign(data: data))
|
response.append(try sign(data: data, from: fileHandle.fileDescriptor))
|
||||||
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription)
|
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@ -74,7 +77,7 @@ extension Agent {
|
|||||||
return countData + keyData
|
return countData + keyData
|
||||||
}
|
}
|
||||||
|
|
||||||
func sign(data: Data) throws -> Data {
|
func sign(data: Data, from pid: Int32) throws -> Data {
|
||||||
let reader = OpenSSHReader(data: data)
|
let reader = OpenSSHReader(data: data)
|
||||||
let hash = try reader.readNextChunk()
|
let hash = try reader.readNextChunk()
|
||||||
guard let (store, secret) = secret(matching: hash) else {
|
guard let (store, secret) = secret(matching: hash) else {
|
||||||
@ -82,8 +85,9 @@ extension Agent {
|
|||||||
throw AgentError.noMatchingKey
|
throw AgentError.noMatchingKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let provenance = requestTracer.provenance(from: pid)
|
||||||
if let witness = witness {
|
if let witness = witness {
|
||||||
try witness.witness(accessTo: secret)
|
try witness.speakNowOrForeverHoldYourPeace(forAccessTo: secret, by: provenance)
|
||||||
}
|
}
|
||||||
|
|
||||||
let dataToSign = try reader.readNextChunk()
|
let dataToSign = try reader.readNextChunk()
|
||||||
@ -118,6 +122,10 @@ extension Agent {
|
|||||||
sub.append(writer.lengthAndData(of: signatureChunk))
|
sub.append(writer.lengthAndData(of: signatureChunk))
|
||||||
signedData.append(writer.lengthAndData(of: sub))
|
signedData.append(writer.lengthAndData(of: sub))
|
||||||
|
|
||||||
|
if let witness = witness {
|
||||||
|
try witness.witness(accessTo: secret, by: provenance)
|
||||||
|
}
|
||||||
|
|
||||||
os_log(.debug, "Agent signed request")
|
os_log(.debug, "Agent signed request")
|
||||||
|
|
||||||
return signedData
|
return signedData
|
||||||
|
@ -7,6 +7,16 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <Security/Security.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
|
||||||
|
// from libproc.h
|
||||||
|
int proc_pidpath(int pid, void * buffer, uint32_t buffersize);
|
||||||
|
|
||||||
|
// from SecTask.h
|
||||||
|
OSStatus SecCodeCreateWithPID(int32_t, SecCSFlags, SecCodeRef *);
|
||||||
|
|
||||||
//! Project version number for SecretAgentKit.
|
//! Project version number for SecretAgentKit.
|
||||||
FOUNDATION_EXPORT double SecretAgentKitVersionNumber;
|
FOUNDATION_EXPORT double SecretAgentKitVersionNumber;
|
||||||
@ -14,6 +24,4 @@ FOUNDATION_EXPORT double SecretAgentKitVersionNumber;
|
|||||||
//! Project version string for SecretAgentKit.
|
//! Project version string for SecretAgentKit.
|
||||||
FOUNDATION_EXPORT const unsigned char SecretAgentKitVersionString[];
|
FOUNDATION_EXPORT const unsigned char SecretAgentKitVersionString[];
|
||||||
|
|
||||||
// In this header, you should import all the public headers of your framework using statements like #import <SecretAgentKit/PublicHeader.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
45
SecretAgentKit/SigningRequestProvenance.swift
Normal file
45
SecretAgentKit/SigningRequestProvenance.swift
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import Foundation
|
||||||
|
import AppKit
|
||||||
|
|
||||||
|
public struct SigningRequestProvenance {
|
||||||
|
|
||||||
|
public var chain: [Process]
|
||||||
|
public init(root: Process) {
|
||||||
|
self.chain = [root]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SigningRequestProvenance {
|
||||||
|
|
||||||
|
public var origin: Process {
|
||||||
|
chain.last!
|
||||||
|
}
|
||||||
|
|
||||||
|
public var intact: Bool {
|
||||||
|
return chain.reduce(true) { $0 && $1.validSignature }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SigningRequestProvenance {
|
||||||
|
|
||||||
|
public struct Process {
|
||||||
|
|
||||||
|
public let pid: Int32
|
||||||
|
public let name: String
|
||||||
|
public let path: String
|
||||||
|
public let validSignature: Bool
|
||||||
|
let parentPID: Int32?
|
||||||
|
|
||||||
|
init(pid: Int32, name: String, path: String, validSignature: Bool, parentPID: Int32?) {
|
||||||
|
self.pid = pid
|
||||||
|
self.name = name
|
||||||
|
self.path = path
|
||||||
|
self.validSignature = validSignature
|
||||||
|
self.parentPID = parentPID
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
43
SecretAgentKit/SigningRequestTracer.swift
Normal file
43
SecretAgentKit/SigningRequestTracer.swift
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import Foundation
|
||||||
|
import AppKit
|
||||||
|
import Security
|
||||||
|
|
||||||
|
struct SigningRequestTracer {
|
||||||
|
|
||||||
|
func provenance(from pid: Int32) -> SigningRequestProvenance {
|
||||||
|
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
|
||||||
|
var len = socklen_t(MemoryLayout<Int32>.size)
|
||||||
|
getsockopt(pid, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len)
|
||||||
|
let pid = pidPointer.load(as: Int32.self)
|
||||||
|
let firstInfo = process(from: pid)
|
||||||
|
|
||||||
|
var provenance = SigningRequestProvenance(root: firstInfo)
|
||||||
|
while NSRunningApplication(processIdentifier: provenance.origin.pid) == nil && provenance.origin.parentPID != nil {
|
||||||
|
provenance.chain.append(process(from: provenance.origin.parentPID!))
|
||||||
|
}
|
||||||
|
return provenance
|
||||||
|
}
|
||||||
|
|
||||||
|
func pidAndNameInfo(from pid: Int32) -> kinfo_proc {
|
||||||
|
var len = MemoryLayout<kinfo_proc>.size
|
||||||
|
let infoPointer = UnsafeMutableRawPointer.allocate(byteCount: len, alignment: 1)
|
||||||
|
var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, pid]
|
||||||
|
sysctl(&name, UInt32(name.count), infoPointer, &len, nil, 0)
|
||||||
|
return infoPointer.load(as: kinfo_proc.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func process(from pid: Int32) -> SigningRequestProvenance.Process {
|
||||||
|
var pidAndNameInfo = self.pidAndNameInfo(from: pid)
|
||||||
|
let ppid = pidAndNameInfo.kp_eproc.e_ppid != 0 ? pidAndNameInfo.kp_eproc.e_ppid : nil
|
||||||
|
let procName = String(cString: &pidAndNameInfo.kp_proc.p_comm.0)
|
||||||
|
let pathPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(MAXPATHLEN))
|
||||||
|
_ = proc_pidpath(pid, pathPointer, UInt32(MAXPATHLEN))
|
||||||
|
let path = String(cString: pathPointer)
|
||||||
|
var secCode: Unmanaged<SecCode>!
|
||||||
|
let flags: SecCSFlags = [.considerExpiration, .enforceRevocationChecks]
|
||||||
|
SecCodeCreateWithPID(pid, SecCSFlags(), &secCode)
|
||||||
|
let valid = SecCodeCheckValidity(secCode.takeRetainedValue(), flags, nil) == errSecSuccess
|
||||||
|
return SigningRequestProvenance.Process(pid: pid, name: procName, path: path, validSignature: valid, parentPID: ppid)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,7 @@ import SecretKit
|
|||||||
|
|
||||||
public protocol SigningWitness {
|
public protocol SigningWitness {
|
||||||
|
|
||||||
func witness(accessTo secret: AnySecret) throws
|
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
|
||||||
|
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,17 @@ extension SmartCard {
|
|||||||
// TODO: Read actual smart card name, eg "YubiKey 5c"
|
// TODO: Read actual smart card name, eg "YubiKey 5c"
|
||||||
@Published public var isAvailable: Bool = false
|
@Published public var isAvailable: Bool = false
|
||||||
public let id = UUID()
|
public let id = UUID()
|
||||||
public let name = NSLocalizedString("Smart Card", comment: "Smart Card")
|
public fileprivate(set) var name = NSLocalizedString("Smart Card", comment: "Smart Card")
|
||||||
@Published public fileprivate(set) var secrets: [Secret] = []
|
@Published public fileprivate(set) var secrets: [Secret] = []
|
||||||
fileprivate let watcher = TKTokenWatcher()
|
fileprivate let watcher = TKTokenWatcher()
|
||||||
fileprivate var tokenID: String?
|
fileprivate var tokenID: String?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
tokenID = watcher.tokenIDs.filter { !$0.contains("setoken") }.first
|
tokenID = watcher.nonSecureEnclaveTokens.first
|
||||||
watcher.setInsertionHandler { string in
|
watcher.setInsertionHandler { string in
|
||||||
guard self.tokenID == nil else { return }
|
guard self.tokenID == nil else { return }
|
||||||
guard !string.contains("setoken") else { return }
|
guard !string.contains("setoken") else { return }
|
||||||
|
|
||||||
self.tokenID = string
|
self.tokenID = string
|
||||||
self.reloadSecrets()
|
self.reloadSecrets()
|
||||||
self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string)
|
self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string)
|
||||||
@ -97,6 +98,14 @@ extension SmartCard.Store {
|
|||||||
|
|
||||||
fileprivate func loadSecrets() {
|
fileprivate func loadSecrets() {
|
||||||
guard let tokenID = tokenID else { return }
|
guard let tokenID = tokenID else { return }
|
||||||
|
// Hack to read name if there's only one smart card
|
||||||
|
let slotNames = TKSmartCardSlotManager().slotNames
|
||||||
|
if watcher.nonSecureEnclaveTokens.count == 1 && slotNames.count == 1 {
|
||||||
|
name = slotNames.first!
|
||||||
|
} else {
|
||||||
|
name = NSLocalizedString("Smart Card", comment: "Smart Card")
|
||||||
|
}
|
||||||
|
|
||||||
let attributes = [
|
let attributes = [
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrTokenID: tokenID,
|
kSecAttrTokenID: tokenID,
|
||||||
@ -124,6 +133,14 @@ extension SmartCard.Store {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TKTokenWatcher {
|
||||||
|
|
||||||
|
fileprivate var nonSecureEnclaveTokens: [String] {
|
||||||
|
tokenIDs.filter { !$0.contains("setoken") }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
extension SmartCard {
|
extension SmartCard {
|
||||||
|
|
||||||
public struct KeychainError: Error {
|
public struct KeychainError: Error {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
50617DCE23FCECFA0099B055 /* SecureEnclaveSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */; };
|
50617DCE23FCECFA0099B055 /* SecureEnclaveSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */; };
|
||||||
50617DD023FCED2C0099B055 /* SecureEnclave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */; };
|
50617DD023FCED2C0099B055 /* SecureEnclave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */; };
|
||||||
50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DD123FCEFA90099B055 /* PreviewStore.swift */; };
|
50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DD123FCEFA90099B055 /* PreviewStore.swift */; };
|
||||||
|
506772C72424784600034DED /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 506772C62424784600034DED /* Credits.rtf */; };
|
||||||
5068389E241471CD00F55094 /* SecretStoreList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5068389D241471CD00F55094 /* SecretStoreList.swift */; };
|
5068389E241471CD00F55094 /* SecretStoreList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5068389D241471CD00F55094 /* SecretStoreList.swift */; };
|
||||||
506838A12415EA5600F55094 /* AnySecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A02415EA5600F55094 /* AnySecret.swift */; };
|
506838A12415EA5600F55094 /* AnySecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A02415EA5600F55094 /* AnySecret.swift */; };
|
||||||
506838A32415EA5D00F55094 /* AnySecretStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A22415EA5D00F55094 /* AnySecretStore.swift */; };
|
506838A32415EA5D00F55094 /* AnySecretStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A22415EA5D00F55094 /* AnySecretStore.swift */; };
|
||||||
@ -35,6 +36,8 @@
|
|||||||
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; };
|
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; };
|
||||||
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; };
|
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; };
|
||||||
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.swift */; };
|
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.swift */; };
|
||||||
|
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; };
|
||||||
|
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; };
|
||||||
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
|
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
|
||||||
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
|
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
|
||||||
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; };
|
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; };
|
||||||
@ -197,12 +200,15 @@
|
|||||||
50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveSecret.swift; sourceTree = "<group>"; };
|
50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveSecret.swift; sourceTree = "<group>"; };
|
||||||
50617DCF23FCED2C0099B055 /* SecureEnclave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclave.swift; sourceTree = "<group>"; };
|
50617DCF23FCED2C0099B055 /* SecureEnclave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclave.swift; sourceTree = "<group>"; };
|
||||||
50617DD123FCEFA90099B055 /* PreviewStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewStore.swift; sourceTree = "<group>"; };
|
50617DD123FCEFA90099B055 /* PreviewStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewStore.swift; sourceTree = "<group>"; };
|
||||||
|
506772C62424784600034DED /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
|
||||||
5068389D241471CD00F55094 /* SecretStoreList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStoreList.swift; sourceTree = "<group>"; };
|
5068389D241471CD00F55094 /* SecretStoreList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStoreList.swift; sourceTree = "<group>"; };
|
||||||
506838A02415EA5600F55094 /* AnySecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecret.swift; sourceTree = "<group>"; };
|
506838A02415EA5600F55094 /* AnySecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecret.swift; sourceTree = "<group>"; };
|
||||||
506838A22415EA5D00F55094 /* AnySecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecretStore.swift; sourceTree = "<group>"; };
|
506838A22415EA5D00F55094 /* AnySecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecretStore.swift; sourceTree = "<group>"; };
|
||||||
50731665241DF8660023809E /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
|
50731665241DF8660023809E /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
|
||||||
50731668241E00C20023809E /* NoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeView.swift; sourceTree = "<group>"; };
|
50731668241E00C20023809E /* NoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeView.swift; sourceTree = "<group>"; };
|
||||||
507CE4EF2420A4C50029F750 /* SigningWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningWitness.swift; sourceTree = "<group>"; };
|
507CE4EF2420A4C50029F750 /* SigningWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningWitness.swift; sourceTree = "<group>"; };
|
||||||
|
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestProvenance.swift; sourceTree = "<group>"; };
|
||||||
|
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; };
|
||||||
508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
|
508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
|
||||||
508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||||
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; };
|
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; };
|
||||||
@ -333,6 +339,7 @@
|
|||||||
50617D8B23FCE48E0099B055 /* Main.storyboard */,
|
50617D8B23FCE48E0099B055 /* Main.storyboard */,
|
||||||
50617D8E23FCE48E0099B055 /* Info.plist */,
|
50617D8E23FCE48E0099B055 /* Info.plist */,
|
||||||
50617D8F23FCE48E0099B055 /* Secretive.entitlements */,
|
50617D8F23FCE48E0099B055 /* Secretive.entitlements */,
|
||||||
|
506772C62424784600034DED /* Credits.rtf */,
|
||||||
50617D8823FCE48E0099B055 /* Preview Content */,
|
50617D8823FCE48E0099B055 /* Preview Content */,
|
||||||
);
|
);
|
||||||
path = Secretive;
|
path = Secretive;
|
||||||
@ -468,6 +475,8 @@
|
|||||||
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */,
|
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */,
|
||||||
50A3B79D24026B9900D209EA /* SocketController.swift */,
|
50A3B79D24026B9900D209EA /* SocketController.swift */,
|
||||||
507CE4EF2420A4C50029F750 /* SigningWitness.swift */,
|
507CE4EF2420A4C50029F750 /* SigningWitness.swift */,
|
||||||
|
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
|
||||||
|
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */,
|
||||||
50A3B79F24026B9900D209EA /* Agent.swift */,
|
50A3B79F24026B9900D209EA /* Agent.swift */,
|
||||||
5099A06F240242BA0062B6F2 /* Info.plist */,
|
5099A06F240242BA0062B6F2 /* Info.plist */,
|
||||||
);
|
);
|
||||||
@ -735,6 +744,7 @@
|
|||||||
50617D8D23FCE48E0099B055 /* Main.storyboard in Resources */,
|
50617D8D23FCE48E0099B055 /* Main.storyboard in Resources */,
|
||||||
50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */,
|
50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */,
|
||||||
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */,
|
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */,
|
||||||
|
506772C72424784600034DED /* Credits.rtf in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -850,6 +860,8 @@
|
|||||||
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */,
|
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */,
|
||||||
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */,
|
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */,
|
||||||
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */,
|
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */,
|
||||||
|
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */,
|
||||||
|
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Test"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
|
23
Secretive/Credits.rtf
Normal file
23
Secretive/Credits.rtf
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{\rtf1\ansi\ansicpg1252\cocoartf2511
|
||||||
|
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||||
|
{\colortbl;\red255\green255\blue255;}
|
||||||
|
{\*\expandedcolortbl;;}
|
||||||
|
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
|
||||||
|
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6119\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
|
||||||
|
{\field{\*\fldinst{HYPERLINK "https://github.com/maxgoedjen/secretive"}}{\fldrslt
|
||||||
|
\f0\fs24 \cf0 https://github.com/maxgoedjen/secretive}}
|
||||||
|
\f0\fs24 \
|
||||||
|
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
|
||||||
|
\cf0 \
|
||||||
|
GITHUB_BUILD_URL\
|
||||||
|
\
|
||||||
|
Special Thanks To:\
|
||||||
|
https://github.com/bdash\
|
||||||
|
https://github.com/danielctull\
|
||||||
|
https://github.com/davedelong\
|
||||||
|
https://github.com/esttorhe\
|
||||||
|
https://github.com/joeblau\
|
||||||
|
https://github.com/marksands\
|
||||||
|
https://github.com/mergesort\
|
||||||
|
https://github.com/phillco\
|
||||||
|
https://github.com/zackdotcomputer}
|
Reference in New Issue
Block a user