diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 24563b8..0897120 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: - '*' jobs: test: - runs-on: macOS-latest + runs-on: macos-11.0 timeout-minutes: 10 steps: - uses: actions/checkout@v1 @@ -18,7 +18,7 @@ jobs: AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }} run: ./.github/scripts/signing.sh - 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 run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive build: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cdc8de4..dc4f0c1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,11 +3,11 @@ name: Test on: [push, pull_request] jobs: test: - runs-on: macOS-latest + runs-on: macos-11.0 timeout-minutes: 10 steps: - uses: actions/checkout@v2 - 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 run: xcrun xcodebuild test -project Secretive.xcodeproj -scheme Secretive diff --git a/APP_CONFIG.md b/APP_CONFIG.md new file mode 100644 index 0000000..eb85007 --- /dev/null +++ b/APP_CONFIG.md @@ -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. \ No newline at end of file diff --git a/FAQ.md b/FAQ.md index 04bb227..1974c0d 100644 --- a/FAQ.md +++ b/FAQ.md @@ -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. -### 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: - -Tower - [Instructions](https://www.git-tower.com/help/mac/integration/environment) - -GitHub Desktop: Should just work, no configuration needed +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). ### Secretive isn't working for me diff --git a/Icon.sketch b/Icon.sketch new file mode 100644 index 0000000..84e4a4b Binary files /dev/null and b/Icon.sketch differ diff --git a/SecretAgent/AppDelegate.swift b/SecretAgent/AppDelegate.swift index af21c2e..d54210c 100644 --- a/SecretAgent/AppDelegate.swift +++ b/SecretAgent/AppDelegate.swift @@ -26,7 +26,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { private var updateSink: AnyCancellable? func applicationDidFinishLaunching(_ aNotification: Notification) { - os_log(.debug, "SecretAgent finished launching") + Logger().debug("SecretAgent finished launching") DispatchQueue.main.async { self.socketController.handler = self.agent.handle(reader:writer:) } diff --git a/SecretAgentKit/Agent.swift b/SecretAgentKit/Agent.swift index 02727c3..b71b277 100644 --- a/SecretAgentKit/Agent.swift +++ b/SecretAgentKit/Agent.swift @@ -12,7 +12,7 @@ public class Agent { private let requestTracer = SigningRequestTracer() public init(storeList: SecretStoreList, witness: SigningWitness? = nil) { - os_log(.debug, "Agent is running") + Logger().debug("Agent is running") self.storeList = storeList self.witness = witness } @@ -22,16 +22,16 @@ public class Agent { extension Agent { public func handle(reader: FileHandleReader, writer: FileHandleWriter) { - os_log(.debug, "Agent handling new data") + Logger().debug("Agent handling new data") let data = reader.availableData guard !data.isEmpty else { return } let requestTypeInt = data[4] guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { 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 } - 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 response = handle(requestType: requestType, data: subData, reader: reader) writer.write(response) @@ -44,17 +44,17 @@ extension Agent { case .requestIdentities: response.append(SSHAgent.ResponseType.agentIdentitiesAnswer.data) response.append(identities()) - os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) + Logger().debug("Agent returned \(SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)") case .signRequest: let provenance = requestTracer.provenance(from: reader) response.append(SSHAgent.ResponseType.agentSignResponse.data) 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 { response.removeAll() 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) return full @@ -76,7 +76,7 @@ extension Agent { let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)! 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 } @@ -84,7 +84,7 @@ extension Agent { let reader = OpenSSHReader(data: data) let hash = reader.readNextChunk() 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 } @@ -137,7 +137,7 @@ extension Agent { try witness.witness(accessTo: secret, by: provenance) } - os_log(.debug, "Agent signed request") + Logger().debug("Agent signed request") return signedData } diff --git a/SecretAgentKit/SocketController.swift b/SecretAgentKit/SocketController.swift index f477bb9..0c916c3 100644 --- a/SecretAgentKit/SocketController.swift +++ b/SecretAgentKit/SocketController.swift @@ -8,16 +8,16 @@ public class SocketController { public var handler: ((FileHandleReader, FileHandleWriter) -> Void)? 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) { - os_log(.debug, "Socket controller removed existing socket") + Logger().debug("Socket controller removed existing socket") } let exists = FileManager.default.fileExists(atPath: path) assert(!exists) - os_log(.debug, "Socket controller path is clear") + Logger().debug("Socket controller path is clear") port = socketPort(at: path) configureSocket(at: path) - os_log(.debug, "Socket listening at %@", path) + Logger().debug("Socket listening at \(path)") } func configureSocket(at path: String) { @@ -50,7 +50,7 @@ public class SocketController { } @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 } handler?(new, new) new.waitForDataInBackgroundAndNotify() @@ -58,9 +58,9 @@ public class SocketController { } @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 } - os_log(.debug, "Socket controller received new file handle") + Logger().debug("Socket controller received new file handle") handler?(new, new) } diff --git a/Secretive.xcodeproj/project.pbxproj b/Secretive.xcodeproj/project.pbxproj index 21bb736..ef8acc9 100644 --- a/Secretive.xcodeproj/project.pbxproj +++ b/Secretive.xcodeproj/project.pbxproj @@ -1401,7 +1401,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1432,7 +1431,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1455,7 +1453,6 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1475,7 +1472,6 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1502,7 +1498,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1532,7 +1527,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1563,7 +1557,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Brief; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1719,7 +1712,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1743,7 +1735,6 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1770,7 +1761,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1794,7 +1784,6 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1880,7 +1869,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1911,7 +1899,6 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1934,7 +1921,6 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1954,7 +1940,6 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretAgentKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json b/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json index 71f386d..c14ca73 100644 --- a/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Secretive/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -31,13 +31,13 @@ "size" : "128x128" }, { - "filename" : "Icon 2@1x.png", + "filename" : "Mac Icon.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { - "filename" : "Icon 2@2x.png", + "filename" : "Mac Icon@0.25x.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" diff --git a/Secretive/Assets.xcassets/AppIcon.appiconset/Icon 2@1x.png b/Secretive/Assets.xcassets/AppIcon.appiconset/Icon 2@1x.png deleted file mode 100644 index c1f6cc1..0000000 Binary files a/Secretive/Assets.xcassets/AppIcon.appiconset/Icon 2@1x.png and /dev/null differ diff --git a/Secretive/Assets.xcassets/AppIcon.appiconset/Icon 2@2x.png b/Secretive/Assets.xcassets/AppIcon.appiconset/Icon 2@2x.png deleted file mode 100644 index b3b5339..0000000 Binary files a/Secretive/Assets.xcassets/AppIcon.appiconset/Icon 2@2x.png and /dev/null differ diff --git a/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon.png b/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon.png new file mode 100644 index 0000000..99a172b Binary files /dev/null and b/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon.png differ diff --git a/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png b/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png new file mode 100644 index 0000000..8b7b7ae Binary files /dev/null and b/Secretive/Assets.xcassets/AppIcon.appiconset/Mac Icon@0.25x.png differ diff --git a/Secretive/Views/CreateSecretView.swift b/Secretive/Views/CreateSecretView.swift index 68d512f..5753932 100644 --- a/Secretive/Views/CreateSecretView.swift +++ b/Secretive/Views/CreateSecretView.swift @@ -23,7 +23,7 @@ struct CreateSecretView: View { } HStack { Text("Name:") - TextField("Shhhhh", text: $name) + TextField("Shhhhh", text: $name).focusable() } HStack { Toggle(isOn: $requiresAuthentication) { diff --git a/Secretive/Views/SetupView.swift b/Secretive/Views/SetupView.swift index 8c9433d..b7c5267 100644 --- a/Secretive/Views/SetupView.swift +++ b/Secretive/Views/SetupView.swift @@ -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.", buttonTitle: "I Added it Manually", 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()) { ForEach(SSHAgentSetupView.controller.shellInstructions) { instruction in Text(instruction.shell)