mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-04-10 03:07:22 +02:00
Compare commits
2 Commits
automatic_
...
proxystore
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513a93fd18 | ||
|
|
747279f837 |
19
.github/scripts/signing.sh
vendored
19
.github/scripts/signing.sh
vendored
@@ -1,5 +1,22 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Import certificate and private key
|
||||||
|
echo $SIGNING_DATA | base64 -d -o Signing.p12
|
||||||
|
security create-keychain -p ci ci.keychain
|
||||||
|
security default-keychain -s ci.keychain
|
||||||
|
security list-keychains -s ci.keychain
|
||||||
|
security import ./Signing.p12 -k ci.keychain -P $SIGNING_PASSWORD -A
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k ci ci.keychain
|
||||||
|
|
||||||
|
# Import Profiles
|
||||||
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
|
echo $HOST_PROFILE_DATA | base64 -d -o Host.provisionprofile
|
||||||
|
HOST_UUID=`grep UUID -A1 -a Host.provisionprofile | grep -io "[-A-F0-9]\{36\}"`
|
||||||
|
cp Host.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/$HOST_UUID.provisionprofile
|
||||||
|
echo $AGENT_PROFILE_DATA | base64 -d -o Agent.provisionprofile
|
||||||
|
AGENT_UUID=`grep UUID -A1 -a Agent.provisionprofile | grep -io "[-A-F0-9]\{36\}"`
|
||||||
|
cp Agent.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/$AGENT_UUID.provisionprofile
|
||||||
|
|
||||||
# Create directories for ASC key
|
# Create directories for ASC key
|
||||||
mkdir ~/.private_keys
|
mkdir ~/.private_keys
|
||||||
echo -n "$APPLE_API_KEY_DATA" > ~/.private_keys/AuthKey.p8
|
echo -n "$APPLE_API_KEY_DATA" > ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8
|
||||||
|
|||||||
16
.github/workflows/add-to-project.yml
vendored
16
.github/workflows/add-to-project.yml
vendored
@@ -1,16 +0,0 @@
|
|||||||
name: Add bugs to bugs project
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
add-to-project:
|
|
||||||
name: Add issue to project
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/add-to-project@v0.0.3
|
|
||||||
with:
|
|
||||||
project-url: https://github.com/users/maxgoedjen/projects/1
|
|
||||||
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
|
|
||||||
10
.github/workflows/nightly.yml
vendored
10
.github/workflows/nightly.yml
vendored
@@ -5,7 +5,7 @@ on:
|
|||||||
- cron: "0 8 * * *"
|
- cron: "0 8 * * *"
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: macOS-latest
|
runs-on: macos-11.0
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
||||||
run: ./.github/scripts/signing.sh
|
run: ./.github/scripts/signing.sh
|
||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_14.1.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_13.2.1.app
|
||||||
- name: Update Build Number
|
- name: Update Build Number
|
||||||
env:
|
env:
|
||||||
RUN_ID: ${{ github.run_id }}
|
RUN_ID: ${{ github.run_id }}
|
||||||
@@ -40,14 +40,10 @@ jobs:
|
|||||||
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
||||||
- name: Document SHAs
|
- name: Document SHAs
|
||||||
run: |
|
run: |
|
||||||
echo "sha-512:"
|
|
||||||
shasum -a 512 Secretive.zip
|
shasum -a 512 Secretive.zip
|
||||||
shasum -a 512 Archive.zip
|
shasum -a 512 Archive.zip
|
||||||
echo "sha-256:"
|
|
||||||
shasum -a 256 Secretive.zip
|
|
||||||
shasum -a 256 Archive.zip
|
|
||||||
- name: Upload App to Artifacts
|
- name: Upload App to Artifacts
|
||||||
uses: actions/upload-artifact@v1
|
uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: Secretive.zip
|
name: Secretive.zip
|
||||||
path: Secretive.zip
|
path: Secretive.zip
|
||||||
69
.github/workflows/release.yml
vendored
69
.github/workflows/release.yml
vendored
@@ -5,33 +5,11 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
jobs:
|
jobs:
|
||||||
# test:
|
test:
|
||||||
# runs-on: macOS-latest
|
runs-on: macos-11.0
|
||||||
# timeout-minutes: 10
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/checkout@v3
|
|
||||||
# - 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 }}
|
|
||||||
# APPLE_API_KEY_DATA: ${{ secrets.APPLE_API_KEY_DATA }}
|
|
||||||
# APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
||||||
# run: ./.github/scripts/signing.sh
|
|
||||||
# - name: Set Environment
|
|
||||||
# run: sudo xcrun xcode-select -s /Applications/Xcode_14.1.app
|
|
||||||
# - name: Test
|
|
||||||
# run: |
|
|
||||||
# pushd Sources/Packages
|
|
||||||
# swift test
|
|
||||||
# popd
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: macOS-latest
|
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v1
|
||||||
- name: Setup Signing
|
- name: Setup Signing
|
||||||
env:
|
env:
|
||||||
SIGNING_DATA: ${{ secrets.SIGNING_DATA }}
|
SIGNING_DATA: ${{ secrets.SIGNING_DATA }}
|
||||||
@@ -42,7 +20,28 @@ jobs:
|
|||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
||||||
run: ./.github/scripts/signing.sh
|
run: ./.github/scripts/signing.sh
|
||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_14.1.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_13.2.1.app
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
pushd Sources/Packages
|
||||||
|
swift test
|
||||||
|
popd
|
||||||
|
build:
|
||||||
|
runs-on: macos-11.0
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- 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 }}
|
||||||
|
APPLE_API_KEY_DATA: ${{ secrets.APPLE_API_KEY_DATA }}
|
||||||
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
||||||
|
run: ./.github/scripts/signing.sh
|
||||||
|
- name: Set Environment
|
||||||
|
run: sudo xcrun xcode-select -s /Applications/Xcode_13.2.1.app
|
||||||
- name: Update Build Number
|
- name: Update Build Number
|
||||||
env:
|
env:
|
||||||
TAG_NAME: ${{ github.ref }}
|
TAG_NAME: ${{ github.ref }}
|
||||||
@@ -53,32 +52,20 @@ jobs:
|
|||||||
sed -i '' -e "s/GITHUB_BUILD_NUMBER/1.$RUN_ID/g" Sources/Config/Config.xcconfig
|
sed -i '' -e "s/GITHUB_BUILD_NUMBER/1.$RUN_ID/g" Sources/Config/Config.xcconfig
|
||||||
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
|
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
||||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
||||||
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive -destination "generic/platform=macOS" archive
|
|
||||||
- name: Export Products
|
|
||||||
env:
|
|
||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
||||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
||||||
run: xcrun xcodebuild -exportArchive -archivePath Archive.xcarchive -exportPath Export -exportOptionsPlist Sources/Config/ExportOptions.plist -allowProvisioningUpdates -authenticationKeyIssuerID $APPLE_API_ISSUER -authenticationKeyID $APPLE_API_KEY_ID -authenticationKeyPath ~/.private_keys/AuthKey.p8
|
|
||||||
- name: Create ZIPs
|
- name: Create ZIPs
|
||||||
run: |
|
run: |
|
||||||
ditto -c -k --sequesterRsrc --keepParent Export/Secretive.app ./Secretive.zip
|
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip
|
||||||
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Archive.zip
|
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Archive.zip
|
||||||
- name: Notarize
|
- name: Notarize
|
||||||
env:
|
env:
|
||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
||||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
||||||
run: xcrun notarytool submit --key $(pwd)/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
||||||
- name: Document SHAs
|
- name: Document SHAs
|
||||||
run: |
|
run: |
|
||||||
echo "sha-512:"
|
|
||||||
shasum -a 512 Secretive.zip
|
shasum -a 512 Secretive.zip
|
||||||
shasum -a 512 Archive.zip
|
shasum -a 512 Archive.zip
|
||||||
echo "sha-256:"
|
|
||||||
shasum -a 256 Secretive.zip
|
|
||||||
shasum -a 256 Archive.zip
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
|
|||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -3,12 +3,12 @@ name: Test
|
|||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: macOS-latest
|
runs-on: macos-11.0
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set Environment
|
- name: Set Environment
|
||||||
run: sudo xcrun xcode-select -s /Applications/Xcode_14.1.app
|
run: sudo xcrun xcode-select -s /Applications/Xcode_13.2.1.app
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: |
|
||||||
pushd Sources/Packages
|
pushd Sources/Packages
|
||||||
|
|||||||
@@ -26,15 +26,6 @@ Host *
|
|||||||
IdentityAgent /Users/$YOUR_USERNAME/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh
|
IdentityAgent /Users/$YOUR_USERNAME/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh
|
||||||
```
|
```
|
||||||
|
|
||||||
## nushell
|
|
||||||
|
|
||||||
Add this to your `~/.ssh/config` (the path should match the socket path from the setup flow).
|
|
||||||
|
|
||||||
```
|
|
||||||
Host *
|
|
||||||
IdentityAgent /Users/$YOUR_USERNAME/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cyberduck
|
## Cyberduck
|
||||||
|
|
||||||
Add this to `~/Library/LaunchAgents/com.maxgoedjen.Secretive.SecretAgent.plist`
|
Add this to `~/Library/LaunchAgents/com.maxgoedjen.Secretive.SecretAgent.plist`
|
||||||
@@ -60,31 +51,6 @@ Add this to `~/Library/LaunchAgents/com.maxgoedjen.Secretive.SecretAgent.plist`
|
|||||||
|
|
||||||
Log out and log in again before launching Cyberduck.
|
Log out and log in again before launching Cyberduck.
|
||||||
|
|
||||||
## Mountain Duck
|
|
||||||
|
|
||||||
Add this to `~/Library/LaunchAgents/com.maxgoedjen.Secretive.SecretAgent.plist`
|
|
||||||
|
|
||||||
```
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>Label</key>
|
|
||||||
<string>link-ssh-auth-sock</string>
|
|
||||||
<key>ProgramArguments</key>
|
|
||||||
<array>
|
|
||||||
<string>/bin/sh</string>
|
|
||||||
<string>-c</string>
|
|
||||||
<string>/bin/ln -sf $HOME/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh $SSH_AUTH_SOCK</string>
|
|
||||||
</array>
|
|
||||||
<key>RunAtLoad</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
```
|
|
||||||
|
|
||||||
Log out and log in again before launching Mountain Duck.
|
|
||||||
|
|
||||||
## GitKraken
|
## GitKraken
|
||||||
|
|
||||||
Add this to `~/Library/LaunchAgents/com.maxgoedjen.Secretive.SecretAgent.plist`
|
Add this to `~/Library/LaunchAgents/com.maxgoedjen.Secretive.SecretAgent.plist`
|
||||||
|
|||||||
4
FAQ.md
4
FAQ.md
@@ -12,10 +12,6 @@ Secretive relies on the `SSH_AUTH_SOCK` environment variable being respected. Th
|
|||||||
|
|
||||||
Please run `ssh -Tv git@github.com` in your terminal and paste the output in a [new GitHub issue](https://github.com/maxgoedjen/secretive/issues/new) with a description of your issue.
|
Please run `ssh -Tv git@github.com` in your terminal and paste the output in a [new GitHub issue](https://github.com/maxgoedjen/secretive/issues/new) with a description of your issue.
|
||||||
|
|
||||||
### Secretive was working for me, but now it has stopped
|
|
||||||
|
|
||||||
Try running the "Setup Secretive" process by clicking on "Help", then "Setup Secretive." If that doesn't work, follow the process above.
|
|
||||||
|
|
||||||
### Secretive prompts me to type my password instead of using my Apple Watch
|
### Secretive prompts me to type my password instead of using my Apple Watch
|
||||||
|
|
||||||
1) Make sure you have enabled "Use your Apple Watch to unlock apps and your Mac" in System Preferences --> Security & Privacy:
|
1) Make sure you have enabled "Use your Apple Watch to unlock apps and your Mac" in System Preferences --> Security & Privacy:
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>method</key>
|
|
||||||
<string>developer-id</string>
|
|
||||||
<key>teamID</key>
|
|
||||||
<string>Z72PRUAWF6</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -18,6 +18,9 @@ let package = Package(
|
|||||||
.library(
|
.library(
|
||||||
name: "SmartCardSecretKit",
|
name: "SmartCardSecretKit",
|
||||||
targets: ["SmartCardSecretKit"]),
|
targets: ["SmartCardSecretKit"]),
|
||||||
|
.library(
|
||||||
|
name: "ProxyAgentSecretKit",
|
||||||
|
targets: ["ProxyAgentSecretKit"]),
|
||||||
.library(
|
.library(
|
||||||
name: "SecretAgentKit",
|
name: "SecretAgentKit",
|
||||||
targets: ["SecretAgentKit"]),
|
targets: ["SecretAgentKit"]),
|
||||||
@@ -47,6 +50,10 @@ let package = Package(
|
|||||||
name: "SmartCardSecretKit",
|
name: "SmartCardSecretKit",
|
||||||
dependencies: ["SecretKit"]
|
dependencies: ["SecretKit"]
|
||||||
),
|
),
|
||||||
|
.target(
|
||||||
|
name: "ProxyAgentSecretKit",
|
||||||
|
dependencies: ["SecretKit", "SecretAgentKit"]
|
||||||
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "SecretAgentKit",
|
name: "SecretAgentKit",
|
||||||
dependencies: ["SecretKit", "SecretAgentKitHeaders"]
|
dependencies: ["SecretKit", "SecretAgentKitHeaders"]
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/// Namespace for the Proxy Agent implementations.
|
||||||
|
public enum ProxyAgent {}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
import SecretKit
|
||||||
|
|
||||||
|
extension ProxyAgent {
|
||||||
|
|
||||||
|
/// An implementation of Secret backed by a Smart Card.
|
||||||
|
public struct Secret: SecretKit.Secret {
|
||||||
|
|
||||||
|
public let id: Data
|
||||||
|
public let name: String
|
||||||
|
public let algorithm: Algorithm
|
||||||
|
public let keySize: Int
|
||||||
|
public let requiresAuthentication: Bool = false
|
||||||
|
public let publicKey: Data
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import Foundation
|
||||||
|
import Security
|
||||||
|
import CryptoTokenKit
|
||||||
|
import LocalAuthentication
|
||||||
|
import SecretKit
|
||||||
|
|
||||||
|
extension ProxyAgent {
|
||||||
|
|
||||||
|
/// An implementation of Store backed by a Proxy Agent.
|
||||||
|
public class Store: SecretStore {
|
||||||
|
|
||||||
|
@Published public var isAvailable: Bool = true
|
||||||
|
public let id = UUID()
|
||||||
|
public private(set) var name = NSLocalizedString("Proxy SSH Agent", comment: "Proxy SSH Agent")
|
||||||
|
@Published public private(set) var secrets: [Secret] = []
|
||||||
|
private let agentPath: String
|
||||||
|
|
||||||
|
/// Initializes a Store.
|
||||||
|
public init(path: String) {
|
||||||
|
agentPath = path
|
||||||
|
secrets.append(Secret(id: "hello".data(using: .utf8)!, name: "Test", algorithm: .ellipticCurve, keySize: 256, publicKey: Data(base64Encoded: "AAAAC3NzaC1lZDI1NTE5AAAAIINQz8WohBS46ICEUtkJ/vdxJPM63T5Dy4bQC35JVgGR")!))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Public API
|
||||||
|
|
||||||
|
public func create(name: String) throws {
|
||||||
|
fatalError("Keys must be created on the smart card.")
|
||||||
|
}
|
||||||
|
|
||||||
|
public func delete(secret: Secret) throws {
|
||||||
|
fatalError("Keys must be deleted on the smart card.")
|
||||||
|
}
|
||||||
|
|
||||||
|
public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func existingPersistedAuthenticationContext(secret: ProxyAgent.Secret) -> PersistedAuthenticationContext? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func persistAuthentication(secret: ProxyAgent.Secret, forDuration: TimeInterval) throws {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProxyAgent.Store {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProxyAgent {
|
||||||
|
|
||||||
|
/// A signing-related error.
|
||||||
|
public struct SigningError: Error {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,25 +4,6 @@ import OSLog
|
|||||||
import SecretKit
|
import SecretKit
|
||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
enum OpenSSHCertificateError: Error {
|
|
||||||
case unsupportedType
|
|
||||||
case parsingFailed
|
|
||||||
case doesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
extension OpenSSHCertificateError: CustomStringConvertible {
|
|
||||||
public var description: String {
|
|
||||||
switch self {
|
|
||||||
case .unsupportedType:
|
|
||||||
return "The key type was unsupported"
|
|
||||||
case .parsingFailed:
|
|
||||||
return "Failed to properly parse the SSH certificate"
|
|
||||||
case .doesNotExist:
|
|
||||||
return "Certificate does not exist"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The `Agent` is an implementation of an SSH agent. It manages coordination and access between a socket, traces requests, notifies witnesses and passes requests to stores.
|
/// The `Agent` is an implementation of an SSH agent. It manages coordination and access between a socket, traces requests, notifies witnesses and passes requests to stores.
|
||||||
public class Agent {
|
public class Agent {
|
||||||
|
|
||||||
@@ -30,7 +11,6 @@ public class Agent {
|
|||||||
private let witness: SigningWitness?
|
private let witness: SigningWitness?
|
||||||
private let writer = OpenSSHKeyWriter()
|
private let writer = OpenSSHKeyWriter()
|
||||||
private let requestTracer = SigningRequestTracer()
|
private let requestTracer = SigningRequestTracer()
|
||||||
private let certsPath = (NSHomeDirectory() as NSString).appendingPathComponent("PublicKeys") as String
|
|
||||||
|
|
||||||
/// Initializes an agent with a store list and a witness.
|
/// Initializes an agent with a store list and a witness.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
@@ -103,22 +83,12 @@ extension Agent {
|
|||||||
var count = UInt32(secrets.count).bigEndian
|
var count = UInt32(secrets.count).bigEndian
|
||||||
let countData = Data(bytes: &count, count: UInt32.bitWidth/8)
|
let countData = Data(bytes: &count, count: UInt32.bitWidth/8)
|
||||||
var keyData = Data()
|
var keyData = Data()
|
||||||
|
let writer = OpenSSHKeyWriter()
|
||||||
for secret in secrets {
|
for secret in secrets {
|
||||||
let keyBlob: Data
|
let keyBlob = writer.data(secret: secret)
|
||||||
let curveData: Data
|
|
||||||
|
|
||||||
if let (certBlob, certName) = try? checkForCert(secret: secret) {
|
|
||||||
keyBlob = certBlob
|
|
||||||
curveData = certName
|
|
||||||
} else {
|
|
||||||
keyBlob = writer.data(secret: secret)
|
|
||||||
curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!
|
|
||||||
}
|
|
||||||
|
|
||||||
keyData.append(writer.lengthAndData(of: keyBlob))
|
keyData.append(writer.lengthAndData(of: keyBlob))
|
||||||
|
let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!
|
||||||
keyData.append(writer.lengthAndData(of: curveData))
|
keyData.append(writer.lengthAndData(of: curveData))
|
||||||
|
|
||||||
}
|
}
|
||||||
Logger().debug("Agent enumerated \(secrets.count) identities")
|
Logger().debug("Agent enumerated \(secrets.count) identities")
|
||||||
return countData + keyData
|
return countData + keyData
|
||||||
@@ -131,13 +101,7 @@ extension Agent {
|
|||||||
/// - Returns: An OpenSSH formatted Data payload containing the signed data response.
|
/// - Returns: An OpenSSH formatted Data payload containing the signed data response.
|
||||||
func sign(data: Data, provenance: SigningRequestProvenance) throws -> Data {
|
func sign(data: Data, provenance: SigningRequestProvenance) throws -> Data {
|
||||||
let reader = OpenSSHReader(data: data)
|
let reader = OpenSSHReader(data: data)
|
||||||
var hash = reader.readNextChunk()
|
let hash = reader.readNextChunk()
|
||||||
|
|
||||||
// Check if hash is actually an openssh certificate and reconstruct the public key if it is
|
|
||||||
if let certPublicKey = try? getPublicKeyFromCert(certBlob: hash) {
|
|
||||||
hash = certPublicKey
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let (store, secret) = secret(matching: hash) else {
|
guard let (store, secret) = secret(matching: hash) else {
|
||||||
Logger().debug("Agent did not have a key matching \(hash as NSData)")
|
Logger().debug("Agent did not have a key matching \(hash as NSData)")
|
||||||
throw AgentError.noMatchingKey
|
throw AgentError.noMatchingKey
|
||||||
@@ -197,74 +161,6 @@ extension Agent {
|
|||||||
|
|
||||||
return signedData
|
return signedData
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconstructs a public key from a ``Data`` object that contains an OpenSSH certificate. Currently only ecdsa certificates are supported
|
|
||||||
/// - Parameter certBlock: The openssh certificate to extract the public key from
|
|
||||||
/// - Returns: A ``Data`` object containing the public key in OpenSSH wire format
|
|
||||||
func getPublicKeyFromCert(certBlob: Data) throws -> Data {
|
|
||||||
let reader = OpenSSHReader(data: certBlob)
|
|
||||||
let certType = String(decoding: reader.readNextChunk(), as: UTF8.self)
|
|
||||||
|
|
||||||
switch certType {
|
|
||||||
case "ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
|
||||||
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
|
||||||
"ecdsa-sha2-nistp521-cert-v01@openssh.com":
|
|
||||||
|
|
||||||
_ = reader.readNextChunk() // nonce
|
|
||||||
let curveIdentifier = reader.readNextChunk()
|
|
||||||
let publicKey = reader.readNextChunk()
|
|
||||||
|
|
||||||
if let curveType = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "").data(using: .utf8) {
|
|
||||||
return writer.lengthAndData(of: curveType) +
|
|
||||||
writer.lengthAndData(of: curveIdentifier) +
|
|
||||||
writer.lengthAndData(of: publicKey)
|
|
||||||
} else {
|
|
||||||
throw OpenSSHCertificateError.parsingFailed
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw OpenSSHCertificateError.unsupportedType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
|
||||||
/// - Parameter secret: The secret to search for a certificate with
|
|
||||||
/// - Returns: Two ``Data`` objects containing the certificate and certificate name respectively
|
|
||||||
func checkForCert(secret: AnySecret) throws -> (Data, Data) {
|
|
||||||
let minimalHex = writer.openSSHMD5Fingerprint(secret: secret).replacingOccurrences(of: ":", with: "")
|
|
||||||
let certificatePath = certsPath.appending("/").appending("\(minimalHex)-cert.pub")
|
|
||||||
|
|
||||||
if FileManager.default.fileExists(atPath: certificatePath) {
|
|
||||||
Logger().debug("Found certificate for \(secret.name)")
|
|
||||||
do {
|
|
||||||
let certContent = try String(contentsOfFile:certificatePath, encoding: .utf8)
|
|
||||||
let certElements = certContent.trimmingCharacters(in: .whitespacesAndNewlines).components(separatedBy: " ")
|
|
||||||
|
|
||||||
if certElements.count >= 2 {
|
|
||||||
if let certDecoded = Data(base64Encoded: certElements[1] as String) {
|
|
||||||
if certElements.count >= 3 {
|
|
||||||
if let certName = certElements[2].data(using: .utf8) {
|
|
||||||
return (certDecoded, certName)
|
|
||||||
} else if let certName = secret.name.data(using: .utf8) {
|
|
||||||
Logger().info("Certificate for \(secret.name) does not have a name tag, using secret name instead")
|
|
||||||
return (certDecoded, certName)
|
|
||||||
} else {
|
|
||||||
throw OpenSSHCertificateError.parsingFailed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Logger().warning("Certificate found for \(secret.name) but failed to decode base64 key")
|
|
||||||
throw OpenSSHCertificateError.parsingFailed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
Logger().warning("Certificate found for \(secret.name) but failed to load")
|
|
||||||
throw OpenSSHCertificateError.parsingFailed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw OpenSSHCertificateError.doesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,10 +40,7 @@ extension SigningRequestTracer {
|
|||||||
func process(from pid: Int32) -> SigningRequestProvenance.Process {
|
func process(from pid: Int32) -> SigningRequestProvenance.Process {
|
||||||
var pidAndNameInfo = self.pidAndNameInfo(from: pid)
|
var pidAndNameInfo = self.pidAndNameInfo(from: pid)
|
||||||
let ppid = pidAndNameInfo.kp_eproc.e_ppid != 0 ? pidAndNameInfo.kp_eproc.e_ppid : nil
|
let ppid = pidAndNameInfo.kp_eproc.e_ppid != 0 ? pidAndNameInfo.kp_eproc.e_ppid : nil
|
||||||
let procName = withUnsafeMutablePointer(to: &pidAndNameInfo.kp_proc.p_comm.0) { pointer in
|
let procName = String(cString: &pidAndNameInfo.kp_proc.p_comm.0)
|
||||||
String(cString: pointer)
|
|
||||||
}
|
|
||||||
|
|
||||||
let pathPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(MAXPATHLEN))
|
let pathPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(MAXPATHLEN))
|
||||||
_ = proc_pidpath(pid, pathPointer, UInt32(MAXPATHLEN))
|
_ = proc_pidpath(pid, pathPointer, UInt32(MAXPATHLEN))
|
||||||
let path = String(cString: pathPointer)
|
let path = String(cString: pathPointer)
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ extension OpenSSHKeyWriter {
|
|||||||
switch algorithm {
|
switch algorithm {
|
||||||
case .ellipticCurve:
|
case .ellipticCurve:
|
||||||
return "ecdsa-sha2-nistp" + String(describing: length)
|
return "ecdsa-sha2-nistp" + String(describing: length)
|
||||||
|
case .rsa:
|
||||||
|
return "ssh-rsa"
|
||||||
|
case .ed25519:
|
||||||
|
return "ssh-ed25519"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +80,11 @@ extension OpenSSHKeyWriter {
|
|||||||
switch algorithm {
|
switch algorithm {
|
||||||
case .ellipticCurve:
|
case .ellipticCurve:
|
||||||
return "nistp" + String(describing: length)
|
return "nistp" + String(describing: length)
|
||||||
|
// TODO: VERIFY
|
||||||
|
case .rsa:
|
||||||
|
return "rsa"
|
||||||
|
case .ed25519:
|
||||||
|
return "ed25519"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,21 +15,15 @@ public class PublicKeyFileStoreController {
|
|||||||
|
|
||||||
/// Writes out the keys specified to disk.
|
/// Writes out the keys specified to disk.
|
||||||
/// - Parameter secrets: The Secrets to generate keys for.
|
/// - Parameter secrets: The Secrets to generate keys for.
|
||||||
/// - Parameter clear: Whether or not any untracked files in the directory should be removed.
|
/// - Parameter clear: Whether or not the directory should be erased before writing keys.
|
||||||
public func generatePublicKeys(for secrets: [AnySecret], clear: Bool = false) throws {
|
public func generatePublicKeys(for secrets: [AnySecret], clear: Bool = false) throws {
|
||||||
logger.log("Writing public keys to disk")
|
logger.log("Writing public keys to disk")
|
||||||
if clear {
|
if clear {
|
||||||
let validPaths = Set(secrets.map { publicKeyPath(for: $0) }).union(Set(secrets.map { sshCertificatePath(for: $0) }))
|
try? FileManager.default.removeItem(at: URL(fileURLWithPath: directory))
|
||||||
let untracked = Set(try FileManager.default.contentsOfDirectory(atPath: directory)
|
|
||||||
.map { "\(directory)/\($0)" })
|
|
||||||
.subtracting(validPaths)
|
|
||||||
for path in untracked {
|
|
||||||
try? FileManager.default.removeItem(at: URL(fileURLWithPath: path))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try? FileManager.default.createDirectory(at: URL(fileURLWithPath: directory), withIntermediateDirectories: false, attributes: nil)
|
try? FileManager.default.createDirectory(at: URL(fileURLWithPath: directory), withIntermediateDirectories: false, attributes: nil)
|
||||||
for secret in secrets {
|
for secret in secrets {
|
||||||
let path = publicKeyPath(for: secret)
|
let path = path(for: secret)
|
||||||
guard let data = keyWriter.openSSHString(secret: secret).data(using: .utf8) else { continue }
|
guard let data = keyWriter.openSSHString(secret: secret).data(using: .utf8) else { continue }
|
||||||
FileManager.default.createFile(atPath: path, contents: data, attributes: nil)
|
FileManager.default.createFile(atPath: path, contents: data, attributes: nil)
|
||||||
}
|
}
|
||||||
@@ -40,18 +34,9 @@ public class PublicKeyFileStoreController {
|
|||||||
/// - Parameter secret: The Secret to return the path for.
|
/// - Parameter secret: The Secret to return the path for.
|
||||||
/// - Returns: The path to the Secret's public key.
|
/// - Returns: The path to the Secret's public key.
|
||||||
/// - Warning: This method returning a path does not imply that a key has been written to disk already. This method only describes where it will be written to.
|
/// - Warning: This method returning a path does not imply that a key has been written to disk already. This method only describes where it will be written to.
|
||||||
public func publicKeyPath<SecretType: Secret>(for secret: SecretType) -> String {
|
public func path<SecretType: Secret>(for secret: SecretType) -> String {
|
||||||
let minimalHex = keyWriter.openSSHMD5Fingerprint(secret: secret).replacingOccurrences(of: ":", with: "")
|
let minimalHex = keyWriter.openSSHMD5Fingerprint(secret: secret).replacingOccurrences(of: ":", with: "")
|
||||||
return directory.appending("/").appending("\(minimalHex).pub")
|
return directory.appending("/").appending("\(minimalHex).pub")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The path for a Secret's SSH Certificate public key.
|
|
||||||
/// - Parameter secret: The Secret to return the path for.
|
|
||||||
/// - Returns: The path to the SSH Certificate public key.
|
|
||||||
/// - Warning: This method returning a path does not imply that a key has a SSH certificates. This method only describes where it will be.
|
|
||||||
public func sshCertificatePath<SecretType: Secret>(for secret: SecretType) -> String {
|
|
||||||
let minimalHex = keyWriter.openSSHMD5Fingerprint(secret: secret).replacingOccurrences(of: ":", with: "")
|
|
||||||
return directory.appending("/").appending("\(minimalHex)-cert.pub")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ public protocol Secret: Identifiable, Hashable {
|
|||||||
/// The type of algorithm the Secret uses. Currently, only elliptic curve algorithms are supported.
|
/// The type of algorithm the Secret uses. Currently, only elliptic curve algorithms are supported.
|
||||||
public enum Algorithm: Hashable {
|
public enum Algorithm: Hashable {
|
||||||
|
|
||||||
|
case rsa
|
||||||
|
case ed25519
|
||||||
case ellipticCurve
|
case ellipticCurve
|
||||||
|
|
||||||
/// Initializes the Algorithm with a secAttr representation of an algorithm.
|
/// Initializes the Algorithm with a secAttr representation of an algorithm.
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
|
|||||||
case Notifier.Constants.persistAuthenticationCategoryIdentitifier:
|
case Notifier.Constants.persistAuthenticationCategoryIdentitifier:
|
||||||
handlePersistAuthenticationResponse(response: response)
|
handlePersistAuthenticationResponse(response: response)
|
||||||
default:
|
default:
|
||||||
break
|
fatalError()
|
||||||
}
|
}
|
||||||
|
|
||||||
completionHandler()
|
completionHandler()
|
||||||
|
|||||||
@@ -47,6 +47,8 @@
|
|||||||
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 */; };
|
||||||
|
50A63F6B27E7DC5700085D7B /* ProxyAgentSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 50A63F6A27E7DC5700085D7B /* ProxyAgentSecretKit */; };
|
||||||
|
50A63F6D27E7E04800085D7B /* ProxyAgentSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 50A63F6C27E7E04800085D7B /* ProxyAgentSecretKit */; };
|
||||||
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; };
|
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; };
|
||||||
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; };
|
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; };
|
||||||
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; };
|
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; };
|
||||||
@@ -154,6 +156,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
50A63F6D27E7E04800085D7B /* ProxyAgentSecretKit in Frameworks */,
|
||||||
5003EF3B278005E800DF2006 /* SecretKit in Frameworks */,
|
5003EF3B278005E800DF2006 /* SecretKit in Frameworks */,
|
||||||
501421622781262300BBAA70 /* Brief in Frameworks */,
|
501421622781262300BBAA70 /* Brief in Frameworks */,
|
||||||
5003EF5F2780081600DF2006 /* SecureEnclaveSecretKit in Frameworks */,
|
5003EF5F2780081600DF2006 /* SecureEnclaveSecretKit in Frameworks */,
|
||||||
@@ -174,6 +177,7 @@
|
|||||||
files = (
|
files = (
|
||||||
5003EF3D278005F300DF2006 /* Brief in Frameworks */,
|
5003EF3D278005F300DF2006 /* Brief in Frameworks */,
|
||||||
5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */,
|
5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */,
|
||||||
|
50A63F6B27E7DC5700085D7B /* ProxyAgentSecretKit in Frameworks */,
|
||||||
5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */,
|
5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */,
|
||||||
5003EF3F278005F300DF2006 /* SecretAgentKit in Frameworks */,
|
5003EF3F278005F300DF2006 /* SecretAgentKit in Frameworks */,
|
||||||
5003EF41278005FA00DF2006 /* SecretKit in Frameworks */,
|
5003EF41278005FA00DF2006 /* SecretKit in Frameworks */,
|
||||||
@@ -345,6 +349,7 @@
|
|||||||
5003EF5E2780081600DF2006 /* SecureEnclaveSecretKit */,
|
5003EF5E2780081600DF2006 /* SecureEnclaveSecretKit */,
|
||||||
5003EF602780081600DF2006 /* SmartCardSecretKit */,
|
5003EF602780081600DF2006 /* SmartCardSecretKit */,
|
||||||
501421612781262300BBAA70 /* Brief */,
|
501421612781262300BBAA70 /* Brief */,
|
||||||
|
50A63F6C27E7E04800085D7B /* ProxyAgentSecretKit */,
|
||||||
);
|
);
|
||||||
productName = Secretive;
|
productName = Secretive;
|
||||||
productReference = 50617D7F23FCE48E0099B055 /* Secretive.app */;
|
productReference = 50617D7F23FCE48E0099B055 /* Secretive.app */;
|
||||||
@@ -388,6 +393,7 @@
|
|||||||
5003EF40278005FA00DF2006 /* SecretKit */,
|
5003EF40278005FA00DF2006 /* SecretKit */,
|
||||||
5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */,
|
5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */,
|
||||||
5003EF642780081B00DF2006 /* SmartCardSecretKit */,
|
5003EF642780081B00DF2006 /* SmartCardSecretKit */,
|
||||||
|
50A63F6A27E7DC5700085D7B /* ProxyAgentSecretKit */,
|
||||||
);
|
);
|
||||||
productName = SecretAgent;
|
productName = SecretAgent;
|
||||||
productReference = 50A3B78A24026B7500D209EA /* SecretAgent.app */;
|
productReference = 50A3B78A24026B7500D209EA /* SecretAgent.app */;
|
||||||
@@ -697,7 +703,7 @@
|
|||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = Secretive/Secretive.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Secretive/Secretive.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "";
|
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;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -713,7 +719,7 @@
|
|||||||
MARKETING_VERSION = 1;
|
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 = "Secretive - Host";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
@@ -830,13 +836,10 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = Secretive/Secretive.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "";
|
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Secretive/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = Z72PRUAWF6;
|
|
||||||
ENABLE_HARDENED_RUNTIME = NO;
|
ENABLE_HARDENED_RUNTIME = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = Secretive/Info.plist;
|
INFOPLIST_FILE = Secretive/Info.plist;
|
||||||
@@ -847,7 +850,6 @@
|
|||||||
MARKETING_VERSION = 1;
|
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 = "";
|
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Test;
|
name = Test;
|
||||||
@@ -878,12 +880,9 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "";
|
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = Z72PRUAWF6;
|
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = SecretAgent/Info.plist;
|
INFOPLIST_FILE = SecretAgent/Info.plist;
|
||||||
@@ -894,8 +893,6 @@
|
|||||||
MARKETING_VERSION = 1;
|
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 = "";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Test;
|
name = Test;
|
||||||
@@ -905,7 +902,6 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
|
CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
|
||||||
@@ -920,8 +916,6 @@
|
|||||||
MARKETING_VERSION = 1;
|
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 = "";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -931,7 +925,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
|
CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
|
||||||
@@ -946,8 +940,7 @@
|
|||||||
MARKETING_VERSION = 1;
|
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 = "";
|
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
@@ -1034,6 +1027,14 @@
|
|||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = Brief;
|
productName = Brief;
|
||||||
};
|
};
|
||||||
|
50A63F6A27E7DC5700085D7B /* ProxyAgentSecretKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = ProxyAgentSecretKit;
|
||||||
|
};
|
||||||
|
50A63F6C27E7E04800085D7B /* ProxyAgentSecretKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = ProxyAgentSecretKit;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 50617D7723FCE48D0099B055 /* Project object */;
|
rootObject = 50617D7723FCE48D0099B055 /* Project object */;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ struct SecretDetailView<SecretType: Secret>: View {
|
|||||||
CopyableView(title: "Public Key", image: Image(systemName: "key"), text: keyString)
|
CopyableView(title: "Public Key", image: Image(systemName: "key"), text: keyString)
|
||||||
Spacer()
|
Spacer()
|
||||||
.frame(height: 20)
|
.frame(height: 20)
|
||||||
CopyableView(title: "Public Key Path", image: Image(systemName: "lock.doc"), text: publicKeyFileStoreController.publicKeyPath(for: secret))
|
CopyableView(title: "Public Key Path", image: Image(systemName: "lock.doc"), text: publicKeyFileStoreController.path(for: secret))
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user