Compare commits

..

30 Commits

Author SHA1 Message Date
2257e1e190 Fix build number 2020-03-19 21:21:28 -07:00
fe16e4d9c4 Build and About page (#64)
* Adding credits txt

* Switch up build number
2020-03-19 21:16:14 -07:00
1caf65c68d Header cleanup 2020-03-18 20:04:48 -07:00
85eb4983bc Split witness call (fixes #62) 2020-03-18 20:04:24 -07:00
5a2d3ecc2e Fix dumb mistake. 2020-03-17 23:28:51 -07:00
32f0ed88f4 Validate code signature as well. 2020-03-17 22:59:03 -07:00
d35c58509b Hacky fix for #16 2020-03-17 20:41:37 -07:00
f810b185f0 Fix debug config for running 2020-03-17 20:34:32 -07:00
5ef1fe996b Add path to request trace (#61) 2020-03-17 01:23:49 -07:00
2b5fdf541d Request Attribution (#59) 2020-03-17 00:56:55 -07:00
4b66e874a7 Cleanup of agent (#58)
* Extract key selection.

* Moving agent and socket stuff to SecretAgentKit

* Cleanup of agent
2020-03-16 23:39:34 -07:00
aa52da2c04 OpenSSH writer tests (#57) 2020-03-16 23:08:48 -07:00
bd683b16f2 Fix #53 (#54) 2020-03-15 18:30:45 -07:00
017bdb85a4 Test infrastructure (#52)
* Adding tests target

* Adding test plan

* Fixing deps

* Add test workflow

* Add config

* More

* Change workflow

* Add test step to release

* Signing changes

* Signing changes

* Remove 11.4 specific test

* More signing
2020-03-15 17:04:20 -07:00
99c8562cf5 Set Up -> Setup 2020-03-15 16:14:02 -07:00
12b920b0af Fix window close behavior (fixes #48) 2020-03-15 16:03:20 -07:00
bfb4f80b8c Self 2020-03-15 15:57:11 -07:00
d661b9002b Run status check on setup dismiss (fixes #49) 2020-03-15 15:56:21 -07:00
9daae8957a Add notice if agent isn't running (#47)
* Add agent checker
* Check on foreground
2020-03-15 14:36:07 -07:00
bde9085d31 Reorg 2020-03-15 14:13:28 -07:00
84521cf8d6 Fixes #44 2020-03-15 14:03:57 -07:00
4a6e8c0b11 Add run ID 2020-03-15 01:17:45 -07:00
ae06e8e892 Fix updater ref 2020-03-15 01:11:16 -07:00
57e6b6779f Fix sed. 2020-03-15 01:08:41 -07:00
6136fc2e69 Updater (#43) 2020-03-15 01:01:40 -07:00
2c052e2657 Update CONTRIBUTING.md 2020-03-14 21:51:50 -07:00
0918e570e4 Add security contact email 2020-03-14 21:48:34 -07:00
024c25bcd9 Create CONTRIBUTING.md 2020-03-14 21:44:11 -07:00
154dac3e50 Add CoC 2020-03-14 21:31:45 -07:00
d778760cc1 Update README.md 2020-03-14 19:58:48 -07:00
45 changed files with 1273 additions and 262 deletions

View File

@ -5,6 +5,20 @@ on:
tags: tags:
- '*' - '*'
jobs: jobs:
test:
runs-on: macOS-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v1
- name: Setup Signing
env:
SIGNING_DATA: ${{ secrets.SIGNING_DATA }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
HOST_PROFILE_DATA: ${{ secrets.HOST_PROFILE_DATA }}
AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }}
run: ./.github/scripts/signing.sh
- name: Test
run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive
build: build:
runs-on: macOS-latest runs-on: macOS-latest
timeout-minutes: 10 timeout-minutes: 10
@ -18,16 +32,25 @@ jobs:
with: with:
tag_name: ${{ github.ref }} tag_name: ${{ github.ref }}
release_name: ${{ github.ref }} release_name: ${{ github.ref }}
body: '' body: "Build: https://github.com/maxgoedjen/secretive/actions/runs/${{ github.run_id }}"
draft: true draft: true
prerelease: false prerelease: false
- name: Set up signing - name: Setup Signing
env: env:
SIGNING_DATA: ${{ secrets.SIGNING_DATA }} SIGNING_DATA: ${{ secrets.SIGNING_DATA }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
HOST_PROFILE_DATA: ${{ secrets.HOST_PROFILE_DATA }} HOST_PROFILE_DATA: ${{ secrets.HOST_PROFILE_DATA }}
AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }} AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }}
run: ./.github/scripts/signing.sh run: ./.github/scripts/signing.sh
- name: Update Build Number
env:
TAG_NAME: ${{ github.ref }}
RUN_ID: ${{ github.run_id }}
run: |
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/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

18
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: Test
on: push
jobs:
test:
runs-on: macOS-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v1
- name: Setup Signing
env:
SIGNING_DATA: ${{ secrets.SIGNING_DATA }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
HOST_PROFILE_DATA: ${{ secrets.HOST_PROFILE_DATA }}
AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }}
run: ./.github/scripts/signing.sh
- name: Test
run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive

76
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at max.goedjen@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

19
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,19 @@
# Contributing to Secretive
Thanks for your interest in contributing to Secretive! Before you contribute, there are a few things I'd like to lay out.
## Security
Security is obviously paramount for a project like Secretive. As such, any contributions that compromise the security or auditabilty of the project will be rejected.
### Dependencies
Secretive is desigend to be easily auditable by people who are considering using it. In keeping with this, Secretive has no third party dependencies, and any contributions which bring in new dependencies will be rejected.
## Code of Conduct
All contributors must abide by the [Code of Conduct](CODE_OF_CONDUCT.md)
## Secretive is Opinionated
I'm releasing Secretive as open source so that other people can use it and audit it, feeling comfortable in knowing that the source is available so they can see what it's doing. I have a pretty strong idea of what I'd like this project to look like, and I may respectfully decline contributions that don't line up with that vision. If you'd like to propose a change before implementing, please feel free to [Open an Issue with the proposed tag](https://github.com/maxgoedjen/secretive/issues/new?labels=proposed).

2
Config/Config.xcconfig Normal file
View File

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

View File

@ -0,0 +1,41 @@
{
"configurations" : [
{
"id" : "5896AE5A-6D5A-48D3-837B-668B646A3273",
"name" : "Configuration 1",
"options" : {
}
}
],
"defaultOptions" : {
},
"testTargets" : [
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:Secretive.xcodeproj",
"identifier" : "50617DAF23FCE4AB0099B055",
"name" : "SecretKitTests"
}
},
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:Secretive.xcodeproj",
"identifier" : "5099A073240242BA0062B6F2",
"name" : "SecretAgentKitTests"
}
},
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:Secretive.xcodeproj",
"identifier" : "50617D9323FCE48E0099B055",
"name" : "SecretiveTests"
}
}
],
"version" : 1
}

View File

@ -38,7 +38,7 @@ For non-command-line based apps, like GUI Git clients, you may need to go throug
### Security Considerations ### Security Considerations
For the moment, you must build Secretive from source. For an app like this, it's critical that you trust that the app you're running is the app whose source you've checked out. To this end, Secretive has no third party dependecies, and is designed to be easy for you to audit for exploits. Builds are produced by GitHub Actions with an auditable build and release generation process. Each build has a "Document SHAs" step, which will output SHA checksums for the build produced by the GitHub Action, so you can verify that the source code for a given build corresponds to any given release.
### A Note Around Code Signing and Keychains ### A Note Around Code Signing and Keychains
@ -47,3 +47,7 @@ While Secretive uses the Secure Enclave for key storage, it still relies on Keyc
### Backups and Transfers to New Machines ### Backups and Transfers to New Machines
Beacuse secrets in the Secure Enclave are not exportable, they are not able to be backed up, and you will not be able to transfer them to a new machine. If you get a new Mac, just create a new set of secrets specific to that Mac. Beacuse secrets in the Secure Enclave are not exportable, they are not able to be backed up, and you will not be able to transfer them to a new machine. If you get a new Mac, just create a new set of secrets specific to that Mac.
## Security
If you discover any vulnerabilities in this project, please notify max.goedjen@gmail.com

View File

@ -1,5 +1,6 @@
import Cocoa import Cocoa
import SecretKit import SecretKit
import SecretAgentKit
import OSLog import OSLog
@NSApplicationMain @NSApplicationMain
@ -13,7 +14,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}() }()
let notifier = Notifier() let notifier = Notifier()
lazy var agent: Agent = { lazy var agent: Agent = {
Agent(storeList: storeList, notifier: notifier) Agent(storeList: storeList, witness: notifier)
}() }()
lazy var socketController: SocketController = { lazy var socketController: SocketController = {
let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string> <string>$(CI_VERSION)</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import SecretKit import SecretKit
import SecretAgentKit
import UserNotifications import UserNotifications
class Notifier { class Notifier {
@ -10,13 +11,24 @@ class Notifier {
} }
} }
func notify<SecretType: Secret>(accessTo secret: SecretType) { func notify(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) {
let notificationCenter = UNUserNotificationCenter.current() let notificationCenter = UNUserNotificationCenter.current()
let notificationContent = UNMutableNotificationContent() let notificationContent = UNMutableNotificationContent()
notificationContent.title = "Signed Request" notificationContent.title = "Signed Request"
notificationContent.body = "\(secret.name) was used to sign a request." notificationContent.body = "\(secret.name) was used to sign a request from \(provenance.origin.name)."
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil) let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
notificationCenter.add(request, withCompletionHandler: nil) notificationCenter.add(request, withCompletionHandler: nil)
} }
} }
extension Notifier: SigningWitness {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
}
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
notify(accessTo: secret, by: provenance)
}
}

View File

@ -3,23 +3,26 @@ import CryptoKit
import OSLog import OSLog
import SecretKit import SecretKit
import SecretAgentKit import SecretAgentKit
import AppKit
class Agent { public class Agent {
fileprivate let storeList: SecretStoreList fileprivate let storeList: SecretStoreList
fileprivate let notifier: Notifier fileprivate let witness: SigningWitness?
fileprivate let writer = OpenSSHKeyWriter()
fileprivate let requestTracer = SigningRequestTracer()
public init(storeList: SecretStoreList, notifier: Notifier) { public init(storeList: SecretStoreList, witness: SigningWitness? = nil) {
os_log(.debug, "Agent is running") os_log(.debug, "Agent is running")
self.storeList = storeList self.storeList = storeList
self.notifier = notifier self.witness = witness
} }
} }
extension Agent { extension Agent {
func handle(fileHandle: FileHandle) { public func handle(fileHandle: FileHandle) {
os_log(.debug, "Agent handling new data") os_log(.debug, "Agent handling new data")
let data = fileHandle.availableData let data = fileHandle.availableData
guard !data.isEmpty else { return } guard !data.isEmpty else { return }
@ -40,7 +43,7 @@ extension Agent {
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)
case .signRequest: case .signRequest:
response.append(SSHAgent.ResponseType.agentSignResponse.data) response.append(SSHAgent.ResponseType.agentSignResponse.data)
response.append(try sign(data: data)) response.append(try sign(data: data, from: fileHandle.fileDescriptor))
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription) os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription)
} }
} catch { } catch {
@ -74,26 +77,22 @@ extension Agent {
return countData + keyData return countData + keyData
} }
func sign(data: Data) throws -> Data { func sign(data: Data, from pid: Int32) throws -> Data {
let reader = OpenSSHReader(data: data) let reader = OpenSSHReader(data: data)
let writer = OpenSSHKeyWriter()
let hash = try reader.readNextChunk() let hash = try reader.readNextChunk()
let matching = storeList.stores.compactMap { store -> (AnySecretStore, AnySecret)? in guard let (store, secret) = secret(matching: hash) else {
let allMatching = store.secrets.filter { secret in os_log(.debug, "Agent did not have a key matching %@", hash as NSData)
hash == writer.data(secret: secret)
}
if let matching = allMatching.first {
return (store, matching)
}
return nil
}
guard let (store, secret) = matching.first else {
throw AgentError.noMatchingKey throw AgentError.noMatchingKey
} }
let provenance = requestTracer.provenance(from: pid)
if let witness = witness {
try witness.speakNowOrForeverHoldYourPeace(forAccessTo: secret, by: provenance)
}
let dataToSign = try 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)
// TODO: Move this
notifier.notify(accessTo: 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)!
// Convert from DER formatted rep to raw (r||s) // Convert from DER formatted rep to raw (r||s)
@ -123,6 +122,10 @@ extension Agent {
sub.append(writer.lengthAndData(of: signatureChunk)) sub.append(writer.lengthAndData(of: signatureChunk))
signedData.append(writer.lengthAndData(of: sub)) signedData.append(writer.lengthAndData(of: sub))
if let witness = witness {
try witness.witness(accessTo: secret, by: provenance)
}
os_log(.debug, "Agent signed request") os_log(.debug, "Agent signed request")
return signedData return signedData
@ -130,6 +133,22 @@ extension Agent {
} }
extension Agent {
func secret(matching hash: Data) -> (AnySecretStore, AnySecret)? {
storeList.stores.compactMap { store -> (AnySecretStore, AnySecret)? in
let allMatching = store.secrets.filter { secret in
hash == writer.data(secret: secret)
}
if let matching = allMatching.first {
return (store, matching)
}
return nil
}.first
}
}
extension Agent { extension Agent {

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>$(CI_VERSION)</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>

View File

@ -7,6 +7,16 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <Security/Security.h>
// Forward declarations
// from libproc.h
int proc_pidpath(int pid, void * buffer, uint32_t buffersize);
// from SecTask.h
OSStatus SecCodeCreateWithPID(int32_t, SecCSFlags, SecCodeRef *);
//! Project version number for SecretAgentKit. //! Project version number for SecretAgentKit.
FOUNDATION_EXPORT double SecretAgentKitVersionNumber; FOUNDATION_EXPORT double SecretAgentKitVersionNumber;
@ -14,6 +24,4 @@ FOUNDATION_EXPORT double SecretAgentKitVersionNumber;
//! Project version string for SecretAgentKit. //! Project version string for SecretAgentKit.
FOUNDATION_EXPORT const unsigned char SecretAgentKitVersionString[]; FOUNDATION_EXPORT const unsigned char SecretAgentKitVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <SecretAgentKit/PublicHeader.h>

View File

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

View File

@ -0,0 +1,43 @@
import Foundation
import AppKit
import Security
struct SigningRequestTracer {
func provenance(from pid: Int32) -> SigningRequestProvenance {
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
var len = socklen_t(MemoryLayout<Int32>.size)
getsockopt(pid, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len)
let pid = pidPointer.load(as: Int32.self)
let firstInfo = process(from: pid)
var provenance = SigningRequestProvenance(root: firstInfo)
while NSRunningApplication(processIdentifier: provenance.origin.pid) == nil && provenance.origin.parentPID != nil {
provenance.chain.append(process(from: provenance.origin.parentPID!))
}
return provenance
}
func pidAndNameInfo(from pid: Int32) -> kinfo_proc {
var len = MemoryLayout<kinfo_proc>.size
let infoPointer = UnsafeMutableRawPointer.allocate(byteCount: len, alignment: 1)
var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, pid]
sysctl(&name, UInt32(name.count), infoPointer, &len, nil, 0)
return infoPointer.load(as: kinfo_proc.self)
}
func process(from pid: Int32) -> SigningRequestProvenance.Process {
var pidAndNameInfo = self.pidAndNameInfo(from: pid)
let ppid = pidAndNameInfo.kp_eproc.e_ppid != 0 ? pidAndNameInfo.kp_eproc.e_ppid : nil
let procName = String(cString: &pidAndNameInfo.kp_proc.p_comm.0)
let pathPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(MAXPATHLEN))
_ = proc_pidpath(pid, pathPointer, UInt32(MAXPATHLEN))
let path = String(cString: pathPointer)
var secCode: Unmanaged<SecCode>!
let flags: SecCSFlags = [.considerExpiration, .enforceRevocationChecks]
SecCodeCreateWithPID(pid, SecCSFlags(), &secCode)
let valid = SecCodeCheckValidity(secCode.takeRetainedValue(), flags, nil) == errSecSuccess
return SigningRequestProvenance.Process(pid: pid, name: procName, path: path, validSignature: valid, parentPID: ppid)
}
}

View File

@ -0,0 +1,9 @@
import Foundation
import SecretKit
public protocol SigningWitness {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
}

View File

@ -1,13 +1,13 @@
import Foundation import Foundation
import OSLog import OSLog
class SocketController { public class SocketController {
fileprivate var fileHandle: FileHandle? fileprivate var fileHandle: FileHandle?
fileprivate var port: SocketPort? fileprivate var port: SocketPort?
var handler: ((FileHandle) -> Void)? public var handler: ((FileHandle) -> Void)?
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)
if let _ = try? FileManager.default.removeItem(atPath: path) { if let _ = try? FileManager.default.removeItem(atPath: path) {
os_log(.debug, "Socket controller removed existing socket") os_log(.debug, "Socket controller removed existing socket")

View File

@ -11,24 +11,9 @@ import XCTest
class SecretAgentKitTests: XCTestCase { class SecretAgentKitTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws { func testExample() throws {
// This is an example of a functional test case. // This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results. // Use XCTAssert and related functions to verify your tests produce the correct results.
} }
func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
} }

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>$(CI_VERSION)</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>

View File

@ -11,16 +11,17 @@ extension SmartCard {
// TODO: Read actual smart card name, eg "YubiKey 5c" // TODO: Read actual smart card name, eg "YubiKey 5c"
@Published public var isAvailable: Bool = false @Published public var isAvailable: Bool = false
public let id = UUID() public let id = UUID()
public let name = NSLocalizedString("Smart Card", comment: "Smart Card") public fileprivate(set) var name = NSLocalizedString("Smart Card", comment: "Smart Card")
@Published public fileprivate(set) var secrets: [Secret] = [] @Published public fileprivate(set) var secrets: [Secret] = []
fileprivate let watcher = TKTokenWatcher() fileprivate let watcher = TKTokenWatcher()
fileprivate var tokenID: String? fileprivate var tokenID: String?
public init() { public init() {
tokenID = watcher.tokenIDs.filter { !$0.contains("setoken") }.first tokenID = watcher.nonSecureEnclaveTokens.first
watcher.setInsertionHandler { string in watcher.setInsertionHandler { string in
guard self.tokenID == nil else { return } guard self.tokenID == nil else { return }
guard !string.contains("setoken") else { return } guard !string.contains("setoken") else { return }
self.tokenID = string self.tokenID = string
self.reloadSecrets() self.reloadSecrets()
self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string) self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string)
@ -97,6 +98,14 @@ extension SmartCard.Store {
fileprivate func loadSecrets() { fileprivate func loadSecrets() {
guard let tokenID = tokenID else { return } guard let tokenID = tokenID else { return }
// Hack to read name if there's only one smart card
let slotNames = TKSmartCardSlotManager().slotNames
if watcher.nonSecureEnclaveTokens.count == 1 && slotNames.count == 1 {
name = slotNames.first!
} else {
name = NSLocalizedString("Smart Card", comment: "Smart Card")
}
let attributes = [ let attributes = [
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrTokenID: tokenID, kSecAttrTokenID: tokenID,
@ -124,6 +133,14 @@ extension SmartCard.Store {
} }
extension TKTokenWatcher {
fileprivate var nonSecureEnclaveTokens: [String] {
tokenIDs.filter { !$0.contains("setoken") }
}
}
extension SmartCard { extension SmartCard {
public struct KeychainError: Error { public struct KeychainError: Error {

View File

@ -0,0 +1,45 @@
import Foundation
import XCTest
@testable import SecretKit
class OpenSSHWriterTests: XCTestCase {
let writer = OpenSSHKeyWriter()
func testECDSA256Fingerprint() {
XCTAssertEqual(writer.openSSHFingerprint(secret: Constants.ecdsa256Secret), "dc:60:4d:ff:c2:d9:18:8b:2f:24:40:b5:7f:43:47:e5")
}
func testECDSA256PublicKey() {
XCTAssertEqual(writer.openSSHString(secret: Constants.ecdsa256Secret),
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOVEjgAA5PHqRgwykjN5qM21uWCHFSY/Sqo5gkHAkn+e1MMQKHOLga7ucB9b3mif33MBid59GRK9GEPVlMiSQwo=")
}
func testECDSA256Hash() {
XCTAssertEqual(writer.data(secret: Constants.ecdsa256Secret), Data(base64Encoded: "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOVEjgAA5PHqRgwykjN5qM21uWCHFSY/Sqo5gkHAkn+e1MMQKHOLga7ucB9b3mif33MBid59GRK9GEPVlMiSQwo="))
}
func testECDSA384Fingerprint() {
XCTAssertEqual(writer.openSSHFingerprint(secret: Constants.ecdsa384Secret), "66:e0:66:d7:41:ed:19:8e:e2:20:df:ce:ac:7e:2b:6e")
}
func testECDSA384PublicKey() {
XCTAssertEqual(writer.openSSHString(secret: Constants.ecdsa384Secret),
"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBG2MNc/C5OTHFE2tBvbZCVcpOGa8vBMquiTLkH4lwkeqOPxhi+PyYUfQZMTRJNPiTyWPoMBqNiCIFRVv60yPN/AHufHaOgbdTP42EgMlMMImkAjYUEv9DESHTVIs2PW1yQ==")
}
func testECDSA384Hash() {
XCTAssertEqual(writer.data(secret: Constants.ecdsa384Secret), Data(base64Encoded: "AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBG2MNc/C5OTHFE2tBvbZCVcpOGa8vBMquiTLkH4lwkeqOPxhi+PyYUfQZMTRJNPiTyWPoMBqNiCIFRVv60yPN/AHufHaOgbdTP42EgMlMMImkAjYUEv9DESHTVIs2PW1yQ=="))
}
}
extension OpenSSHWriterTests {
enum Constants {
static let ecdsa256Secret = SmartCard.Secret(id: Data(), name: "Test Key (ECDSA 256)", algorithm: .ellipticCurve, keySize: 256, publicKey: Data(base64Encoded: "BOVEjgAA5PHqRgwykjN5qM21uWCHFSY/Sqo5gkHAkn+e1MMQKHOLga7ucB9b3mif33MBid59GRK9GEPVlMiSQwo=")!)
static let ecdsa384Secret = SmartCard.Secret(id: Data(), name: "Test Key (ECDSA 384)", algorithm: .ellipticCurve, keySize: 384, publicKey: Data(base64Encoded: "BG2MNc/C5OTHFE2tBvbZCVcpOGa8vBMquiTLkH4lwkeqOPxhi+PyYUfQZMTRJNPiTyWPoMBqNiCIFRVv60yPN/AHufHaOgbdTP42EgMlMMImkAjYUEv9DESHTVIs2PW1yQ==")!)
}
}

View File

@ -1,34 +0,0 @@
//
// SecretKitTests.swift
// SecretKitTests
//
// Created by Max Goedjen on 2/18/20.
// Copyright © 2020 Max Goedjen. All rights reserved.
//
import XCTest
@testable import SecretKit
class SecretKitTests: XCTestCase {
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
50020BB024064869003D4025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50020BAF24064869003D4025 /* AppDelegate.swift */; }; 50020BB024064869003D4025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50020BAF24064869003D4025 /* AppDelegate.swift */; };
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; }; 5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */; };
50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* AppDelegate.swift */; }; 50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* AppDelegate.swift */; };
50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; }; 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; };
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; }; 50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
@ -16,7 +17,6 @@
50617D8D23FCE48E0099B055 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8B23FCE48E0099B055 /* Main.storyboard */; }; 50617D8D23FCE48E0099B055 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8B23FCE48E0099B055 /* Main.storyboard */; };
50617D9923FCE48E0099B055 /* SecretiveTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D9823FCE48E0099B055 /* SecretiveTests.swift */; }; 50617D9923FCE48E0099B055 /* SecretiveTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D9823FCE48E0099B055 /* SecretiveTests.swift */; };
50617DB123FCE4AB0099B055 /* SecretKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; }; 50617DB123FCE4AB0099B055 /* SecretKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; };
50617DB823FCE4AB0099B055 /* SecretKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DB723FCE4AB0099B055 /* SecretKitTests.swift */; };
50617DBA23FCE4AB0099B055 /* SecretKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 50617DAA23FCE4AB0099B055 /* SecretKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 50617DBA23FCE4AB0099B055 /* SecretKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 50617DAA23FCE4AB0099B055 /* SecretKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
50617DBD23FCE4AB0099B055 /* SecretKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; }; 50617DBD23FCE4AB0099B055 /* SecretKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; };
50617DBE23FCE4AB0099B055 /* SecretKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 50617DBE23FCE4AB0099B055 /* SecretKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -26,10 +26,23 @@
50617DCE23FCECFA0099B055 /* SecureEnclaveSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */; }; 50617DCE23FCECFA0099B055 /* SecureEnclaveSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */; };
50617DD023FCED2C0099B055 /* SecureEnclave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */; }; 50617DD023FCED2C0099B055 /* SecureEnclave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */; };
50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DD123FCEFA90099B055 /* PreviewStore.swift */; }; 50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DD123FCEFA90099B055 /* PreviewStore.swift */; };
506772C72424784600034DED /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 506772C62424784600034DED /* Credits.rtf */; };
5068389E241471CD00F55094 /* SecretStoreList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5068389D241471CD00F55094 /* SecretStoreList.swift */; }; 5068389E241471CD00F55094 /* SecretStoreList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5068389D241471CD00F55094 /* SecretStoreList.swift */; };
506838A12415EA5600F55094 /* AnySecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A02415EA5600F55094 /* AnySecret.swift */; }; 506838A12415EA5600F55094 /* AnySecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A02415EA5600F55094 /* AnySecret.swift */; };
506838A32415EA5D00F55094 /* AnySecretStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A22415EA5D00F55094 /* AnySecretStore.swift */; }; 506838A32415EA5D00F55094 /* AnySecretStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A22415EA5D00F55094 /* AnySecretStore.swift */; };
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 */; };
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; };
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; };
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.swift */; };
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; };
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; };
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; };
508A5911241EF09C0069DC07 /* SecretAgentKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
508A5913241EF0B20069DC07 /* SecretKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */; }; 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */; };
5099A02723FE34FA0062B6F2 /* SmartCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02623FE34FA0062B6F2 /* SmartCard.swift */; }; 5099A02723FE34FA0062B6F2 /* SmartCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02623FE34FA0062B6F2 /* SmartCard.swift */; };
5099A02923FE35240062B6F2 /* SmartCardStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02823FE35240062B6F2 /* SmartCardStore.swift */; }; 5099A02923FE35240062B6F2 /* SmartCardStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02823FE35240062B6F2 /* SmartCardStore.swift */; };
@ -42,8 +55,6 @@
50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; }; 50A3B79124026B7600D209EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79024026B7600D209EA /* Assets.xcassets */; };
50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79324026B7600D209EA /* Preview Assets.xcassets */; }; 50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79324026B7600D209EA /* Preview Assets.xcassets */; };
50A3B79724026B7600D209EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79524026B7600D209EA /* Main.storyboard */; }; 50A3B79724026B7600D209EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79524026B7600D209EA /* Main.storyboard */; };
50A3B7A024026B9900D209EA /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; };
50A3B7A224026B9900D209EA /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; };
50A5C18C240E4B4B00E2996C /* SecretAgentKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; }; 50A5C18C240E4B4B00E2996C /* SecretAgentKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; };
50A5C18D240E4B4B00E2996C /* SecretAgentKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 50A5C18D240E4B4B00E2996C /* SecretAgentKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5099A06C240242BA0062B6F2 /* SecretAgentKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
50A5C18F240E4B4C00E2996C /* SecretKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; }; 50A5C18F240E4B4C00E2996C /* SecretKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50617DA823FCE4AB0099B055 /* SecretKit.framework */; };
@ -84,14 +95,14 @@
remoteGlobalIDString = 50617DA723FCE4AB0099B055; remoteGlobalIDString = 50617DA723FCE4AB0099B055;
remoteInfo = SecretKit; remoteInfo = SecretKit;
}; };
50617DB423FCE4AB0099B055 /* PBXContainerItemProxy */ = { 50617DBB23FCE4AB0099B055 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 50617D7723FCE48D0099B055 /* Project object */; containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 50617D7E23FCE48D0099B055; remoteGlobalIDString = 50617DA723FCE4AB0099B055;
remoteInfo = Secretive; remoteInfo = SecretKit;
}; };
50617DBB23FCE4AB0099B055 /* PBXContainerItemProxy */ = { 507CE4F12420A6B50029F750 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 50617D7723FCE48D0099B055 /* Project object */; containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
proxyType = 1; proxyType = 1;
@ -105,13 +116,6 @@
remoteGlobalIDString = 5099A06B240242BA0062B6F2; remoteGlobalIDString = 5099A06B240242BA0062B6F2;
remoteInfo = SecretAgentKit; remoteInfo = SecretAgentKit;
}; };
5099A078240242BA0062B6F2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 50617D7723FCE48D0099B055 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 50617D7E23FCE48D0099B055;
remoteInfo = Secretive;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -126,6 +130,26 @@
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
508A5910241EF0920069DC07 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
508A5911241EF09C0069DC07 /* SecretAgentKit.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
508A5912241EF0AC0069DC07 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
508A5913241EF0B20069DC07 /* SecretKit.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
50A5C18E240E4B4B00E2996C /* Embed Frameworks */ = { 50A5C18E240E4B4B00E2996C /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -153,6 +177,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; }; 5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSSHWriterTests.swift; sourceTree = "<group>"; };
50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; };
50617D8223FCE48E0099B055 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 50617D8223FCE48E0099B055 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -168,7 +193,6 @@
50617DAA23FCE4AB0099B055 /* SecretKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecretKit.h; sourceTree = "<group>"; }; 50617DAA23FCE4AB0099B055 /* SecretKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecretKit.h; sourceTree = "<group>"; };
50617DAB23FCE4AB0099B055 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 50617DAB23FCE4AB0099B055 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50617DB023FCE4AB0099B055 /* SecretKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecretKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 50617DB023FCE4AB0099B055 /* SecretKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecretKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
50617DB723FCE4AB0099B055 /* SecretKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretKitTests.swift; sourceTree = "<group>"; };
50617DB923FCE4AB0099B055 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 50617DB923FCE4AB0099B055 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50617DC623FCE4EA0099B055 /* SecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStore.swift; sourceTree = "<group>"; }; 50617DC623FCE4EA0099B055 /* SecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStore.swift; sourceTree = "<group>"; };
50617DC823FCE50E0099B055 /* SecureEnclaveStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveStore.swift; sourceTree = "<group>"; }; 50617DC823FCE50E0099B055 /* SecureEnclaveStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveStore.swift; sourceTree = "<group>"; };
@ -176,9 +200,20 @@
50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveSecret.swift; sourceTree = "<group>"; }; 50617DCD23FCECFA0099B055 /* SecureEnclaveSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclaveSecret.swift; sourceTree = "<group>"; };
50617DCF23FCED2C0099B055 /* SecureEnclave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclave.swift; sourceTree = "<group>"; }; 50617DCF23FCED2C0099B055 /* SecureEnclave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureEnclave.swift; sourceTree = "<group>"; };
50617DD123FCEFA90099B055 /* PreviewStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewStore.swift; sourceTree = "<group>"; }; 50617DD123FCEFA90099B055 /* PreviewStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewStore.swift; sourceTree = "<group>"; };
506772C62424784600034DED /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
5068389D241471CD00F55094 /* SecretStoreList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStoreList.swift; sourceTree = "<group>"; }; 5068389D241471CD00F55094 /* SecretStoreList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStoreList.swift; sourceTree = "<group>"; };
506838A02415EA5600F55094 /* AnySecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecret.swift; sourceTree = "<group>"; }; 506838A02415EA5600F55094 /* AnySecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecret.swift; sourceTree = "<group>"; };
506838A22415EA5D00F55094 /* AnySecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecretStore.swift; sourceTree = "<group>"; }; 506838A22415EA5D00F55094 /* AnySecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecretStore.swift; sourceTree = "<group>"; };
50731665241DF8660023809E /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
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>"; };
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestProvenance.swift; sourceTree = "<group>"; };
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; };
508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
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>"; };
508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewAgentStatusChecker.swift; sourceTree = "<group>"; };
508A590F241EEF6D0069DC07 /* Secretive.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Secretive.xctestplan; sourceTree = "<group>"; };
5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSecretView.swift; sourceTree = "<group>"; }; 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSecretView.swift; sourceTree = "<group>"; };
5099A02623FE34FA0062B6F2 /* SmartCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCard.swift; sourceTree = "<group>"; }; 5099A02623FE34FA0062B6F2 /* SmartCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCard.swift; sourceTree = "<group>"; };
5099A02823FE35240062B6F2 /* SmartCardStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCardStore.swift; sourceTree = "<group>"; }; 5099A02823FE35240062B6F2 /* SmartCardStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCardStore.swift; sourceTree = "<group>"; };
@ -274,6 +309,7 @@
50A3B78B24026B7500D209EA /* SecretAgent */, 50A3B78B24026B7500D209EA /* SecretAgent */,
5099A06D240242BA0062B6F2 /* SecretAgentKit */, 5099A06D240242BA0062B6F2 /* SecretAgentKit */,
5099A07A240242BA0062B6F2 /* SecretAgentKitTests */, 5099A07A240242BA0062B6F2 /* SecretAgentKitTests */,
508A58AF241E144C0069DC07 /* Config */,
50617D8023FCE48E0099B055 /* Products */, 50617D8023FCE48E0099B055 /* Products */,
5099A08B240243730062B6F2 /* Frameworks */, 5099A08B240243730062B6F2 /* Frameworks */,
); );
@ -297,16 +333,13 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50617D8223FCE48E0099B055 /* AppDelegate.swift */, 50617D8223FCE48E0099B055 /* AppDelegate.swift */,
50617D8423FCE48E0099B055 /* ContentView.swift */, 508A58B0241ED1C40069DC07 /* Views */,
50C385A42407A76D00AF2719 /* SecretDetailView.swift */, 508A58B1241ED1EA0069DC07 /* Controllers */,
5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */,
50B8550C24138C4F009958AC /* DeleteSecretView.swift */,
50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */,
50C385A8240B636500AF2719 /* SetupView.swift */,
50617D8623FCE48E0099B055 /* Assets.xcassets */, 50617D8623FCE48E0099B055 /* Assets.xcassets */,
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;
@ -317,6 +350,8 @@
children = ( children = (
50617D8923FCE48E0099B055 /* Preview Assets.xcassets */, 50617D8923FCE48E0099B055 /* Preview Assets.xcassets */,
50617DD123FCEFA90099B055 /* PreviewStore.swift */, 50617DD123FCEFA90099B055 /* PreviewStore.swift */,
508A58A9241E06B40069DC07 /* PreviewUpdater.swift */,
508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */,
); );
path = "Preview Content"; path = "Preview Content";
sourceTree = "<group>"; sourceTree = "<group>";
@ -347,7 +382,7 @@
50617DB623FCE4AB0099B055 /* SecretKitTests */ = { 50617DB623FCE4AB0099B055 /* SecretKitTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50617DB723FCE4AB0099B055 /* SecretKitTests.swift */, 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */,
50617DB923FCE4AB0099B055 /* Info.plist */, 50617DB923FCE4AB0099B055 /* Info.plist */,
); );
path = SecretKitTests; path = SecretKitTests;
@ -381,6 +416,38 @@
path = OpenSSH; path = OpenSSH;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
508A58AF241E144C0069DC07 /* Config */ = {
isa = PBXGroup;
children = (
508A590F241EEF6D0069DC07 /* Secretive.xctestplan */,
508A58AB241E121B0069DC07 /* Config.xcconfig */,
);
path = Config;
sourceTree = "<group>";
};
508A58B0241ED1C40069DC07 /* Views */ = {
isa = PBXGroup;
children = (
50617D8423FCE48E0099B055 /* ContentView.swift */,
50731668241E00C20023809E /* NoticeView.swift */,
50C385A42407A76D00AF2719 /* SecretDetailView.swift */,
5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */,
50B8550C24138C4F009958AC /* DeleteSecretView.swift */,
50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */,
50C385A8240B636500AF2719 /* SetupView.swift */,
);
path = Views;
sourceTree = "<group>";
};
508A58B1241ED1EA0069DC07 /* Controllers */ = {
isa = PBXGroup;
children = (
50731665241DF8660023809E /* Updater.swift */,
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
);
path = Controllers;
sourceTree = "<group>";
};
5099A02523FE34DE0062B6F2 /* SmartCard */ = { 5099A02523FE34DE0062B6F2 /* SmartCard */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -406,6 +473,11 @@
children = ( children = (
5099A06E240242BA0062B6F2 /* SecretAgentKit.h */, 5099A06E240242BA0062B6F2 /* SecretAgentKit.h */,
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */, 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */,
50A3B79D24026B9900D209EA /* SocketController.swift */,
507CE4EF2420A4C50029F750 /* SigningWitness.swift */,
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */,
50A3B79F24026B9900D209EA /* Agent.swift */,
5099A06F240242BA0062B6F2 /* Info.plist */, 5099A06F240242BA0062B6F2 /* Info.plist */,
); );
path = SecretAgentKit; path = SecretAgentKit;
@ -431,9 +503,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50020BAF24064869003D4025 /* AppDelegate.swift */, 50020BAF24064869003D4025 /* AppDelegate.swift */,
50A3B79F24026B9900D209EA /* Agent.swift */,
5018F54E24064786002EB505 /* Notifier.swift */, 5018F54E24064786002EB505 /* Notifier.swift */,
50A3B79D24026B9900D209EA /* SocketController.swift */,
50A3B79024026B7600D209EA /* Assets.xcassets */, 50A3B79024026B7600D209EA /* Assets.xcassets */,
50A3B79524026B7600D209EA /* Main.storyboard */, 50A3B79524026B7600D209EA /* Main.storyboard */,
50A3B79824026B7600D209EA /* Info.plist */, 50A3B79824026B7600D209EA /* Info.plist */,
@ -536,12 +606,12 @@
50617DAC23FCE4AB0099B055 /* Sources */, 50617DAC23FCE4AB0099B055 /* Sources */,
50617DAD23FCE4AB0099B055 /* Frameworks */, 50617DAD23FCE4AB0099B055 /* Frameworks */,
50617DAE23FCE4AB0099B055 /* Resources */, 50617DAE23FCE4AB0099B055 /* Resources */,
508A5912241EF0AC0069DC07 /* CopyFiles */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
50617DB323FCE4AB0099B055 /* PBXTargetDependency */, 50617DB323FCE4AB0099B055 /* PBXTargetDependency */,
50617DB523FCE4AB0099B055 /* PBXTargetDependency */,
); );
name = SecretKitTests; name = SecretKitTests;
productName = SecretKitTests; productName = SecretKitTests;
@ -560,6 +630,7 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
507CE4F22420A6B50029F750 /* PBXTargetDependency */,
); );
name = SecretAgentKit; name = SecretAgentKit;
productName = SecretAgentKit; productName = SecretAgentKit;
@ -573,12 +644,12 @@
5099A070240242BA0062B6F2 /* Sources */, 5099A070240242BA0062B6F2 /* Sources */,
5099A071240242BA0062B6F2 /* Frameworks */, 5099A071240242BA0062B6F2 /* Frameworks */,
5099A072240242BA0062B6F2 /* Resources */, 5099A072240242BA0062B6F2 /* Resources */,
508A5910241EF0920069DC07 /* CopyFiles */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
5099A077240242BA0062B6F2 /* PBXTargetDependency */, 5099A077240242BA0062B6F2 /* PBXTargetDependency */,
5099A079240242BA0062B6F2 /* PBXTargetDependency */,
); );
name = SecretAgentKitTests; name = SecretAgentKitTests;
productName = SecretAgentKitTests; productName = SecretAgentKitTests;
@ -628,7 +699,6 @@
}; };
50617DAF23FCE4AB0099B055 = { 50617DAF23FCE4AB0099B055 = {
CreatedOnToolsVersion = 11.3; CreatedOnToolsVersion = 11.3;
TestTargetID = 50617D7E23FCE48D0099B055;
}; };
5099A06B240242BA0062B6F2 = { 5099A06B240242BA0062B6F2 = {
CreatedOnToolsVersion = 11.4; CreatedOnToolsVersion = 11.4;
@ -636,7 +706,6 @@
}; };
5099A073240242BA0062B6F2 = { 5099A073240242BA0062B6F2 = {
CreatedOnToolsVersion = 11.4; CreatedOnToolsVersion = 11.4;
TestTargetID = 50617D7E23FCE48D0099B055;
}; };
50A3B78924026B7500D209EA = { 50A3B78924026B7500D209EA = {
CreatedOnToolsVersion = 11.4; CreatedOnToolsVersion = 11.4;
@ -675,6 +744,7 @@
50617D8D23FCE48E0099B055 /* Main.storyboard in Resources */, 50617D8D23FCE48E0099B055 /* Main.storyboard in Resources */,
50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */, 50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */,
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */, 50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */,
506772C72424784600034DED /* Credits.rtf in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -733,11 +803,16 @@
50C385A9240B636500AF2719 /* SetupView.swift in Sources */, 50C385A9240B636500AF2719 /* SetupView.swift in Sources */,
50617D8523FCE48E0099B055 /* ContentView.swift in Sources */, 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */,
50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */, 50617DD223FCEFA90099B055 /* PreviewStore.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 */,
50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */, 50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */,
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */,
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -773,7 +848,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
50617DB823FCE4AB0099B055 /* SecretKitTests.swift in Sources */, 50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -781,7 +856,12 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */,
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */, 5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */,
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */,
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */,
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */,
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -799,8 +879,6 @@
files = ( files = (
50020BB024064869003D4025 /* AppDelegate.swift in Sources */, 50020BB024064869003D4025 /* AppDelegate.swift in Sources */,
5018F54F24064786002EB505 /* Notifier.swift in Sources */, 5018F54F24064786002EB505 /* Notifier.swift in Sources */,
50A3B7A224026B9900D209EA /* Agent.swift in Sources */,
50A3B7A024026B9900D209EA /* SocketController.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -827,26 +905,21 @@
target = 50617DA723FCE4AB0099B055 /* SecretKit */; target = 50617DA723FCE4AB0099B055 /* SecretKit */;
targetProxy = 50617DB223FCE4AB0099B055 /* PBXContainerItemProxy */; targetProxy = 50617DB223FCE4AB0099B055 /* PBXContainerItemProxy */;
}; };
50617DB523FCE4AB0099B055 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 50617D7E23FCE48D0099B055 /* Secretive */;
targetProxy = 50617DB423FCE4AB0099B055 /* PBXContainerItemProxy */;
};
50617DBC23FCE4AB0099B055 /* PBXTargetDependency */ = { 50617DBC23FCE4AB0099B055 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 50617DA723FCE4AB0099B055 /* SecretKit */; target = 50617DA723FCE4AB0099B055 /* SecretKit */;
targetProxy = 50617DBB23FCE4AB0099B055 /* PBXContainerItemProxy */; targetProxy = 50617DBB23FCE4AB0099B055 /* PBXContainerItemProxy */;
}; };
507CE4F22420A6B50029F750 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 50617DA723FCE4AB0099B055 /* SecretKit */;
targetProxy = 507CE4F12420A6B50029F750 /* PBXContainerItemProxy */;
};
5099A077240242BA0062B6F2 /* PBXTargetDependency */ = { 5099A077240242BA0062B6F2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 5099A06B240242BA0062B6F2 /* SecretAgentKit */; target = 5099A06B240242BA0062B6F2 /* SecretAgentKit */;
targetProxy = 5099A076240242BA0062B6F2 /* PBXContainerItemProxy */; targetProxy = 5099A076240242BA0062B6F2 /* PBXContainerItemProxy */;
}; };
5099A079240242BA0062B6F2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 50617D7E23FCE48D0099B055 /* Secretive */;
targetProxy = 5099A078240242BA0062B6F2 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
@ -871,6 +944,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
50617D9B23FCE48E0099B055 /* Debug */ = { 50617D9B23FCE48E0099B055 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
@ -931,6 +1005,7 @@
}; };
50617D9C23FCE48E0099B055 /* Release */ = { 50617D9C23FCE48E0099B055 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
@ -991,6 +1066,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\"";
DEVELOPMENT_TEAM = Z72PRUAWF6; DEVELOPMENT_TEAM = Z72PRUAWF6;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -1001,6 +1077,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -1017,6 +1094,7 @@
CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\"";
DEVELOPMENT_TEAM = Z72PRUAWF6; DEVELOPMENT_TEAM = Z72PRUAWF6;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -1027,6 +1105,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host"; PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host";
@ -1153,7 +1232,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
}; };
name = Debug; name = Debug;
}; };
@ -1173,10 +1251,247 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
}; };
name = Release; name = Release;
}; };
508A5914241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 508A58AB241E121B0069DC07 /* Config.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Test;
};
508A5915241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Secretive/Secretive.entitlements;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\"";
DEVELOPMENT_TEAM = Z72PRUAWF6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = Secretive/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host";
SWIFT_VERSION = 5.0;
};
name = Test;
};
508A5916241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretiveTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretiveTests;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
};
name = Test;
};
508A5917241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
DEVELOPMENT_TEAM = Z72PRUAWF6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = SecretAgent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
SWIFT_VERSION = 5.0;
};
name = Test;
};
508A5918241EF1A00069DC07 /* 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 = SecretKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit;
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;
};
508A5919241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretKitTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Test;
};
508A591A241EF1A00069DC07 /* 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 = SecretAgentKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit;
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;
};
508A591B241EF1A00069DC07 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = Z72PRUAWF6;
INFOPLIST_FILE = SecretAgentKitTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Test;
};
5099A084240242BA0062B6F2 /* Debug */ = { 5099A084240242BA0062B6F2 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -1240,7 +1555,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;
@ -1252,7 +1566,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
}; };
name = Debug; name = Debug;
}; };
@ -1260,7 +1573,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;
@ -1272,7 +1584,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
}; };
name = Release; name = Release;
}; };
@ -1293,7 +1604,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 0.1.0; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@ -1318,7 +1629,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15; MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 0.1.0; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent"; PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
@ -1333,6 +1644,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
50617D9B23FCE48E0099B055 /* Debug */, 50617D9B23FCE48E0099B055 /* Debug */,
508A5914241EF1A00069DC07 /* Test */,
50617D9C23FCE48E0099B055 /* Release */, 50617D9C23FCE48E0099B055 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1342,6 +1654,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
50617D9E23FCE48E0099B055 /* Debug */, 50617D9E23FCE48E0099B055 /* Debug */,
508A5915241EF1A00069DC07 /* Test */,
50617D9F23FCE48E0099B055 /* Release */, 50617D9F23FCE48E0099B055 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1351,6 +1664,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
50617DA123FCE48E0099B055 /* Debug */, 50617DA123FCE48E0099B055 /* Debug */,
508A5916241EF1A00069DC07 /* Test */,
50617DA223FCE48E0099B055 /* Release */, 50617DA223FCE48E0099B055 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1360,6 +1674,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
50617DC023FCE4AB0099B055 /* Debug */, 50617DC023FCE4AB0099B055 /* Debug */,
508A5918241EF1A00069DC07 /* Test */,
50617DC123FCE4AB0099B055 /* Release */, 50617DC123FCE4AB0099B055 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1369,6 +1684,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
50617DC223FCE4AB0099B055 /* Debug */, 50617DC223FCE4AB0099B055 /* Debug */,
508A5919241EF1A00069DC07 /* Test */,
50617DC323FCE4AB0099B055 /* Release */, 50617DC323FCE4AB0099B055 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1378,6 +1694,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
5099A084240242BA0062B6F2 /* Debug */, 5099A084240242BA0062B6F2 /* Debug */,
508A591A241EF1A00069DC07 /* Test */,
5099A085240242BA0062B6F2 /* Release */, 5099A085240242BA0062B6F2 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1387,6 +1704,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
5099A087240242BA0062B6F2 /* Debug */, 5099A087240242BA0062B6F2 /* Debug */,
508A591B241EF1A00069DC07 /* Test */,
5099A088240242BA0062B6F2 /* Release */, 5099A088240242BA0062B6F2 /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
@ -1396,6 +1714,7 @@
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
50A3B79B24026B7600D209EA /* Debug */, 50A3B79B24026B7600D209EA /* Debug */,
508A5917241EF1A00069DC07 /* Test */,
50A3B79C24026B7600D209EA /* Release */, 50A3B79C24026B7600D209EA /* Release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1140" LastUpgradeVersion = "1140"
version = "1.3"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
@ -23,11 +23,47 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug" buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:Config/Secretive.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables> <Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5099A073240242BA0062B6F2"
BuildableName = "SecretAgentKitTests.xctest"
BlueprintName = "SecretAgentKitTests"
ReferencedContainer = "container:Secretive.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "50617DAF23FCE4AB0099B055"
BuildableName = "SecretKitTests.xctest"
BlueprintName = "SecretKitTests"
ReferencedContainer = "container:Secretive.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "50617D9323FCE48E0099B055"
BuildableName = "SecretiveTests.xctest"
BlueprintName = "SecretiveTests"
ReferencedContainer = "container:Secretive.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1140" LastUpgradeVersion = "1140"
version = "1.3"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
@ -23,11 +23,29 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug" buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:Config/Secretive.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables> <Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5099A073240242BA0062B6F2"
BuildableName = "SecretAgentKitTests.xctest"
BlueprintName = "SecretAgentKitTests"
ReferencedContainer = "container:Secretive.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1140" LastUpgradeVersion = "1140"
version = "1.3"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
@ -23,12 +23,16 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug" buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <TestPlans>
</Testables> <TestPlanReference
reference = "container:Config/Secretive.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1140" LastUpgradeVersion = "1140"
version = "1.3"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
@ -23,10 +23,16 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug" buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:Config/Secretive.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">

View File

@ -6,6 +6,7 @@ import SecretKit
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow! var window: NSWindow!
@IBOutlet var newMenuItem: NSMenuItem!
@IBOutlet var toolbar: NSToolbar! @IBOutlet var toolbar: NSToolbar!
let storeList: SecretStoreList = { let storeList: SecretStoreList = {
let list = SecretStoreList() let list = SecretStoreList()
@ -13,10 +14,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
list.add(store: SmartCard.Store()) list.add(store: SmartCard.Store())
return list return list
}() }()
let updater = Updater()
let agentStatusChecker = AgentStatusChecker()
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentView = ContentView(storeList: storeList, updater: updater, agentStatusChecker: agentStatusChecker, runSetupBlock: { self.runSetup(sender: nil) })
let contentView = ContentView(storeList: storeList)
// Create the window and set the content view. // Create the window and set the content view.
window = NSWindow( window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
@ -28,15 +30,27 @@ class AppDelegate: NSObject, NSApplicationDelegate {
window.makeKeyAndOrderFront(nil) window.makeKeyAndOrderFront(nil)
window.titleVisibility = .hidden window.titleVisibility = .hidden
window.toolbar = toolbar window.toolbar = toolbar
window.isReleasedWhenClosed = false
if storeList.modifiableStore?.isAvailable ?? false { if storeList.modifiableStore?.isAvailable ?? false {
let plus = NSTitlebarAccessoryViewController() let plus = NSTitlebarAccessoryViewController()
plus.view = NSButton(image: NSImage(named: NSImage.addTemplateName)!, target: self, action: #selector(add(sender:))) plus.view = NSButton(image: NSImage(named: NSImage.addTemplateName)!, target: self, action: #selector(add(sender:)))
plus.layoutAttribute = .right plus.layoutAttribute = .right
window.addTitlebarAccessoryViewController(plus) window.addTitlebarAccessoryViewController(plus)
newMenuItem.isEnabled = true
} }
runSetupIfNeeded() runSetupIfNeeded()
} }
func applicationDidBecomeActive(_ notification: Notification) {
agentStatusChecker.check()
}
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
guard !flag else { return false }
window.makeKeyAndOrderFront(self)
return true
}
@IBAction func add(sender: AnyObject?) { @IBAction func add(sender: AnyObject?) {
var addWindow: NSWindow! var addWindow: NSWindow!
let addView = CreateSecretView(store: storeList.modifiableStore!) { let addView = CreateSecretView(store: storeList.modifiableStore!) {
@ -57,6 +71,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
backing: .buffered, defer: false) backing: .buffered, defer: false)
let setupView = SetupView() { success in let setupView = SetupView() { success in
self.window.endSheet(setupWindow) self.window.endSheet(setupWindow)
self.agentStatusChecker.check()
} }
setupWindow.contentView = NSHostingView(rootView: setupView) setupWindow.contentView = NSHostingView(rootView: setupView)
window.beginSheet(setupWindow, completionHandler: nil) window.beginSheet(setupWindow, completionHandler: nil)

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> <document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="16085" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16085"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<scenes> <scenes>
@ -9,7 +9,7 @@
<scene sceneID="JPo-4y-FX3"> <scene sceneID="JPo-4y-FX3">
<objects> <objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController"> <application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> <menu key="mainMenu" title="Main Menu" systemMenu="main" autoenablesItems="NO" id="AYu-sK-qS6">
<items> <items>
<menuItem title="Secretive" id="1Xt-HY-uBw"> <menuItem title="Secretive" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
@ -57,9 +57,9 @@
</menuItem> </menuItem>
<menuItem title="File" id="dMs-cI-mzQ"> <menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu"> <menu key="submenu" title="File" autoenablesItems="NO" id="bib-Uj-vzu">
<items> <items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl"> <menuItem title="New" enabled="NO" keyEquivalent="n" id="Was-JA-tGl">
<connections> <connections>
<action selector="addWithSender:" target="Voe-Tx-rLC" id="U1t-YZ-Hn5"/> <action selector="addWithSender:" target="Voe-Tx-rLC" id="U1t-YZ-Hn5"/>
</connections> </connections>
@ -102,7 +102,7 @@
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items> <items>
<menuItem title="Set Up Helper App" id="04y-R6-7bF"> <menuItem title="Setup Helper App" id="04y-R6-7bF">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="runSetupWithSender:" target="Voe-Tx-rLC" id="Fty-2m-eng"/> <action selector="runSetupWithSender:" target="Voe-Tx-rLC" id="Fty-2m-eng"/>
@ -125,6 +125,7 @@
</application> </application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Secretive" customModuleProvider="target"> <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Secretive" customModuleProvider="target">
<connections> <connections>
<outlet property="newMenuItem" destination="Was-JA-tGl" id="C8s-uk-gMA"/>
<outlet property="toolbar" destination="bvo-mt-QR4" id="XSF-g2-znt"/> <outlet property="toolbar" destination="bvo-mt-QR4" id="XSF-g2-znt"/>
</connections> </connections>
</customObject> </customObject>

View File

@ -1,97 +0,0 @@
import SwiftUI
import SecretKit
struct ContentView: View {
@ObservedObject var storeList: SecretStoreList
@State fileprivate var active: AnySecret.ID?
@State fileprivate var showingDeletion = false
@State fileprivate var deletingSecret: AnySecret?
var body: some View {
NavigationView {
List(selection: $active) {
ForEach(storeList.stores) { store in
if store.isAvailable {
Section(header: Text(store.name)) {
if store.secrets.isEmpty {
if store is AnySecretStoreModifiable {
NavigationLink(destination: EmptyStoreModifiableView(), tag: Constants.emptyStoreModifiableTag, selection: self.$active) {
Text("No Secrets")
}
} else {
NavigationLink(destination: EmptyStoreView(), tag: Constants.emptyStoreTag, selection: self.$active) {
Text("No Secrets")
}
}
} else {
ForEach(store.secrets) { secret in
NavigationLink(destination: SecretDetailView(secret: secret), tag: secret.id, selection: self.$active) {
Text(secret.name)
}.contextMenu {
if store is AnySecretStoreModifiable {
Button(action: { self.delete(secret: secret) }) {
Text("Delete")
}
}
}
}
}
}
}
}
}.onAppear {
let fallback: AnyHashable
if self.storeList.modifiableStore?.isAvailable ?? false {
fallback = Constants.emptyStoreModifiableTag
} else {
fallback = Constants.emptyStoreTag
}
self.active = self.storeList.stores.compactMap { $0.secrets.first }.first?.id ?? fallback
}
.listStyle(SidebarListStyle())
.frame(minWidth: 100, idealWidth: 240)
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.sheet(isPresented: $showingDeletion) {
if self.storeList.modifiableStore != nil {
DeleteSecretView(secret: self.deletingSecret!, store: self.storeList.modifiableStore!) {
self.showingDeletion = false
}
}
}
}
func delete<SecretType: Secret>(secret: SecretType) {
deletingSecret = AnySecret(secret)
self.showingDeletion = true
}
}
extension ContentView {
enum Constants {
static let emptyStoreModifiableTag: AnyHashable = "emptyStoreModifiableTag"
static let emptyStoreTag: AnyHashable = "emptyStoreModifiableTag"
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
ContentView(storeList: Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
ContentView(storeList: Preview.storeList(stores: [Preview.Store()]))
ContentView(storeList: Preview.storeList(modifiableStores: [Preview.StoreModifiable()]))
}
}
}
#endif

View File

@ -0,0 +1,33 @@
import Foundation
import Combine
import AppKit
protocol AgentStatusCheckerProtocol: ObservableObject {
var running: Bool { get }
}
class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol {
@Published var running: Bool = false
init() {
check()
}
func check() {
running = secretAgentProcess != nil
}
var secretAgentProcess: NSRunningApplication? {
NSRunningApplication.runningApplications(withBundleIdentifier: Constants.secretAgentAppID).first
}
}
extension AgentStatusChecker {
enum Constants {
static let secretAgentAppID = "com.maxgoedjen.Secretive.SecretAgent"
}
}

View File

@ -0,0 +1,82 @@
import Foundation
import Combine
protocol UpdaterProtocol: ObservableObject {
var update: Release? { get }
}
class Updater: ObservableObject, UpdaterProtocol {
@Published var update: Release?
init() {
checkForUpdates()
let timer = Timer.scheduledTimer(withTimeInterval: 60*60*24, repeats: true) { _ in
self.checkForUpdates()
}
timer.tolerance = 60*60
}
func checkForUpdates() {
URLSession.shared.dataTask(with: Constants.updateURL) { data, _, _ in
guard let data = data else { return }
guard let release = try? JSONDecoder().decode(Release.self, from: data) else { return }
self.evaluate(release: release)
}.resume()
}
func evaluate(release: Release) {
let latestVersion = semVer(from: release.name)
let currentVersion = semVer(from: Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String)
for (latest, current) in zip(latestVersion, currentVersion) {
if latest > current {
DispatchQueue.main.async {
self.update = release
}
return
}
}
}
func semVer(from stringVersion: String) -> [Int] {
var split = stringVersion.split(separator: ".").compactMap { Int($0) }
while split.count < 3 {
split.append(0)
}
return split
}
}
extension Updater {
enum Constants {
static let updateURL = URL(string: "https://api.github.com/repos/maxgoedjen/secretive/releases/latest")!
}
}
struct Release: Codable {
let name: String
let html_url: URL
let body: String
}
extension Release {
var critical: Bool {
return body.contains(Constants.securityContent)
}
}
extension Release {
enum Constants {
static let securityContent = "Critical Security Update"
}
}

23
Secretive/Credits.rtf Normal file
View File

@ -0,0 +1,23 @@
{\rtf1\ansi\ansicpg1252\cocoartf2511
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6119\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://github.com/maxgoedjen/secretive"}}{\fldrslt
\f0\fs24 \cf0 https://github.com/maxgoedjen/secretive}}
\f0\fs24 \
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
\cf0 \
GITHUB_BUILD_URL\
\
Special Thanks To:\
https://github.com/bdash\
https://github.com/danielctull\
https://github.com/davedelong\
https://github.com/esttorhe\
https://github.com/joeblau\
https://github.com/marksands\
https://github.com/mergesort\
https://github.com/phillco\
https://github.com/zackdotcomputer}

View File

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>$(CI_VERSION)</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>$(CI_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>

View File

@ -0,0 +1,12 @@
import Foundation
import Combine
class PreviewAgentStatusChecker: AgentStatusCheckerProtocol {
let running: Bool
init(running: Bool = true) {
self.running = running
}
}

View File

@ -0,0 +1,27 @@
import Foundation
import Combine
class PreviewUpdater: UpdaterProtocol {
let update: Release?
init(update: Update = .none) {
switch update {
case .none:
self.update = nil
case .advisory:
self.update = Release(name: "10.10.10", html_url: URL(string: "https://example.com")!, body: "Some regular update")
case .critical:
self.update = Release(name: "10.10.10", html_url: URL(string: "https://example.com")!, body: "Critical Security Update")
}
}
}
extension PreviewUpdater {
enum Update {
case none, advisory, critical
}
}

View File

@ -6,6 +6,8 @@
<true/> <true/>
<key>com.apple.security.smartcard</key> <key>com.apple.security.smartcard</key>
<true/> <true/>
<key>com.apple.security.network.client</key>
<true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.maxgoedjen.Secretive</string> <string>$(AppIdentifierPrefix)com.maxgoedjen.Secretive</string>

View File

@ -0,0 +1,144 @@
import SwiftUI
import SecretKit
struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentStatusCheckerProtocol>: View {
@ObservedObject var storeList: SecretStoreList
@ObservedObject var updater: UpdaterType
@ObservedObject var agentStatusChecker: AgentStatusCheckerType
var runSetupBlock: (() -> Void)?
@State fileprivate var active: AnySecret.ID?
@State fileprivate var showingDeletion = false
@State fileprivate var deletingSecret: AnySecret?
var body: some View {
VStack {
if updater.update != nil {
updateNotice()
}
if !agentStatusChecker.running {
agentNotice()
}
NavigationView {
List(selection: $active) {
ForEach(storeList.stores) { store in
if store.isAvailable {
Section(header: Text(store.name)) {
if store.secrets.isEmpty {
if store is AnySecretStoreModifiable {
NavigationLink(destination: EmptyStoreModifiableView(), tag: Constants.emptyStoreModifiableTag, selection: self.$active) {
Text("No Secrets")
}
} else {
NavigationLink(destination: EmptyStoreView(), tag: Constants.emptyStoreTag, selection: self.$active) {
Text("No Secrets")
}
}
} else {
ForEach(store.secrets) { secret in
NavigationLink(destination: SecretDetailView(secret: secret), tag: secret.id, selection: self.$active) {
Text(secret.name)
}.contextMenu {
if store is AnySecretStoreModifiable {
Button(action: { self.delete(secret: secret) }) {
Text("Delete")
}
}
}
}
}
}
}
}
}.onAppear {
self.active = self.nextDefaultSecret
}
.listStyle(SidebarListStyle())
.frame(minWidth: 100, idealWidth: 240)
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
.sheet(isPresented: $showingDeletion) {
if self.storeList.modifiableStore != nil {
DeleteSecretView(secret: self.deletingSecret!, store: self.storeList.modifiableStore!) { deleted in
self.showingDeletion = false
if deleted {
self.active = self.nextDefaultSecret
}
}
}
}
}
}
func updateNotice() -> some View {
guard let update = updater.update else { return AnyView(Spacer()) }
let severity: NoticeView.Severity
let text: String
if update.critical {
severity = .critical
text = "Critical Security Update Required"
} else {
severity = .advisory
text = "Update Available"
}
return AnyView(NoticeView(text: text, severity: severity, actionTitle: "Update") {
NSWorkspace.shared.open(update.html_url)
})
}
func agentNotice() -> some View {
NoticeView(text: "Secret Agent isn't running. Run setup again to fix.", severity: .advisory, actionTitle: "Run Setup") {
self.runSetupBlock?()
}
}
func delete<SecretType: Secret>(secret: SecretType) {
deletingSecret = AnySecret(secret)
self.showingDeletion = true
}
var nextDefaultSecret: AnyHashable? {
let fallback: AnyHashable
if self.storeList.modifiableStore?.isAvailable ?? false {
fallback = Constants.emptyStoreModifiableTag
} else {
fallback = Constants.emptyStoreTag
}
return self.storeList.stores.compactMap { $0.secrets.first }.first?.id ?? fallback
}
}
fileprivate enum Constants {
static let emptyStoreModifiableTag: AnyHashable = "emptyStoreModifiableTag"
static let emptyStoreTag: AnyHashable = "emptyStoreModifiableTag"
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)],
modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]),
updater: PreviewUpdater(),
agentStatusChecker: PreviewAgentStatusChecker())
ContentView(storeList: Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]), updater: PreviewUpdater(),
agentStatusChecker: PreviewAgentStatusChecker())
ContentView(storeList: Preview.storeList(stores: [Preview.Store()]), updater: PreviewUpdater(),
agentStatusChecker: PreviewAgentStatusChecker())
ContentView(storeList: Preview.storeList(modifiableStores: [Preview.StoreModifiable()]), updater: PreviewUpdater(),
agentStatusChecker: PreviewAgentStatusChecker())
ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .advisory),
agentStatusChecker: PreviewAgentStatusChecker())
ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .critical),
agentStatusChecker: PreviewAgentStatusChecker())
ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .critical),
agentStatusChecker: PreviewAgentStatusChecker(running: false))
}
}
}
#endif

View File

@ -8,9 +8,9 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
@State var confirm = "" @State var confirm = ""
fileprivate var dismissalBlock: () -> () fileprivate var dismissalBlock: (Bool) -> ()
init(secret: StoreType.SecretType, store: StoreType, dismissalBlock: @escaping () -> ()) { init(secret: StoreType.SecretType, store: StoreType, dismissalBlock: @escaping (Bool) -> ()) {
self.secret = secret self.secret = secret
self.store = store self.store = store
self.dismissalBlock = dismissalBlock self.dismissalBlock = dismissalBlock
@ -37,14 +37,16 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
TextField(secret.name, text: $confirm) TextField(secret.name, text: $confirm)
} }
} }
.onExitCommand(perform: dismissalBlock) .onExitCommand {
self.dismissalBlock(false)
}
} }
HStack { HStack {
Spacer() Spacer()
Button(action: delete) { Button(action: delete) {
Text("Delete") Text("Delete")
}.disabled(confirm != secret.name) }.disabled(confirm != secret.name)
Button(action: dismissalBlock) { Button(action: { self.dismissalBlock(false) }) {
Text("Don't Delete") Text("Don't Delete")
} }
} }
@ -53,6 +55,6 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
func delete() { func delete() {
try! store.delete(secret: secret) try! store.delete(secret: secret)
dismissalBlock() self.dismissalBlock(true)
} }
} }

View File

@ -0,0 +1,57 @@
import Foundation
import SwiftUI
struct NoticeView: View {
let text: String
let severity: Severity
let actionTitle: String?
let action: (() -> Void)?
var body: some View {
HStack {
Text(text).bold()
Spacer()
if action != nil {
Button(action: action!) {
Text(actionTitle!)
}
}
}.padding().background(color)
}
var color: Color {
switch severity {
case .advisory:
return Color.orange
case .critical:
return Color.red
}
}
}
extension NoticeView {
enum Severity {
case advisory, critical
}
}
#if DEBUG
struct NoticeView_Previews: PreviewProvider {
static var previews: some View {
Group {
NoticeView(text: "Agent Not Running", severity: .advisory, actionTitle: "Run Setup") {
print("OK")
}
NoticeView(text: "Critical Security Update Required", severity: .critical, actionTitle: "Update") {
print("OK")
}
}
}
}
#endif

View File

@ -24,11 +24,5 @@ class SecretiveTests: XCTestCase {
// Use XCTAssert and related functions to verify your tests produce the correct results. // Use XCTAssert and related functions to verify your tests produce the correct results.
} }
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
} }