Compare commits

..

5 Commits

Author SHA1 Message Date
a2105a2ae6 Revert serach path test 2020-03-17 00:55:05 -07:00
c1d535ef95 Remove unneeded appikit import 2020-03-17 00:54:14 -07:00
1083c0f733 Restore notifier. 2020-03-17 00:39:36 -07:00
914e4d6910 Cleaning up a bit 2020-03-17 00:38:25 -07:00
e70774f6aa Rough POC 2020-03-16 00:49:43 -07:00
44 changed files with 153 additions and 1046 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -45,12 +45,9 @@ 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/GITHUB_CI_VERSION/$CLEAN_TAG/g" Config/Config.xcconfig sed -i '' -e "s/CI_VERSION = 0.0.0/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

View File

@ -1,19 +0,0 @@
//
// Brief.h
// Brief
//
// Created by Max Goedjen on 3/21/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for Brief.
FOUNDATION_EXPORT double BriefVersionNumber;
//! Project version string for Brief.
FOUNDATION_EXPORT const unsigned char BriefVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Brief/PublicHeader.h>

View File

@ -1,24 +0,0 @@
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_NAME) is MIT Licensed.</string>
</dict>
</plist>

View File

@ -1,2 +1 @@
CI_VERSION = GITHUB_CI_VERSION CI_VERSION = 0.0.0
CI_BUILD_NUMBER = GITHUB_BUILD_NUMBER

View File

@ -1,11 +1,9 @@
# Secretive ![Test](https://github.com/maxgoedjen/secretive/workflows/Test/badge.svg) ![Release](https://github.com/maxgoedjen/secretive/workflows/Release/badge.svg) # Secretive
Secretive is an app for storing and managing SSH keys in the Secure Enclave. It is inspired by the [sekey project](https://github.com/sekey/sekey), but rewritten in Swift with no external dependencies and with a handy native management app. Secretive is an app for storing and managing SSH keys in the Secure Enclave. It is inspired by the [sekey project](https://github.com/sekey/sekey), but rewritten in Swift with no external dependencies and with a handy native management app.
<img src="/.github/readme/app.png" alt="Screenshot of Secretive" width="600"> <img src="/.github/readme/app.png" alt="Screenshot of Secretive" width="600">
## Why? ## Why?
### Safer Storage ### Safer Storage

View File

@ -1,9 +1,7 @@
import Cocoa import Cocoa
import OSLog
import Combine
import SecretKit import SecretKit
import SecretAgentKit import SecretAgentKit
import Brief import OSLog
@NSApplicationMain @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
@ -14,7 +12,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
list.add(store: SmartCard.Store()) list.add(store: SmartCard.Store())
return list return list
}() }()
let updater = Updater()
let notifier = Notifier() let notifier = Notifier()
lazy var agent: Agent = { lazy var agent: Agent = {
Agent(storeList: storeList, witness: notifier) Agent(storeList: storeList, witness: notifier)
@ -23,18 +20,17 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String
return SocketController(path: path) return SocketController(path: path)
}() }()
fileprivate var updateSink: AnyCancellable?
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
os_log(.debug, "SecretAgent finished launching") os_log(.debug, "SecretAgent finished launching")
DispatchQueue.main.async { DispatchQueue.main.async {
self.socketController.handler = self.agent.handle(reader:writer:) self.socketController.handler = self.agent.handle(fileHandle:)
} }
notifier.prompt() notifier.prompt()
updateSink = updater.$update.sink { update in }
guard let update = update else { return }
self.notifier.notify(update: update, ignore: self.updater.ignore(release:)) func applicationWillTerminate(_ aNotification: Notification) {
} // Insert code here to tear down your application
} }

View File

@ -25,7 +25,7 @@
<key>LSUIElement</key> <key>LSUIElement</key>
<true/> <true/>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_NAME) is MIT Licensed.</string> <string>Copyright © 2020 Max Goedjen. All rights reserved.</string>
<key>NSMainStoryboardFile</key> <key>NSMainStoryboardFile</key>
<string>Main</string> <string>Main</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>

View File

@ -1,23 +1,10 @@
import Foundation import Foundation
import UserNotifications
import AppKit
import SecretKit import SecretKit
import SecretAgentKit import SecretAgentKit
import Brief import UserNotifications
class Notifier { class Notifier {
fileprivate let notificationDelegate = NotificationDelegate()
init() {
let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: "Update", options: [])
let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: "Ignore", options: [])
let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: [])
let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory])
UNUserNotificationCenter.current().delegate = notificationDelegate
}
func prompt() { func prompt() {
let notificationCenter = UNUserNotificationCenter.current() let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options: .alert) { _, _ in notificationCenter.requestAuthorization(options: .alert) { _, _ in
@ -27,97 +14,18 @@ class Notifier {
func notify(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) { 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 from \(provenance.origin.name)" notificationContent.title = "Signed Request"
notificationContent.subtitle = "Using secret \"\(secret.name)\"" notificationContent.body = "\(secret.name) was used to sign a request from \(provenance.origin.name)."
if let iconURL = iconURL(for: provenance), let attachment = try? UNNotificationAttachment(identifier: "icon", url: iconURL, options: nil) {
notificationContent.attachments = [attachment]
}
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)
} }
func notify(update: Release, ignore: ((Release) -> Void)?) {
notificationDelegate.release = update
notificationDelegate.ignore = ignore
let notificationCenter = UNUserNotificationCenter.current()
let notificationContent = UNMutableNotificationContent()
if update.critical {
notificationContent.title = "Critical Security Update - \(update.name)"
} else {
notificationContent.title = "Update Available - \(update.name)"
}
notificationContent.subtitle = "Click to Update"
notificationContent.body = update.body
notificationContent.categoryIdentifier = update.critical ? Constants.criticalUpdateCategoryIdentitifier : Constants.updateCategoryIdentitifier
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
notificationCenter.add(request, withCompletionHandler: nil)
}
}
extension Notifier {
func iconURL(for provenance: SigningRequestProvenance) -> URL? {
do {
if let app = NSRunningApplication(processIdentifier: provenance.origin.pid), let icon = app.icon?.tiffRepresentation {
let temporaryURL = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("\(UUID().uuidString).png"))
let bitmap = NSBitmapImageRep(data: icon)
try bitmap?.representation(using: .png, properties: [:])?.write(to: temporaryURL)
return temporaryURL
}
} catch {
}
return nil
}
} }
extension Notifier: SigningWitness { extension Notifier: SigningWitness {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
}
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws { func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
notify(accessTo: secret, by: provenance) notify(accessTo: secret, by: provenance)
} }
} }
extension Notifier {
enum Constants {
static let updateCategoryIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update"
static let criticalUpdateCategoryIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update.critical"
static let updateActionIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update.updateaction"
static let ignoreActionIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update.ignoreaction"
}
}
class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
fileprivate var release: Release?
fileprivate var ignore: ((Release) -> Void)?
func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
guard let update = release else { return }
switch response.actionIdentifier {
case Notifier.Constants.updateActionIdentitifier, UNNotificationDefaultActionIdentifier:
NSWorkspace.shared.open(update.html_url)
case Notifier.Constants.ignoreActionIdentitifier:
ignore?(update)
default:
fatalError()
}
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
}

View File

@ -4,8 +4,6 @@
<dict> <dict>
<key>com.apple.security.app-sandbox</key> <key>com.apple.security.app-sandbox</key>
<true/> <true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.smartcard</key> <key>com.apple.security.smartcard</key>
<true/> <true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>

View File

@ -2,6 +2,7 @@ import Foundation
import CryptoKit import CryptoKit
import OSLog import OSLog
import SecretKit import SecretKit
import SecretAgentKit
import AppKit import AppKit
public class Agent { public class Agent {
@ -21,34 +22,28 @@ public class Agent {
extension Agent { extension Agent {
public func handle(reader: FileHandleReader, writer: FileHandleWriter) { public func handle(fileHandle: FileHandle) {
os_log(.debug, "Agent handling new data") os_log(.debug, "Agent handling new data")
let data = reader.availableData let data = fileHandle.availableData
guard !data.isEmpty else { return } guard !data.isEmpty else { return }
let requestTypeInt = data[4] let requestTypeInt = data[4]
guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { return }
writer.write(OpenSSHKeyWriter().lengthAndData(of: SSHAgent.ResponseType.agentFailure.data))
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription)
return
}
os_log(.debug, "Agent handling request of type %@", requestType.debugDescription) os_log(.debug, "Agent handling request of type %@", requestType.debugDescription)
let subData = Data(data[5...]) let subData = Data(data[5...])
let response = handle(requestType: requestType, data: subData, reader: reader) handle(requestType: requestType, data: subData, fileHandle: fileHandle)
writer.write(response)
} }
func handle(requestType: SSHAgent.RequestType, data: Data, reader: FileHandleReader) -> Data { func handle(requestType: SSHAgent.RequestType, data: Data, fileHandle: FileHandle) {
var response = Data() var response = Data()
do { do {
switch requestType { switch requestType {
case .requestIdentities: case .requestIdentities:
response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data) response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data)
response.append(identities()) response.append(try identities())
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)
case .signRequest: case .signRequest:
let provenance = requestTracer.provenance(from: reader)
response.append(SSHAgent.ResponseType.agentSignResponse.data) response.append(SSHAgent.ResponseType.agentSignResponse.data)
response.append(try sign(data: data, provenance: provenance)) 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 {
@ -57,14 +52,14 @@ extension Agent {
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription) os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription)
} }
let full = OpenSSHKeyWriter().lengthAndData(of: response) let full = OpenSSHKeyWriter().lengthAndData(of: response)
return full fileHandle.write(full)
} }
} }
extension Agent { extension Agent {
func identities() -> Data { func identities() throws -> Data {
// TODO: RESTORE ONCE XCODE 11.4 IS GM // TODO: RESTORE ONCE XCODE 11.4 IS GM
let secrets = storeList.stores.flatMap { $0.secrets } let secrets = storeList.stores.flatMap { $0.secrets }
// let secrets = storeList.stores.flatMap(\.secrets) // let secrets = storeList.stores.flatMap(\.secrets)
@ -82,19 +77,20 @@ extension Agent {
return countData + keyData return countData + keyData
} }
func sign(data: Data, provenance: SigningRequestProvenance) throws -> Data { func sign(data: Data, from pid: Int32) throws -> Data {
let reader = OpenSSHReader(data: data) let reader = OpenSSHReader(data: data)
let hash = reader.readNextChunk() let hash = try reader.readNextChunk()
guard let (store, secret) = secret(matching: hash) else { guard let (store, secret) = secret(matching: hash) else {
os_log(.debug, "Agent did not have a key matching %@", hash as NSData) os_log(.debug, "Agent did not have a key matching %@", hash as NSData)
throw AgentError.noMatchingKey throw AgentError.noMatchingKey
} }
let provenance = requestTracer.provenance(from: pid)
if let witness = witness { if let witness = witness {
try witness.speakNowOrForeverHoldYourPeace(forAccessTo: secret, by: provenance) try witness.witness(accessTo: secret, by: provenance)
} }
let dataToSign = reader.readNextChunk() let dataToSign = try reader.readNextChunk()
let derSignature = try store.sign(data: dataToSign, with: secret) let derSignature = try store.sign(data: dataToSign, with: secret)
let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)! let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!
@ -108,7 +104,7 @@ extension Agent {
case (.ellipticCurve, 384): case (.ellipticCurve, 384):
rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation
default: default:
throw AgentError.unsupportedKeyType fatalError()
} }
@ -126,10 +122,6 @@ 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
@ -159,7 +151,6 @@ extension Agent {
enum AgentError: Error { enum AgentError: Error {
case unhandledType case unhandledType
case noMatchingKey case noMatchingKey
case unsupportedKeyType
} }
} }

View File

@ -1,26 +0,0 @@
import Foundation
public protocol FileHandleReader {
var availableData: Data { get }
var fileDescriptor: Int32 { get }
var pidOfConnectedProcess: Int32 { get }
}
public protocol FileHandleWriter {
func write(_ data: Data)
}
extension FileHandle: FileHandleReader, FileHandleWriter {
public var pidOfConnectedProcess: Int32 {
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
var len = socklen_t(MemoryLayout<Int32>.size)
getsockopt(fileDescriptor, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len)
return pidPointer.load(as: Int32.self)
}
}

View File

@ -19,6 +19,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_NAME) is MIT Licensed.</string> <string>Copyright © 2020 Max Goedjen. All rights reserved.</string>
</dict> </dict>
</plist> </plist>

View File

@ -12,7 +12,7 @@ extension SSHAgent {
switch self { switch self {
case .requestIdentities: case .requestIdentities:
return "RequestIdentities" return "RequestIdentities"
case .signRequest: default:
return "SignRequest" return "SignRequest"
} }
} }

View File

@ -1,14 +1,12 @@
//
// SecretAgentKit.h
// SecretAgentKit
//
// Created by Max Goedjen on 2/22/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
#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;
@ -16,4 +14,6 @@ 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>

View File

@ -1,7 +1,7 @@
import Foundation import Foundation
import AppKit import AppKit
public struct SigningRequestProvenance: Equatable { public struct SigningRequestProvenance {
public var chain: [Process] public var chain: [Process]
public init(root: Process) { public init(root: Process) {
@ -16,27 +16,21 @@ extension SigningRequestProvenance {
chain.last! chain.last!
} }
public var intact: Bool {
return chain.reduce(true) { $0 && $1.validSignature }
}
} }
extension SigningRequestProvenance { extension SigningRequestProvenance {
public struct Process: Equatable { public struct Process {
public let pid: Int32 public let pid: Int32
public let name: String public let name: String
public let path: String public let path: String
public let validSignature: Bool
let parentPID: Int32? let parentPID: Int32?
init(pid: Int32, name: String, path: String, validSignature: Bool, parentPID: Int32?) { init(pid: Int32, name: String, path: String, parentPID: Int32?) {
self.pid = pid self.pid = pid
self.name = name self.name = name
self.path = path self.path = path
self.validSignature = validSignature
self.parentPID = parentPID self.parentPID = parentPID
} }

View File

@ -1,11 +1,14 @@
import Foundation import Foundation
import AppKit import AppKit
import Security
struct SigningRequestTracer { struct SigningRequestTracer {
func provenance(from fileHandleReader: FileHandleReader) -> SigningRequestProvenance { func provenance(from pid: Int32) -> SigningRequestProvenance {
let firstInfo = process(from: fileHandleReader.pidOfConnectedProcess) 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) 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 {
@ -26,14 +29,7 @@ struct SigningRequestTracer {
var pidAndNameInfo = self.pidAndNameInfo(from: pid) var pidAndNameInfo = self.pidAndNameInfo(from: pid)
let ppid = pidAndNameInfo.kp_eproc.e_ppid != 0 ? pidAndNameInfo.kp_eproc.e_ppid : nil 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 procName = String(cString: &pidAndNameInfo.kp_proc.p_comm.0)
let pathPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(MAXPATHLEN)) return SigningRequestProvenance.Process(pid: pid, name: procName, path: "", parentPID: ppid)
_ = 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)
} }
} }

View File

@ -3,7 +3,6 @@ import SecretKit
public protocol SigningWitness { public protocol SigningWitness {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
} }

View File

@ -5,7 +5,7 @@ public class SocketController {
fileprivate var fileHandle: FileHandle? fileprivate var fileHandle: FileHandle?
fileprivate var port: SocketPort? fileprivate var port: SocketPort?
public var handler: ((FileHandleReader, FileHandleWriter) -> Void)? public var handler: ((FileHandle) -> Void)?
public init(path: String) { public init(path: String) {
os_log(.debug, "Socket controller setting up at %@", path) os_log(.debug, "Socket controller setting up at %@", path)
@ -52,7 +52,7 @@ public class SocketController {
@objc func handleConnectionAccept(notification: Notification) { @objc func handleConnectionAccept(notification: Notification) {
os_log(.debug, "Socket controller accepted connection") os_log(.debug, "Socket controller accepted connection")
guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return } guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return }
handler?(new, new) handler?(new)
new.waitForDataInBackgroundAndNotify() new.waitForDataInBackgroundAndNotify()
fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!]) fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!])
} }
@ -61,7 +61,7 @@ public class SocketController {
os_log(.debug, "Socket controller has new data available") os_log(.debug, "Socket controller has new data available")
guard let new = notification.object as? FileHandle else { return } guard let new = notification.object as? FileHandle else { return }
os_log(.debug, "Socket controller received new file handle") os_log(.debug, "Socket controller received new file handle")
handler?(new, new) handler?(new)
} }
} }

View File

@ -1,162 +0,0 @@
import Foundation
import XCTest
import CryptoKit
@testable import SecretKit
@testable import SecretAgentKit
class AgentTests: XCTestCase {
let stubWriter = StubFileHandleWriter()
// MARK: Identity Listing
func testEmptyStores() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestIdentities)
let agent = Agent(storeList: SecretStoreList())
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertEqual(stubWriter.data, Constants.Responses.requestIdentitiesEmpty)
}
func testIdentitiesList() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestIdentities)
let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let agent = Agent(storeList: list)
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertEqual(stubWriter.data, Constants.Responses.requestIdentitiesMultiple)
}
// MARK: Signatures
func testNoMatchingIdentities() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignatureWithNoneMatching)
let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let agent = Agent(storeList: list)
agent.handle(reader: stubReader, writer: stubWriter)
// XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure)
}
func testSignature() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature)
let requestReader = OpenSSHReader(data: Constants.Requests.requestSignature[5...])
_ = requestReader.readNextChunk()
let dataToSign = requestReader.readNextChunk()
let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let agent = Agent(storeList: list)
agent.handle(reader: stubReader, writer: stubWriter)
let outer = OpenSSHReader(data: stubWriter.data[5...])
let payload = outer.readNextChunk()
let inner = OpenSSHReader(data: payload)
_ = inner.readNextChunk()
let signedData = inner.readNextChunk()
let rsData = OpenSSHReader(data: signedData)
let r = rsData.readNextChunk()
let s = rsData.readNextChunk()
var rs = r
rs.append(s)
let signature = try! P256.Signing.ECDSASignature(rawRepresentation: rs)
let valid = try! P256.Signing.PublicKey(x963Representation: Constants.Secrets.ecdsa256Secret.publicKey).isValidSignature(signature, for: dataToSign)
XCTAssertTrue(valid)
}
// MARK: Witness protocol
func testWitnessObjectionStopsRequest() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature)
let list = storeList(with: [Constants.Secrets.ecdsa256Secret])
let witness = StubWitness(speakNow: { _,_ in
return true
}, witness: { _, _ in })
let agent = Agent(storeList: list, witness: witness)
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure)
}
func testWitnessSignature() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature)
let list = storeList(with: [Constants.Secrets.ecdsa256Secret])
var witnessed = false
let witness = StubWitness(speakNow: { _, trace in
return false
}, witness: { _, trace in
witnessed = true
})
let agent = Agent(storeList: list, witness: witness)
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertTrue(witnessed)
}
func testRequestTracing() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature)
let list = storeList(with: [Constants.Secrets.ecdsa256Secret])
var speakNowTrace: SigningRequestProvenance! = nil
var witnessTrace: SigningRequestProvenance! = nil
let witness = StubWitness(speakNow: { _, trace in
speakNowTrace = trace
return false
}, witness: { _, trace in
witnessTrace = trace
})
let agent = Agent(storeList: list, witness: witness)
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertEqual(witnessTrace, speakNowTrace)
XCTAssertEqual(witnessTrace.origin.name, "Finder")
XCTAssertEqual(witnessTrace.origin.validSignature, true)
XCTAssertEqual(witnessTrace.origin.parentPID, 1)
}
// MARK: Exception Handling
func testSignatureException() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.requestSignature)
let list = storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let store = list.stores.first?.base as! Stub.Store
store.shouldThrow = true
let agent = Agent(storeList: list)
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure)
}
// MARK: Unsupported
func testUnhandledAdd() {
let stubReader = StubFileHandleReader(availableData: Constants.Requests.addIdentity)
let agent = Agent(storeList: SecretStoreList())
agent.handle(reader: stubReader, writer: stubWriter)
XCTAssertEqual(stubWriter.data, Constants.Responses.requestFailure)
}
}
extension AgentTests {
func storeList(with secrets: [Stub.Secret]) -> SecretStoreList {
let store = Stub.Store()
store.secrets.append(contentsOf: secrets)
let storeList = SecretStoreList()
storeList.add(store: store)
return storeList
}
enum Constants {
enum Requests {
static let requestIdentities = Data(base64Encoded: "AAAAAQs=")!
static let addIdentity = Data(base64Encoded: "AAAAARE=")!
static let requestSignatureWithNoneMatching = Data(base64Encoded: "AAABhA0AAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAO8AAAAgbqmrqPUtJ8mmrtaSVexjMYyXWNqjHSnoto7zgv86xvcyAAAAA2dpdAAAAA5zc2gtY29ubmVjdGlvbgAAAAlwdWJsaWNrZXkBAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAAA=")!
static let requestSignature = Data(base64Encoded: "AAABRA0AAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08AAADPAAAAIBIFsbCZ4/dhBmLNGHm0GKj7EJ4N8k/jXRxlyg+LFIYzMgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAAA==")!
}
enum Responses {
static let requestIdentitiesEmpty = Data(base64Encoded: "AAAABQwAAAAA")!
static let requestIdentitiesMultiple = Data(base64Encoded: "AAABKwwAAAACAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0")!
static let requestFailure = Data(base64Encoded: "AAAAAQU=")!
}
enum Secrets {
static let ecdsa256Secret = Stub.Secret(keySize: 256, publicKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08=")!, privateKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy09nw780wy/TSfUmzj15iJkV234AaCLNl+H8qFL6qK8VIg==")!)
static let ecdsa384Secret = Stub.Secret(keySize: 384, publicKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDA==")!, privateKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDHNapAOzrt9E+9QC4/KYoXS7Uw4pmdAz53uIj02tttiq3c0ZyIQ7XoscWWRqRrz8Kw==")!)
}
}
}

View File

@ -0,0 +1,19 @@
//
// SecretAgentKitTests.swift
// SecretAgentKitTests
//
// Created by Max Goedjen on 2/22/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
import XCTest
@testable import SecretAgentKit
class SecretAgentKitTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
}

View File

@ -1,14 +0,0 @@
import SecretAgentKit
import AppKit
struct StubFileHandleReader: FileHandleReader {
let availableData: Data
var fileDescriptor: Int32 {
NSWorkspace.shared.runningApplications.filter({ $0.localizedName == "Finder" }).first!.processIdentifier
}
var pidOfConnectedProcess: Int32 {
fileDescriptor
}
}

View File

@ -1,11 +0,0 @@
import SecretAgentKit
class StubFileHandleWriter: FileHandleWriter {
var data = Data()
func write(_ data: Data) {
self.data.append(data)
}
}

View File

@ -1,113 +0,0 @@
import SecretKit
import CryptoKit
struct Stub {}
extension Stub {
public class Store: SecretStore {
public let isAvailable = true
public let id = UUID()
public let name = "Stub"
public var secrets: [Secret] = []
public var shouldThrow = false
public init() {
// try! create(size: 256)
// try! create(size: 384)
}
public func create(size: Int) throws {
let flags: SecAccessControlCreateFlags = []
let access =
SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
flags,
nil) as Any
let attributes = [
kSecAttrLabel: name,
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits: size,
kSecPrivateKeyAttrs: [
kSecAttrIsPermanent: true,
kSecAttrAccessControl: access
]
] as CFDictionary
var privateKey: SecKey! = nil
var publicKey: SecKey! = nil
SecKeyGeneratePair(attributes, &publicKey, &privateKey)
let publicAttributes = SecKeyCopyAttributes(publicKey) as! [CFString: Any]
let privateAttributes = SecKeyCopyAttributes(privateKey) as! [CFString: Any]
let publicData = (publicAttributes[kSecValueData] as! Data)
let privateData = (privateAttributes[kSecValueData] as! Data)
let secret = Secret(keySize: size, publicKey: publicData, privateKey: privateData)
print(secret)
print("Public Key OpenSSH: \(OpenSSHKeyWriter().openSSHString(secret: secret))")
}
public func sign(data: Data, with secret: Secret) throws -> Data {
guard !shouldThrow else {
throw NSError()
}
let privateKey = SecKeyCreateWithData(secret.privateKey as CFData, [
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits: secret.keySize,
kSecAttrKeyClass: kSecAttrKeyClassPrivate
] as CFDictionary
, nil)!
let signatureAlgorithm: SecKeyAlgorithm
switch secret.keySize {
case 256:
signatureAlgorithm = .ecdsaSignatureMessageX962SHA256
case 384:
signatureAlgorithm = .ecdsaSignatureMessageX962SHA384
default:
fatalError()
}
return SecKeyCreateSignature(privateKey, signatureAlgorithm, data as CFData, nil)! as Data
}
}
}
extension Stub {
struct Secret: SecretKit.Secret, CustomDebugStringConvertible {
let id = UUID().uuidString.data(using: .utf8)!
let name = UUID().uuidString
let algorithm = Algorithm.ellipticCurve
let keySize: Int
let publicKey: Data
let privateKey: Data
init(keySize: Int, publicKey: Data, privateKey: Data) {
self.keySize = keySize
self.publicKey = publicKey
self.privateKey = privateKey
}
var debugDescription: String {
"""
Key Size \(keySize)
Private: \(privateKey.base64EncodedString())
Public: \(publicKey.base64EncodedString())
"""
}
}
}
extension Stub.Store {
struct StubError: Error {
}
}

View File

@ -1,32 +0,0 @@
import SecretKit
import SecretAgentKit
struct StubWitness {
let speakNow: (AnySecret, SigningRequestProvenance) -> Bool
let witness: (AnySecret, SigningRequestProvenance) -> ()
}
extension StubWitness: SigningWitness {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
let objection = speakNow(secret, provenance)
if objection {
throw TheresMyChance()
}
}
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
witness(secret, provenance)
}
}
extension StubWitness {
struct TheresMyChance: Error {
}
}

View File

@ -8,7 +8,7 @@ public class OpenSSHReader {
remaining = Data(data) remaining = Data(data)
} }
public func readNextChunk() -> Data { public func readNextChunk() throws -> Data {
let lengthRange = 0..<(UInt32.bitWidth/8) let lengthRange = 0..<(UInt32.bitWidth/8)
let lengthChunk = remaining[lengthRange] let lengthChunk = remaining[lengthRange]
remaining.removeSubrange(lengthRange) remaining.removeSubrange(lengthRange)

View File

@ -20,10 +20,6 @@ public class SecretStoreList: ObservableObject {
addInternal(store: modifiable) addInternal(store: modifiable)
} }
public var anyAvailable: Bool {
stores.reduce(false, { $0 || $1.isAvailable })
}
} }
extension SecretStoreList { extension SecretStoreList {

View File

@ -19,6 +19,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_NAME) is MIT Licensed.</string> <string>Copyright © 2020 Max Goedjen. All rights reserved.</string>
</dict> </dict>
</plist> </plist>

View File

@ -7,7 +7,7 @@ public protocol Secret: Identifiable, Hashable {
} }
public enum Algorithm: Hashable { public enum Algorithm {
case ellipticCurve case ellipticCurve
public init(secAttr: NSNumber) { public init(secAttr: NSNumber) {
let secAttrString = secAttr.stringValue as CFString let secAttrString = secAttr.stringValue as CFString

View File

@ -1,3 +1,11 @@
//
// SecretKit.h
// SecretKit
//
// Created by Max Goedjen on 2/18/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
//! Project version number for SecretKit. //! Project version number for SecretKit.

View File

@ -11,17 +11,16 @@ 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 fileprivate(set) var name = NSLocalizedString("Smart Card", comment: "Smart Card") public let 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.nonSecureEnclaveTokens.first tokenID = watcher.tokenIDs.filter { !$0.contains("setoken") }.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)
@ -98,14 +97,6 @@ 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,
@ -133,14 +124,6 @@ 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 {

View File

@ -1,17 +0,0 @@
import Foundation
import XCTest
@testable import SecretKit
class AnySecretTests: XCTestCase {
func testEraser() {
let secret = SmartCard.Secret(id: UUID().uuidString.data(using: .utf8)!, name: "Name", algorithm: .ellipticCurve, keySize: 256, publicKey: UUID().uuidString.data(using: .utf8)!)
let erased = AnySecret(secret)
XCTAssert(erased.id == secret.id as AnyHashable)
XCTAssert(erased.name == secret.name)
XCTAssert(erased.algorithm == secret.algorithm)
XCTAssert(erased.keySize == secret.keySize)
XCTAssert(erased.publicKey == secret.publicKey)
}
}

View File

@ -1,25 +0,0 @@
import Foundation
import XCTest
@testable import SecretKit
class OpenSSHReaderTests: XCTestCase {
func testSignatureRequest() {
let reader = OpenSSHReader(data: Constants.signatureRequest)
let hash = reader.readNextChunk()
XCTAssert(hash == Data(base64Encoded: "AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQ=="))
let dataToSign = reader.readNextChunk()
XCTAssert(dataToSign == Data(base64Encoded: "AAAAICi5xf1ixOestUlxdjvt/BDcM+rzhwy7Vo8cW5YcxA8+MgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMzg0AAAAiAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRKgm5CWzh8uUtcFQmiaCj5qUtHoDOH6zKpZYJ5UUUP1L55+hFUvKFdN3DwNgc9BHREskSgP7G5p9GgbYIyMBhC8buOVFxFtUxM+k8cktLt77iKkd1qNQq0FkQ55Kxv6QU="))
let empty = reader.readNextChunk()
XCTAssert(empty.isEmpty)
}
}
extension OpenSSHReaderTests {
enum Constants {
static let signatureRequest = Data(base64Encoded: "AAAAiAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRKgm5CWzh8uUtcFQmiaCj5qUtHoDOH6zKpZYJ5UUUP1L55+hFUvKFdN3DwNgc9BHREskSgP7G5p9GgbYIyMBhC8buOVFxFtUxM+k8cktLt77iKkd1qNQq0FkQ55Kxv6QUAAADvAAAAICi5xf1ixOestUlxdjvt/BDcM+rzhwy7Vo8cW5YcxA8+MgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMzg0AAAAiAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRKgm5CWzh8uUtcFQmiaCj5qUtHoDOH6zKpZYJ5UUUP1L55+hFUvKFdN3DwNgc9BHREskSgP7G5p9GgbYIyMBhC8buOVFxFtUxM+k8cktLt77iKkd1qNQq0FkQ55Kxv6QUAAAAA")!
}
}

View File

@ -26,30 +26,17 @@
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 */; };
506772C92425BB8500034DED /* NoStoresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506772C82425BB8500034DED /* NoStoresView.swift */; };
506772FF2426F3F400034DED /* Brief.h in Headers */ = {isa = PBXBuildFile; fileRef = 506772FD2426F3F400034DED /* Brief.h */; settings = {ATTRIBUTES = (Public, ); }; };
506773022426F3F400034DED /* Brief.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 506772FB2426F3F400034DED /* Brief.framework */; };
506773032426F3F400034DED /* Brief.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 506772FB2426F3F400034DED /* Brief.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
506773092426F3FD00034DED /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506773082426F3FD00034DED /* Updater.swift */; };
5067730C2426F40E00034DED /* Brief.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 506772FB2426F3F400034DED /* Brief.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5067730E242701BA00034DED /* OpenSSHReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067730D242701BA00034DED /* OpenSSHReaderTests.swift */; };
506773102427057600034DED /* AnySecretTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067730F2427057600034DED /* AnySecretTests.swift */; };
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 */; };
506AB87E2412334700335D91 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 506AB87E2412334700335D91 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
50731666241DF8660023809E /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50731665241DF8660023809E /* Updater.swift */; };
50731669241E00C20023809E /* NoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50731668241E00C20023809E /* NoticeView.swift */; }; 50731669241E00C20023809E /* NoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50731668241E00C20023809E /* NoticeView.swift */; };
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 */; }; 507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; };
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; }; 507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; };
507EE34224281E12003C4FE3 /* FileHandleProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */; };
507EE34624281F89003C4FE3 /* StubFileHandleReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */; };
507EE34824281FB8003C4FE3 /* StubFileHandleWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34724281FB8003C4FE3 /* StubFileHandleWriter.swift */; };
507EE34A2428263B003C4FE3 /* StubStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE3492428263B003C4FE3 /* StubStore.swift */; };
507EE34E2428784F003C4FE3 /* StubWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34D2428784F003C4FE3 /* StubWitness.swift */; };
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; }; 508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; }; 508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; }; 508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; };
@ -61,7 +48,7 @@
5099A02B23FE352C0062B6F2 /* SmartCardSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02A23FE352C0062B6F2 /* SmartCardSecret.swift */; }; 5099A02B23FE352C0062B6F2 /* SmartCardSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02A23FE352C0062B6F2 /* SmartCardSecret.swift */; };
5099A02E23FE56E10062B6F2 /* OpenSSHKeyWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02D23FE56E10062B6F2 /* OpenSSHKeyWriter.swift */; }; 5099A02E23FE56E10062B6F2 /* OpenSSHKeyWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02D23FE56E10062B6F2 /* OpenSSHKeyWriter.swift */; };
5099A075240242BA0062B6F2 /* SecretAgentKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; }; 5099A075240242BA0062B6F2 /* SecretAgentKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; };
5099A07C240242BA0062B6F2 /* AgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A07B240242BA0062B6F2 /* AgentTests.swift */; }; 5099A07C240242BA0062B6F2 /* SecretAgentKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A07B240242BA0062B6F2 /* SecretAgentKitTests.swift */; };
5099A07E240242BA0062B6F2 /* SecretAgentKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5099A06E240242BA0062B6F2 /* SecretAgentKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5099A07E240242BA0062B6F2 /* SecretAgentKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5099A06E240242BA0062B6F2 /* SecretAgentKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */; }; 5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */; };
50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; }; 50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; };
@ -114,20 +101,6 @@
remoteGlobalIDString = 50617DA723FCE4AB0099B055; remoteGlobalIDString = 50617DA723FCE4AB0099B055;
remoteInfo = SecretKit; remoteInfo = SecretKit;
}; };
506773002426F3F400034DED /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 506772FA2426F3F400034DED;
remoteInfo = Brief;
};
5067730A2426F40A00034DED /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 506772FA2426F3F400034DED;
remoteInfo = Brief;
};
507CE4F12420A6B50029F750 /* PBXContainerItemProxy */ = { 507CE4F12420A6B50029F750 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 50617D7723FCE48D0099B055 /* Project object */; containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
@ -152,7 +125,6 @@
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
50617DBE23FCE4AB0099B055 /* SecretKit.framework in Embed Frameworks */, 50617DBE23FCE4AB0099B055 /* SecretKit.framework in Embed Frameworks */,
506773032426F3F400034DED /* Brief.framework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -183,7 +155,6 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
5067730C2426F40E00034DED /* Brief.framework in Embed Frameworks */,
50A5C18D240E4B4B00E2996C /* SecretAgentKit.framework in Embed Frameworks */, 50A5C18D240E4B4B00E2996C /* SecretAgentKit.framework in Embed Frameworks */,
50A5C190240E4B4C00E2996C /* SecretKit.framework in Embed Frameworks */, 50A5C190240E4B4C00E2996C /* SecretKit.framework in Embed Frameworks */,
); );
@ -228,26 +199,14 @@
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>"; };
506772C82425BB8500034DED /* NoStoresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStoresView.swift; sourceTree = "<group>"; };
506772FB2426F3F400034DED /* Brief.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Brief.framework; sourceTree = BUILT_PRODUCTS_DIR; };
506772FD2426F3F400034DED /* Brief.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Brief.h; sourceTree = "<group>"; };
506772FE2426F3F400034DED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
506773082426F3FD00034DED /* Updater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
5067730D242701BA00034DED /* OpenSSHReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSSHReaderTests.swift; sourceTree = "<group>"; };
5067730F2427057600034DED /* AnySecretTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecretTests.swift; 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>"; };
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>"; }; 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestProvenance.swift; sourceTree = "<group>"; };
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; }; 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; };
507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileHandleProtocols.swift; sourceTree = "<group>"; };
507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFileHandleReader.swift; sourceTree = "<group>"; };
507EE34724281FB8003C4FE3 /* StubFileHandleWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFileHandleWriter.swift; sourceTree = "<group>"; };
507EE3492428263B003C4FE3 /* StubStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubStore.swift; sourceTree = "<group>"; };
507EE34D2428784F003C4FE3 /* StubWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubWitness.swift; sourceTree = "<group>"; };
508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; }; 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; 508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; }; 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; };
@ -262,7 +221,7 @@
5099A06E240242BA0062B6F2 /* SecretAgentKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecretAgentKit.h; sourceTree = "<group>"; }; 5099A06E240242BA0062B6F2 /* SecretAgentKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecretAgentKit.h; sourceTree = "<group>"; };
5099A06F240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 5099A06F240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5099A074240242BA0062B6F2 /* SecretAgentKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecretAgentKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5099A074240242BA0062B6F2 /* SecretAgentKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecretAgentKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5099A07B240242BA0062B6F2 /* AgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentTests.swift; sourceTree = "<group>"; }; 5099A07B240242BA0062B6F2 /* SecretAgentKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretAgentKitTests.swift; sourceTree = "<group>"; };
5099A07D240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 5099A07D240242BA0062B6F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHAgentProtocol.swift; sourceTree = "<group>"; }; 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHAgentProtocol.swift; sourceTree = "<group>"; };
50A3B78A24026B7500D209EA /* SecretAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecretAgent.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50A3B78A24026B7500D209EA /* SecretAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecretAgent.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -286,7 +245,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
50617DBD23FCE4AB0099B055 /* SecretKit.framework in Frameworks */, 50617DBD23FCE4AB0099B055 /* SecretKit.framework in Frameworks */,
506773022426F3F400034DED /* Brief.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -312,13 +270,6 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
506772F82426F3F400034DED /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5099A069240242BA0062B6F2 /* Frameworks */ = { 5099A069240242BA0062B6F2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -357,7 +308,6 @@
5099A06D240242BA0062B6F2 /* SecretAgentKit */, 5099A06D240242BA0062B6F2 /* SecretAgentKit */,
5099A07A240242BA0062B6F2 /* SecretAgentKitTests */, 5099A07A240242BA0062B6F2 /* SecretAgentKitTests */,
508A58AF241E144C0069DC07 /* Config */, 508A58AF241E144C0069DC07 /* Config */,
506772FC2426F3F400034DED /* Brief */,
50617D8023FCE48E0099B055 /* Products */, 50617D8023FCE48E0099B055 /* Products */,
5099A08B240243730062B6F2 /* Frameworks */, 5099A08B240243730062B6F2 /* Frameworks */,
); );
@ -373,7 +323,6 @@
5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */, 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */,
5099A074240242BA0062B6F2 /* SecretAgentKitTests.xctest */, 5099A074240242BA0062B6F2 /* SecretAgentKitTests.xctest */,
50A3B78A24026B7500D209EA /* SecretAgent.app */, 50A3B78A24026B7500D209EA /* SecretAgent.app */,
506772FB2426F3F400034DED /* Brief.framework */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -388,7 +337,6 @@
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;
@ -432,8 +380,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */, 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */,
5067730D242701BA00034DED /* OpenSSHReaderTests.swift */,
5067730F2427057600034DED /* AnySecretTests.swift */,
50617DB923FCE4AB0099B055 /* Info.plist */, 50617DB923FCE4AB0099B055 /* Info.plist */,
); );
path = SecretKitTests; path = SecretKitTests;
@ -449,16 +395,6 @@
path = SecureEnclave; path = SecureEnclave;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
506772FC2426F3F400034DED /* Brief */ = {
isa = PBXGroup;
children = (
506773082426F3FD00034DED /* Updater.swift */,
506772FD2426F3F400034DED /* Brief.h */,
506772FE2426F3F400034DED /* Info.plist */,
);
path = Brief;
sourceTree = "<group>";
};
5068389F2415EA4F00F55094 /* Erasers */ = { 5068389F2415EA4F00F55094 /* Erasers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -495,7 +431,6 @@
5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */, 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */,
50B8550C24138C4F009958AC /* DeleteSecretView.swift */, 50B8550C24138C4F009958AC /* DeleteSecretView.swift */,
50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */, 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */,
506772C82425BB8500034DED /* NoStoresView.swift */,
50C385A8240B636500AF2719 /* SetupView.swift */, 50C385A8240B636500AF2719 /* SetupView.swift */,
); );
path = Views; path = Views;
@ -504,6 +439,7 @@
508A58B1241ED1EA0069DC07 /* Controllers */ = { 508A58B1241ED1EA0069DC07 /* Controllers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50731665241DF8660023809E /* Updater.swift */,
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */, 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
); );
path = Controllers; path = Controllers;
@ -539,7 +475,6 @@
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */, 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */, 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */,
50A3B79F24026B9900D209EA /* Agent.swift */, 50A3B79F24026B9900D209EA /* Agent.swift */,
507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */,
5099A06F240242BA0062B6F2 /* Info.plist */, 5099A06F240242BA0062B6F2 /* Info.plist */,
); );
path = SecretAgentKit; path = SecretAgentKit;
@ -548,11 +483,7 @@
5099A07A240242BA0062B6F2 /* SecretAgentKitTests */ = { 5099A07A240242BA0062B6F2 /* SecretAgentKitTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5099A07B240242BA0062B6F2 /* AgentTests.swift */, 5099A07B240242BA0062B6F2 /* SecretAgentKitTests.swift */,
507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */,
507EE34724281FB8003C4FE3 /* StubFileHandleWriter.swift */,
507EE34D2428784F003C4FE3 /* StubWitness.swift */,
507EE3492428263B003C4FE3 /* StubStore.swift */,
5099A07D240242BA0062B6F2 /* Info.plist */, 5099A07D240242BA0062B6F2 /* Info.plist */,
); );
path = SecretAgentKitTests; path = SecretAgentKitTests;
@ -598,14 +529,6 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
506772F62426F3F400034DED /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
506772FF2426F3F400034DED /* Brief.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5099A067240242BA0062B6F2 /* Headers */ = { 5099A067240242BA0062B6F2 /* Headers */ = {
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -631,7 +554,6 @@
); );
dependencies = ( dependencies = (
50617DBC23FCE4AB0099B055 /* PBXTargetDependency */, 50617DBC23FCE4AB0099B055 /* PBXTargetDependency */,
506773012426F3F400034DED /* PBXTargetDependency */,
); );
name = Secretive; name = Secretive;
productName = Secretive; productName = Secretive;
@ -693,24 +615,6 @@
productReference = 50617DB023FCE4AB0099B055 /* SecretKitTests.xctest */; productReference = 50617DB023FCE4AB0099B055 /* SecretKitTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test"; productType = "com.apple.product-type.bundle.unit-test";
}; };
506772FA2426F3F400034DED /* Brief */ = {
isa = PBXNativeTarget;
buildConfigurationList = 506773042426F3F400034DED /* Build configuration list for PBXNativeTarget "Brief" */;
buildPhases = (
506772F62426F3F400034DED /* Headers */,
506772F72426F3F400034DED /* Sources */,
506772F82426F3F400034DED /* Frameworks */,
506772F92426F3F400034DED /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Brief;
productName = Brief;
productReference = 506772FB2426F3F400034DED /* Brief.framework */;
productType = "com.apple.product-type.framework";
};
5099A06B240242BA0062B6F2 /* SecretAgentKit */ = { 5099A06B240242BA0062B6F2 /* SecretAgentKit */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 5099A083240242BA0062B6F2 /* Build configuration list for PBXNativeTarget "SecretAgentKit" */; buildConfigurationList = 5099A083240242BA0062B6F2 /* Build configuration list for PBXNativeTarget "SecretAgentKit" */;
@ -763,7 +667,6 @@
dependencies = ( dependencies = (
5018F5492402736A002EB505 /* PBXTargetDependency */, 5018F5492402736A002EB505 /* PBXTargetDependency */,
5018F54B2402736A002EB505 /* PBXTargetDependency */, 5018F54B2402736A002EB505 /* PBXTargetDependency */,
5067730B2426F40A00034DED /* PBXTargetDependency */,
); );
name = SecretAgent; name = SecretAgent;
productName = SecretAgent; productName = SecretAgent;
@ -794,10 +697,6 @@
50617DAF23FCE4AB0099B055 = { 50617DAF23FCE4AB0099B055 = {
CreatedOnToolsVersion = 11.3; CreatedOnToolsVersion = 11.3;
}; };
506772FA2426F3F400034DED = {
CreatedOnToolsVersion = 11.4;
LastSwiftMigration = 1140;
};
5099A06B240242BA0062B6F2 = { 5099A06B240242BA0062B6F2 = {
CreatedOnToolsVersion = 11.4; CreatedOnToolsVersion = 11.4;
LastSwiftMigration = 1140; LastSwiftMigration = 1140;
@ -830,7 +729,6 @@
50617DAF23FCE4AB0099B055 /* SecretKitTests */, 50617DAF23FCE4AB0099B055 /* SecretKitTests */,
5099A06B240242BA0062B6F2 /* SecretAgentKit */, 5099A06B240242BA0062B6F2 /* SecretAgentKit */,
5099A073240242BA0062B6F2 /* SecretAgentKitTests */, 5099A073240242BA0062B6F2 /* SecretAgentKitTests */,
506772FA2426F3F400034DED /* Brief */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -843,7 +741,6 @@
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;
}; };
@ -868,13 +765,6 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
506772F92426F3F400034DED /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5099A06A240242BA0062B6F2 /* Resources */ = { 5099A06A240242BA0062B6F2 /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -912,11 +802,11 @@
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */, 508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */,
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */, 50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */, 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
50731666241DF8660023809E /* Updater.swift in Sources */,
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */, 50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */,
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */, 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */,
50731669241E00C20023809E /* NoticeView.swift in Sources */, 50731669241E00C20023809E /* NoticeView.swift in Sources */,
50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */, 50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */,
506772C92425BB8500034DED /* NoStoresView.swift in Sources */,
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */, 508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */,
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */, 508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */,
); );
@ -955,16 +845,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */, 50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */,
506773102427057600034DED /* AnySecretTests.swift in Sources */,
5067730E242701BA00034DED /* OpenSSHReaderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
506772F72426F3F400034DED /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
506773092426F3FD00034DED /* Updater.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -972,7 +852,6 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
507EE34224281E12003C4FE3 /* FileHandleProtocols.swift in Sources */,
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */, 507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */,
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */, 5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */,
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */, 507CE4ED2420A3C70029F750 /* Agent.swift in Sources */,
@ -986,11 +865,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
507EE34E2428784F003C4FE3 /* StubWitness.swift in Sources */, 5099A07C240242BA0062B6F2 /* SecretAgentKitTests.swift in Sources */,
507EE34624281F89003C4FE3 /* StubFileHandleReader.swift in Sources */,
507EE34A2428263B003C4FE3 /* StubStore.swift in Sources */,
5099A07C240242BA0062B6F2 /* AgentTests.swift in Sources */,
507EE34824281FB8003C4FE3 /* StubFileHandleWriter.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -1031,16 +906,6 @@
target = 50617DA723FCE4AB0099B055 /* SecretKit */; target = 50617DA723FCE4AB0099B055 /* SecretKit */;
targetProxy = 50617DBB23FCE4AB0099B055 /* PBXContainerItemProxy */; targetProxy = 50617DBB23FCE4AB0099B055 /* PBXContainerItemProxy */;
}; };
506773012426F3F400034DED /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 506772FA2426F3F400034DED /* Brief */;
targetProxy = 506773002426F3F400034DED /* PBXContainerItemProxy */;
};
5067730B2426F40A00034DED /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 506772FA2426F3F400034DED /* Brief */;
targetProxy = 5067730A2426F40A00034DED /* PBXContainerItemProxy */;
};
507CE4F22420A6B50029F750 /* PBXTargetDependency */ = { 507CE4F22420A6B50029F750 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 50617DA723FCE4AB0099B055 /* SecretKit */; target = 50617DA723FCE4AB0099B055 /* SecretKit */;
@ -1385,95 +1250,6 @@
}; };
name = Release; name = Release;
}; };
506773052426F3F400034DED /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Brief/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
506773062426F3F400034DED /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Brief/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Test;
};
506773072426F3F400034DED /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Brief/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
508A5914241EF1A00069DC07 /* Test */ = { 508A5914241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */; baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
@ -1647,8 +1423,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6; DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretKitTests/Info.plist; INFOPLIST_FILE = SecretKitTests/Info.plist;
@ -1659,7 +1435,6 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Test; name = Test;
@ -1698,8 +1473,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6; DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretAgentKitTests/Info.plist; INFOPLIST_FILE = SecretAgentKitTests/Info.plist;
@ -1710,7 +1484,6 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Test; name = Test;
@ -1778,7 +1551,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6; DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretAgentKitTests/Info.plist; INFOPLIST_FILE = SecretAgentKitTests/Info.plist;
@ -1797,7 +1569,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6; DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretAgentKitTests/Info.plist; INFOPLIST_FILE = SecretAgentKitTests/Info.plist;
@ -1915,16 +1686,6 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
506773042426F3F400034DED /* Build configuration list for PBXNativeTarget "Brief" */ = {
isa = XCConfigurationList;
buildConfigurations = (
506773052426F3F400034DED /* Debug */,
506773062426F3F400034DED /* Test */,
506773072426F3F400034DED /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5099A083240242BA0062B6F2 /* Build configuration list for PBXNativeTarget "SecretAgentKit" */ = { 5099A083240242BA0062B6F2 /* Build configuration list for PBXNativeTarget "SecretAgentKit" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (

View File

@ -67,7 +67,7 @@
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"

View File

@ -1,7 +1,6 @@
import Cocoa import Cocoa
import SwiftUI import SwiftUI
import SecretKit import SecretKit
import Brief
@NSApplicationMain @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
@ -67,7 +66,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBAction func runSetup(sender: AnyObject?) { @IBAction func runSetup(sender: AnyObject?) {
let setupWindow = NSWindow( let setupWindow = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 0, height: 0), contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false) backing: .buffered, defer: false)
let setupView = SetupView() { success in let setupView = SetupView() { success in

View File

@ -1,17 +1,17 @@
import Foundation import Foundation
import Combine import Combine
public protocol UpdaterProtocol: ObservableObject { protocol UpdaterProtocol: ObservableObject {
var update: Release? { get } var update: Release? { get }
} }
public class Updater: ObservableObject, UpdaterProtocol { class Updater: ObservableObject, UpdaterProtocol {
@Published public var update: Release? @Published var update: Release?
public init() { init() {
checkForUpdates() checkForUpdates()
let timer = Timer.scheduledTimer(withTimeInterval: 60*60*24, repeats: true) { _ in let timer = Timer.scheduledTimer(withTimeInterval: 60*60*24, repeats: true) { _ in
self.checkForUpdates() self.checkForUpdates()
@ -19,7 +19,7 @@ public class Updater: ObservableObject, UpdaterProtocol {
timer.tolerance = 60*60 timer.tolerance = 60*60
} }
public func checkForUpdates() { func checkForUpdates() {
URLSession.shared.dataTask(with: Constants.updateURL) { data, _, _ in URLSession.shared.dataTask(with: Constants.updateURL) { data, _, _ in
guard let data = data else { return } guard let data = data else { return }
guard let release = try? JSONDecoder().decode(Release.self, from: data) else { return } guard let release = try? JSONDecoder().decode(Release.self, from: data) else { return }
@ -27,20 +27,7 @@ public class Updater: ObservableObject, UpdaterProtocol {
}.resume() }.resume()
} }
public func ignore(release: Release) {
guard !release.critical else { return }
defaults.set(true, forKey: release.name)
DispatchQueue.main.async {
self.update = nil
}
}
}
extension Updater {
func evaluate(release: Release) { func evaluate(release: Release) {
guard !userIgnored(release: release) else { return }
let latestVersion = semVer(from: release.name) let latestVersion = semVer(from: release.name)
let currentVersion = semVer(from: Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String) let currentVersion = semVer(from: Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String)
for (latest, current) in zip(latestVersion, currentVersion) { for (latest, current) in zip(latestVersion, currentVersion) {
@ -61,14 +48,6 @@ extension Updater {
return split return split
} }
func userIgnored(release: Release) -> Bool {
guard !release.critical else { return false }
return defaults.bool(forKey: release.name)
}
var defaults: UserDefaults {
UserDefaults(suiteName: "com.maxgoedjen.Secretive.updater.ignorelist")!
}
} }
extension Updater { extension Updater {
@ -79,24 +58,16 @@ extension Updater {
} }
public struct Release: Codable { struct Release: Codable {
let name: String
public let name: String let html_url: URL
public let html_url: URL let body: String
public let body: String
public init(name: String, html_url: URL, body: String) {
self.name = name
self.html_url = html_url
self.body = body
}
} }
extension Release { extension Release {
public var critical: Bool { var critical: Bool {
return body.contains(Constants.securityContent) return body.contains(Constants.securityContent)
} }

View File

@ -1,23 +0,0 @@
{\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 GitHub Repository}}
\f0\fs24 \
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
\cf0 \
{\field{\*\fldinst{HYPERLINK "GITHUB_BUILD_URL"}}{\fldrslt Build Log}}\
\
Special Thanks To:\
{\field{\*\fldinst{HYPERLINK "https://github.com/bdash"}}{\fldrslt Mark Rowe}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/danielctull"}}{\fldrslt Daniel Tull}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/davedelong"}}{\fldrslt Dave DeLong}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/esttorhe"}}{\fldrslt Esteban Torres}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/joeblau"}}{\fldrslt Joe Blau}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/marksands"}}{\fldrslt Mark Sands}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/mergesort"}}{\fldrslt Joe Fabisevich}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/phillco"}}{\fldrslt Phil Cohen}}\
{\field{\*\fldinst{HYPERLINK "https://github.com/zackdotcomputer"}}{\fldrslt Zack Sheppard}}}

View File

@ -19,11 +19,11 @@
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(CI_VERSION)</string> <string>$(CI_VERSION)</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CI_BUILD_NUMBER)</string> <string>$(CI_VERSION)</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_NAME) is MIT Licensed.</string> <string>Copyright © 2020 Max Goedjen. All rights reserved.</string>
<key>NSMainStoryboardFile</key> <key>NSMainStoryboardFile</key>
<string>Main</string> <string>Main</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>

View File

@ -1,6 +1,5 @@
import Foundation import Foundation
import Combine import Combine
import Brief
class PreviewUpdater: UpdaterProtocol { class PreviewUpdater: UpdaterProtocol {

View File

@ -1,6 +1,5 @@
import SwiftUI import SwiftUI
import SecretKit import SecretKit
import Brief
struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentStatusCheckerProtocol>: View { struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentStatusCheckerProtocol>: View {
@ -21,7 +20,6 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
if !agentStatusChecker.running { if !agentStatusChecker.running {
agentNotice() agentNotice()
} }
if storeList.anyAvailable {
NavigationView { NavigationView {
List(selection: $active) { List(selection: $active) {
ForEach(storeList.stores) { store in ForEach(storeList.stores) { store in
@ -70,10 +68,7 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
} }
} }
} }
} else { }
NoStoresView()
}
}.frame(minWidth: 640, minHeight: 320)
} }
func updateNotice() -> some View { func updateNotice() -> some View {

View File

@ -1,29 +0,0 @@
//
// NoStoresView.swift
// Secretive
//
// Created by Max Goedjen on 3/20/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
import SwiftUI
struct NoStoresView: View {
var body: some View {
VStack {
Text("No Secure Storage Available").bold()
Text("Your Mac doesn't have a Secure Enclave, and there's not a compatible Smart Card inserted.")
Button(action: {
NSWorkspace.shared.open(URL(string: "https://www.yubico.com/products/compare-yubikey-5-series/")!)
}) {
Text("If you're looking to add one to your Mac, the YubiKey 5 Series are great.")
}
}.padding()
}
}
struct NoStoresView_Previews: PreviewProvider {
static var previews: some View {
NoStoresView()
}
}

View File

@ -3,18 +3,18 @@ import SwiftUI
import ServiceManagement import ServiceManagement
struct SetupView: View { struct SetupView: View {
var completion: ((Bool) -> Void)? var completion: ((Bool) -> Void)?
var body: some View { var body: some View {
Form { Form {
SetupStepView<Spacer>(text: "Secretive needs to install a helper app to sign requests when the main app isn't running. This app is called \"SecretAgent\" and you might see it in Activity Manager from time to time.", SetupStepView<Spacer>(text: "Secretive needs to install a helper app to sign requests when the main app isn't running. This app is called \"SecretAgent\" and you might see it in Activity Manager from time to time.",
index: 1, index: 1,
nestedView: nil, nestedView: nil,
actionText: "Install") { actionText: "Install") {
self.installLaunchAgent() self.installLaunchAgent()
} }
SetupStepView(text: "Add this line to your shell config (.bashrc or .zshrc) telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.", SetupStepView(text: "You need to add a line to your shell config (.bashrc or .zshrc) telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.",
index: 2, index: 2,
nestedView: SetupStepCommandView(text: Constants.socketPrompt), nestedView: SetupStepCommandView(text: Constants.socketPrompt),
actionText: "Added") { actionText: "Added") {
@ -22,25 +22,25 @@ struct SetupView: View {
} }
HStack { HStack {
Spacer() Spacer()
Button(action: { self.completion?(true) }) { Button(action: { self.completion?(true) }) {
Text("Finish") Text("Finish")
} }
.padding() .padding()
} }
}.frame(minWidth: 640, minHeight: 400) }
} }
} }
struct SetupStepView<NestedViewType: View>: View { struct SetupStepView<NestedViewType: View>: View {
let text: String let text: String
let index: Int let index: Int
let nestedView: NestedViewType? let nestedView: NestedViewType?
@State var completed = false @State var completed = false
let actionText: String let actionText: String
let action: (() -> Bool) let action: (() -> Bool)
var body: some View { var body: some View {
Section { Section {
HStack { HStack {
@ -64,8 +64,10 @@ struct SetupStepView<NestedViewType: View>: View {
Text(text) Text(text)
.opacity(completed ? 0.5 : 1) .opacity(completed ? 0.5 : 1)
.lineLimit(nil) .lineLimit(nil)
.frame(idealHeight: 0, maxHeight: .infinity)
if nestedView != nil { if nestedView != nil {
nestedView!.padding() Spacer()
nestedView!
} }
} }
.padding() .padding()
@ -81,58 +83,43 @@ struct SetupStepView<NestedViewType: View>: View {
} }
struct SetupStepCommandView: View { struct SetupStepCommandView: View {
let text: String let text: String
var body: some View { var body: some View {
VStack(alignment: .leading) { Text(text)
Text(text) .font(.system(.caption, design: .monospaced))
.lineLimit(nil) .lineLimit(nil)
.font(.system(.caption, design: .monospaced)) .frame(idealHeight: 0, maxHeight: .infinity)
.multilineTextAlignment(.leading) .padding()
.frame(minHeight: 50) .background(Color(white: 0, opacity: 0.10))
HStack { .cornerRadius(10)
Spacer() .onDrag {
Button(action: copy) { return NSItemProvider(item: NSData(data: self.text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
Text("Copy")
}
}
}
.padding()
.background(Color(white: 0, opacity: 0.10))
.cornerRadius(10)
.onDrag {
return NSItemProvider(item: NSData(data: self.text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
} }
} }
func copy() {
NSPasteboard.general.declareTypes([.string], owner: nil)
NSPasteboard.general.setString(text, forType: .string)
}
} }
extension SetupView { extension SetupView {
func installLaunchAgent() -> Bool { func installLaunchAgent() -> Bool {
SMLoginItemSetEnabled("com.maxgoedjen.Secretive.SecretAgent" as CFString, true) SMLoginItemSetEnabled("com.maxgoedjen.Secretive.SecretAgent" as CFString, true)
} }
func markAsDone() -> Bool { func markAsDone() -> Bool {
return true return true
} }
} }
extension SetupView { extension SetupView {
enum Constants { enum Constants {
static let socketPath = (NSHomeDirectory().replacingOccurrences(of: "com.maxgoedjen.Secretive.Host", with: "com.maxgoedjen.Secretive.SecretAgent") as NSString).appendingPathComponent("socket.ssh") as String static let socketPath = (NSHomeDirectory().replacingOccurrences(of: "com.maxgoedjen.Secretive.Host", with: "com.maxgoedjen.Secretive.SecretAgent") as NSString).appendingPathComponent("socket.ssh") as String
static let socketPrompt = "export SSH_AUTH_SOCK=\(socketPath)" static let socketPrompt = "export SSH_AUTH_SOCK=\(socketPath)"
} }
} }
#if DEBUG #if DEBUG

View File

@ -1,3 +1,11 @@
//
// SecretiveTests.swift
// SecretiveTests
//
// Created by Max Goedjen on 2/18/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
import XCTest import XCTest
@testable import Secretive @testable import Secretive