diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift index 23d64ce..ac4ced2 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift @@ -4,7 +4,7 @@ import OSLog /// Manages storage and lookup for OpenSSH certificates. public actor OpenSSHCertificateHandler: Sendable { - private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: NSHomeDirectory()) + private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.homeDirectory) private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "OpenSSHCertificateHandler") private let writer = OpenSSHPublicKeyWriter() private var keyBlobsAndNames: [AnySecret: (Data, Data)] = [:] diff --git a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift index ada02d7..71bb426 100644 --- a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift +++ b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift @@ -5,12 +5,12 @@ import OSLog public final class PublicKeyFileStoreController: Sendable { private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "PublicKeyFileStoreController") - private let directory: String + private let directory: URL private let keyWriter = OpenSSHPublicKeyWriter() /// Initializes a PublicKeyFileStoreController. - public init(homeDirectory: String) { - directory = homeDirectory.appending("/PublicKeys") + public init(homeDirectory: URL) { + directory = homeDirectory.appending(component: "PublicKeys") } /// Writes out the keys specified to disk. @@ -20,7 +20,7 @@ public final class PublicKeyFileStoreController: Sendable { logger.log("Writing public keys to disk") if clear { let validPaths = Set(secrets.map { publicKeyPath(for: $0) }).union(Set(secrets.map { sshCertificatePath(for: $0) })) - let contentsOfDirectory = (try? FileManager.default.contentsOfDirectory(atPath: directory)) ?? [] + let contentsOfDirectory = (try? FileManager.default.contentsOfDirectory(atPath: directory.path())) ?? [] let fullPathContents = contentsOfDirectory.map { "\(directory)/\($0)" } let untracked = Set(fullPathContents) @@ -29,7 +29,7 @@ public final class PublicKeyFileStoreController: Sendable { 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: directory, withIntermediateDirectories: false, attributes: nil) for secret in secrets { let path = publicKeyPath(for: secret) let data = Data(keyWriter.openSSHString(secret: secret).utf8) @@ -44,14 +44,14 @@ public final class PublicKeyFileStoreController: Sendable { /// - 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(for secret: SecretType) -> String { let minimalHex = keyWriter.openSSHMD5Fingerprint(secret: secret).replacingOccurrences(of: ":", with: "") - return directory.appending("/").appending("\(minimalHex).pub") + return directory.appending(component: "\(minimalHex).pub").path() } /// Short-circuit check to ship enumerating a bunch of paths if there's nothing in the cert directory. public var hasAnyCertificates: Bool { do { return try FileManager.default - .contentsOfDirectory(atPath: directory) + .contentsOfDirectory(atPath: directory.path()) .filter { $0.hasSuffix("-cert.pub") } .isEmpty == false } catch { @@ -65,7 +65,7 @@ public final class PublicKeyFileStoreController: Sendable { /// - 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(for secret: SecretType) -> String { let minimalHex = keyWriter.openSSHMD5Fingerprint(secret: secret).replacingOccurrences(of: ":", with: "") - return directory.appending("/").appending("\(minimalHex)-cert.pub") + return directory.appending(component: "\(minimalHex)-cert.pub").path() } } diff --git a/Sources/SecretAgent/AppDelegate.swift b/Sources/SecretAgent/AppDelegate.swift index 5800c75..877145e 100644 --- a/Sources/SecretAgent/AppDelegate.swift +++ b/Sources/SecretAgent/AppDelegate.swift @@ -21,7 +21,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { }() private let updater = Updater(checkOnLaunch: true) private let notifier = Notifier() - private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: NSHomeDirectory()) + private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.homeDirectory) private lazy var agent: Agent = { Agent(storeList: storeList, witness: notifier) }() diff --git a/Sources/Secretive/Views/IntegrationsView.swift b/Sources/Secretive/Views/IntegrationsView.swift index 7e31674..e91c63b 100644 --- a/Sources/Secretive/Views/IntegrationsView.swift +++ b/Sources/Secretive/Views/IntegrationsView.swift @@ -71,20 +71,24 @@ struct IntegrationsView: View { case .gettingStarted: Text("TBD") case .tool: - Section(selectedInstruction.tool) { - ConfigurationItemView(title: "Configuration File", value: selectedInstruction.configPath, action: .revealInFinder( selectedInstruction.configPath)) - ConfigurationItemView(title: "Add This:", action: .copy(selectedInstruction.configText)) { - HStack { - Text(selectedInstruction.configText) - .padding(8) - .font(.system(.subheadline, design: .monospaced)) - Spacer() - } - .frame(maxWidth: .infinity) - .background { - RoundedRectangle(cornerRadius: 6) - .fill(.black.opacity(0.05)) - .stroke(.separator, lineWidth: 1) + ForEach(selectedInstruction.steps) { stepGroup in + Section { + ConfigurationItemView(title: "Configuration File", value: stepGroup.path, action: .revealInFinder(stepGroup.path)) + ForEach(stepGroup.steps, id: \.self) { step in + ConfigurationItemView(title: "Add This:", action: .copy(step)) { + HStack { + Text(step) + .padding(8) + .font(.system(.subheadline, design: .monospaced)) + Spacer() + } + .frame(maxWidth: .infinity) + .background { + RoundedRectangle(cornerRadius: 6) + .fill(.black.opacity(0.05)) + .stroke(.separator, lineWidth: 1) + } + } } } } @@ -140,27 +144,39 @@ struct ConfigurationGroup: Identifiable { var instructions: [ConfigurationFileInstructions] = [] } -struct ConfigurationFileInstructions: Identifiable, Hashable { +struct ConfigurationFileInstructions: Hashable, Identifiable { + + struct StepGroup: Hashable, Identifiable { + let path: String + let steps: [String] + var id: String { path } + } var id: ID var tool: String - var configPath: String - var configText: String + var steps: [StepGroup] var website: URL? + var note: String? - init(tool: String, configPath: String, configText: String, website: URL? = nil) { + init(tool: String, configPath: String, configText: String, website: URL? = nil, note: String? = nil) { self.id = .tool(tool) self.tool = tool - self.configPath = configPath - self.configText = configText + self.steps = [StepGroup(path: configPath, steps: [configText])] + self.website = website + self.note = note + } + + init(tool: String, steps: [StepGroup], website: URL? = nil, note: String? = nil) { + self.id = .tool(tool) + self.tool = tool + self.steps = steps self.website = website } init(_ name: LocalizedStringResource, id: ID) { self.id = id tool = String(localized: name) - configPath = "" - configText = "" + self.steps = [] } enum ID: Identifiable, Hashable { diff --git a/Sources/Secretive/Views/SecretDetailView.swift b/Sources/Secretive/Views/SecretDetailView.swift index 1e616f1..69b6d33 100644 --- a/Sources/Secretive/Views/SecretDetailView.swift +++ b/Sources/Secretive/Views/SecretDetailView.swift @@ -6,7 +6,7 @@ struct SecretDetailView: View { let secret: SecretType private let keyWriter = OpenSSHPublicKeyWriter() - private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.agentHomePath) + private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.agentHomeURL) var body: some View { ScrollView { @@ -39,8 +39,8 @@ struct SecretDetailView: View { extension URL { - static var agentHomePath: String { - URL.homeDirectory.path().replacingOccurrences(of: Bundle.hostBundleID, with: Bundle.agentBundleID) + static var agentHomeURL: URL { + URL(fileURLWithPath: URL.homeDirectory.path().replacingOccurrences(of: Bundle.hostBundleID, with: Bundle.agentBundleID)) } } diff --git a/Sources/Secretive/Views/SetupView.swift b/Sources/Secretive/Views/SetupView.swift index 6aefefc..eaa1652 100644 --- a/Sources/Secretive/Views/SetupView.swift +++ b/Sources/Secretive/Views/SetupView.swift @@ -141,7 +141,6 @@ extension SetupView { } - #Preview { SetupView(setupComplete: .constant(false)) }