Merge branch 'main' into popovers

This commit is contained in:
Max Goedjen 2020-11-11 15:35:25 -08:00
commit 763b6ea57d
No known key found for this signature in database
GPG Key ID: E58C21DD77B9B8E8
16 changed files with 61 additions and 46 deletions

View File

@ -6,7 +6,7 @@ on:
- '*' - '*'
jobs: jobs:
test: test:
runs-on: macOS-latest runs-on: macos-11.0
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
@ -18,7 +18,7 @@ jobs:
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: Set Environment - name: Set Environment
run: sudo xcrun xcode-select -s /Applications/Xcode_12_beta.app run: sudo xcrun xcode-select -s /Applications/Xcode_12.2.app
- name: Test - name: Test
run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive
build: build:

View File

@ -3,11 +3,11 @@ 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_12_beta.app run: sudo xcrun xcode-select -s /Applications/Xcode_12.2.app
- name: Test - name: Test
run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive

33
APP_CONFIG.md Normal file
View File

@ -0,0 +1,33 @@
# Setting up Third Party Apps FAQ
## Tower
Tower provides [instructions](https://www.git-tower.com/help/mac/integration/environment).
## GitHub Desktop
Should just work, no configuration needed
## Fork
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
```
## VS Code
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
```
# The app I use isn't listed here!
If you know how to get it set up, please open a PR for this page and add it! Contributions are very welcome.
If you're not able to get it working, please file a [GitHub issue](https://github.com/maxgoedjen/secretive/issues/new) for it. No guarantees we'll be able to get it working, but chances are someone else in the community might be able to.

8
FAQ.md
View File

@ -4,13 +4,9 @@
The secure enclave doesn't allow import or export of private keys. For any new computer, you should just create a new set of keys. If you're using a smart card, you _might_ be able to export your private key from the vendor's software. The secure enclave doesn't allow import or export of private keys. For any new computer, you should just create a new set of keys. If you're using a smart card, you _might_ be able to export your private key from the vendor's software.
### Secretive doesn't work with my git client ### Secretive doesn't work with my git client/app
Secretive relies on the `SSH_AUTH_SOCK` environment variable being respected. The `git` and `ssh` command line tools natively respect this, but third party apps may require some configuration to work. A non-exhaustive list of clients is provided here: Secretive relies on the `SSH_AUTH_SOCK` environment variable being respected. The `git` and `ssh` command line tools natively respect this, but third party apps may require some configuration to work. A non-exhaustive list of setup steps is provided in the [App Config FAQ](APP_CONFIG.md).
Tower - [Instructions](https://www.git-tower.com/help/mac/integration/environment)
GitHub Desktop: Should just work, no configuration needed
### Secretive isn't working for me ### Secretive isn't working for me

BIN
Icon.sketch Normal file

Binary file not shown.

View File

@ -26,7 +26,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private var updateSink: AnyCancellable? private var updateSink: AnyCancellable?
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
os_log(.debug, "SecretAgent finished launching") Logger().debug("SecretAgent finished launching")
DispatchQueue.main.async { DispatchQueue.main.async {
self.socketController.handler = self.agent.handle(reader:writer:) self.socketController.handler = self.agent.handle(reader:writer:)
} }

View File

@ -12,7 +12,7 @@ public class Agent {
private let requestTracer = SigningRequestTracer() private let requestTracer = SigningRequestTracer()
public init(storeList: SecretStoreList, witness: SigningWitness? = nil) { public init(storeList: SecretStoreList, witness: SigningWitness? = nil) {
os_log(.debug, "Agent is running") Logger().debug("Agent is running")
self.storeList = storeList self.storeList = storeList
self.witness = witness self.witness = witness
} }
@ -22,16 +22,16 @@ public class Agent {
extension Agent { extension Agent {
public func handle(reader: FileHandleReader, writer: FileHandleWriter) { public func handle(reader: FileHandleReader, writer: FileHandleWriter) {
os_log(.debug, "Agent handling new data") Logger().debug("Agent handling new data")
let data = reader.availableData let data = reader.availableData
guard !data.isEmpty else { return } guard !data.isEmpty else { return }
let requestTypeInt = data[4] let requestTypeInt = data[4]
guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else {
writer.write(OpenSSHKeyWriter().lengthAndData(of: SSHAgent.ResponseType.agentFailure.data)) writer.write(OpenSSHKeyWriter().lengthAndData(of: SSHAgent.ResponseType.agentFailure.data))
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription) Logger().debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription)")
return return
} }
os_log(.debug, "Agent handling request of type %@", requestType.debugDescription) Logger().debug("Agent handling request of type \(requestType.debugDescription)")
let subData = Data(data[5...]) let subData = Data(data[5...])
let response = handle(requestType: requestType, data: subData, reader: reader) let response = handle(requestType: requestType, data: subData, reader: reader)
writer.write(response) writer.write(response)
@ -44,17 +44,17 @@ extension Agent {
case .requestIdentities: case .requestIdentities:
response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data) response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data)
response.append(identities()) response.append(identities())
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) Logger().debug("Agent returned \(SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)")
case .signRequest: case .signRequest:
let provenance = requestTracer.provenance(from: reader) let provenance = requestTracer.provenance(from: reader)
response.append(SSHAgent.ResponseType.agentSignResponse.data) response.append(SSHAgent.ResponseType.agentSignResponse.data)
response.append(try sign(data: data, provenance: provenance)) response.append(try sign(data: data, provenance: provenance))
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription) Logger().debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)")
} }
} catch { } catch {
response.removeAll() response.removeAll()
response.append(SSHAgent.ResponseType.agentFailure.data) response.append(SSHAgent.ResponseType.agentFailure.data)
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentFailure.debugDescription) Logger().debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription)")
} }
let full = OpenSSHKeyWriter().lengthAndData(of: response) let full = OpenSSHKeyWriter().lengthAndData(of: response)
return full return full
@ -76,7 +76,7 @@ extension Agent {
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)!
keyData.append(writer.lengthAndData(of: curveData)) keyData.append(writer.lengthAndData(of: curveData))
} }
os_log(.debug, "Agent enumerated %@ identities", secrets.count as NSNumber) Logger().debug("Agent enumerated \(secrets.count) identities")
return countData + keyData return countData + keyData
} }
@ -84,7 +84,7 @@ extension Agent {
let reader = OpenSSHReader(data: data) let reader = OpenSSHReader(data: data)
let hash = reader.readNextChunk() let hash = reader.readNextChunk()
guard let (store, secret) = secret(matching: hash) else { guard let (store, secret) = secret(matching: hash) else {
os_log(.debug, "Agent did not have a key matching %@", hash as NSData) Logger().debug("Agent did not have a key matching \(hash as NSData)")
throw AgentError.noMatchingKey throw AgentError.noMatchingKey
} }
@ -137,7 +137,7 @@ extension Agent {
try witness.witness(accessTo: secret, by: provenance) try witness.witness(accessTo: secret, by: provenance)
} }
os_log(.debug, "Agent signed request") Logger().debug("Agent signed request")
return signedData return signedData
} }

View File

@ -8,16 +8,16 @@ public class SocketController {
public var handler: ((FileHandleReader, FileHandleWriter) -> Void)? public var handler: ((FileHandleReader, FileHandleWriter) -> Void)?
public init(path: String) { public init(path: String) {
os_log(.debug, "Socket controller setting up at %@", path) Logger().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") Logger().debug("Socket controller removed existing socket")
} }
let exists = FileManager.default.fileExists(atPath: path) let exists = FileManager.default.fileExists(atPath: path)
assert(!exists) assert(!exists)
os_log(.debug, "Socket controller path is clear") Logger().debug("Socket controller path is clear")
port = socketPort(at: path) port = socketPort(at: path)
configureSocket(at: path) configureSocket(at: path)
os_log(.debug, "Socket listening at %@", path) Logger().debug("Socket listening at \(path)")
} }
func configureSocket(at path: String) { func configureSocket(at path: String) {
@ -50,7 +50,7 @@ public class SocketController {
} }
@objc func handleConnectionAccept(notification: Notification) { @objc func handleConnectionAccept(notification: Notification) {
os_log(.debug, "Socket controller accepted connection") Logger().debug("Socket controller accepted connection")
guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return } guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return }
handler?(new, new) handler?(new, new)
new.waitForDataInBackgroundAndNotify() new.waitForDataInBackgroundAndNotify()
@ -58,9 +58,9 @@ public class SocketController {
} }
@objc func handleConnectionDataAvailable(notification: Notification) { @objc func handleConnectionDataAvailable(notification: Notification) {
os_log(.debug, "Socket controller has new data available") Logger().debug("Socket controller has new data available")
guard let new = notification.object as? FileHandle else { return } guard let new = notification.object as? FileHandle else { return }
os_log(.debug, "Socket controller received new file handle") Logger().debug("Socket controller received new file handle")
handler?(new, new) handler?(new, new)
} }

View File

@ -1401,7 +1401,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1432,7 +1431,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1455,7 +1453,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
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;
@ -1475,7 +1472,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
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;
@ -1502,7 +1498,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1532,7 +1527,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1563,7 +1557,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1719,7 +1712,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1743,7 +1735,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -1770,7 +1761,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1794,7 +1784,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -1880,7 +1869,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1911,7 +1899,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/Frameworks", "@loader_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1934,7 +1921,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
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;
@ -1954,7 +1940,6 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
"@loader_path/../Frameworks", "@loader_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.15;
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;

View File

@ -31,13 +31,13 @@
"size" : "128x128" "size" : "128x128"
}, },
{ {
"filename" : "Icon 2@1x.png", "filename" : "Mac Icon.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "256x256" "size" : "256x256"
}, },
{ {
"filename" : "Icon 2@2x.png", "filename" : "Mac Icon@0.25x.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "256x256" "size" : "256x256"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -23,7 +23,7 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
} }
HStack { HStack {
Text("Name:") Text("Name:")
TextField("Shhhhh", text: $name) TextField("Shhhhh", text: $name).focusable()
} }
HStack { HStack {
Toggle(isOn: $requiresAuthentication) { Toggle(isOn: $requiresAuthentication) {

View File

@ -176,6 +176,7 @@ struct SSHAgentSetupView: View {
bodyText: "Add this line to your shell config telling SSH to talk to Secret Agent when it wants to authenticate. Secretive can either do this for you automatically, or you can copy and paste this into your config file.", bodyText: "Add this line to your shell config telling SSH to talk to Secret Agent when it wants to authenticate. Secretive can either do this for you automatically, or you can copy and paste this into your config file.",
buttonTitle: "I Added it Manually", buttonTitle: "I Added it Manually",
buttonAction: buttonAction) { buttonAction: buttonAction) {
Link("If you're trying to set up a third party app, check out the FAQ.", destination: URL(string: "https://github.com/maxgoedjen/secretive/APP_CONFIG.md")!)
Picker(selection: $selectedShellInstruction, label: EmptyView()) { Picker(selection: $selectedShellInstruction, label: EmptyView()) {
ForEach(SSHAgentSetupView.controller.shellInstructions) { instruction in ForEach(SSHAgentSetupView.controller.shellInstructions) { instruction in
Text(instruction.shell) Text(instruction.shell)