mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-03-06 01:37:22 +01:00
New setup (#657)
* WIP * WIP * WIP * Tweaks. * WIP * WIP * WIP * WIP * WIP * Cleanup * WIP * WIP * WIP * WIP * WIP * WIP * WIP * REmove setup menu item * WIP * . * . * . * Cleaup.
This commit is contained in:
@@ -6,12 +6,14 @@ import Observation
|
||||
@MainActor protocol AgentStatusCheckerProtocol: Observable, Sendable {
|
||||
var running: Bool { get }
|
||||
var developmentBuild: Bool { get }
|
||||
var process: NSRunningApplication? { get }
|
||||
func check()
|
||||
}
|
||||
|
||||
@Observable @MainActor final class AgentStatusChecker: AgentStatusCheckerProtocol {
|
||||
|
||||
var running: Bool = false
|
||||
var process: NSRunningApplication? = nil
|
||||
|
||||
nonisolated init() {
|
||||
Task { @MainActor in
|
||||
@@ -20,32 +22,39 @@ import Observation
|
||||
}
|
||||
|
||||
func check() {
|
||||
running = instanceSecretAgentProcess != nil
|
||||
process = instanceSecretAgentProcess
|
||||
running = process != nil
|
||||
}
|
||||
|
||||
// All processes, including ones from older versions, etc
|
||||
var secretAgentProcesses: [NSRunningApplication] {
|
||||
NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.agentBundleID)
|
||||
var allSecretAgentProcesses: [NSRunningApplication] {
|
||||
NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.agentBundleID)
|
||||
}
|
||||
|
||||
// The process corresponding to this instance of Secretive
|
||||
var instanceSecretAgentProcess: NSRunningApplication? {
|
||||
let agents = secretAgentProcesses
|
||||
// FIXME: CHECK VERSION
|
||||
let agents = allSecretAgentProcesses
|
||||
for agent in agents {
|
||||
guard let url = agent.bundleURL else { continue }
|
||||
if url.absoluteString.hasPrefix(Bundle.main.bundleURL.absoluteString) {
|
||||
if url.absoluteString.hasPrefix(Bundle.main.bundleURL.absoluteString) || (url.isXcodeURL && developmentBuild) {
|
||||
return agent
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Whether Secretive is being run in an Xcode environment.
|
||||
var developmentBuild: Bool {
|
||||
Bundle.main.bundleURL.absoluteString.contains("/Library/Developer/Xcode")
|
||||
Bundle.main.bundleURL.isXcodeURL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension URL {
|
||||
|
||||
var isXcodeURL: Bool {
|
||||
absoluteString.contains("/Library/Developer/Xcode")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,16 +8,28 @@ struct LaunchAgentController {
|
||||
|
||||
private let logger = Logger(subsystem: "com.maxgoedjen.secretive", category: "LaunchAgentController")
|
||||
|
||||
func install() async {
|
||||
func install() async -> Bool {
|
||||
logger.debug("Installing agent")
|
||||
_ = setEnabled(false)
|
||||
// This is definitely a bit of a "seems to work better" thing but:
|
||||
// Seems to more reliably hit if these are on separate runloops, otherwise it seems like it sometimes doesn't kill old
|
||||
// and start new?
|
||||
try? await Task.sleep(for: .seconds(1))
|
||||
await MainActor.run {
|
||||
_ = setEnabled(true)
|
||||
let result = await MainActor.run {
|
||||
setEnabled(true)
|
||||
}
|
||||
try? await Task.sleep(for: .seconds(1))
|
||||
return result
|
||||
}
|
||||
|
||||
func uninstall() async -> Bool {
|
||||
logger.debug("Uninstalling agent")
|
||||
try? await Task.sleep(for: .seconds(1))
|
||||
let result = await MainActor.run {
|
||||
setEnabled(false)
|
||||
}
|
||||
try? await Task.sleep(for: .seconds(1))
|
||||
return result
|
||||
}
|
||||
|
||||
func forceLaunch() async -> Bool {
|
||||
@@ -28,6 +40,7 @@ struct LaunchAgentController {
|
||||
do {
|
||||
try await NSWorkspace.shared.openApplication(at: url, configuration: config)
|
||||
logger.debug("Agent force launched")
|
||||
try? await Task.sleep(for: .seconds(1))
|
||||
return true
|
||||
} catch {
|
||||
logger.error("Error force launching \(error.localizedDescription)")
|
||||
@@ -36,7 +49,7 @@ struct LaunchAgentController {
|
||||
}
|
||||
|
||||
private func setEnabled(_ enabled: Bool) -> Bool {
|
||||
let service = SMAppService.loginItem(identifier: Bundle.main.agentBundleID)
|
||||
let service = SMAppService.loginItem(identifier: Bundle.agentBundleID)
|
||||
do {
|
||||
if enabled {
|
||||
try service.register()
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import SecretKit
|
||||
|
||||
struct ShellConfigurationController {
|
||||
|
||||
let socketPath = (NSHomeDirectory().replacingOccurrences(of: Bundle.main.hostBundleID, with: Bundle.main.agentBundleID) as NSString).appendingPathComponent("socket.ssh") as String
|
||||
|
||||
var shellInstructions: [ShellConfigInstruction] {
|
||||
[
|
||||
ShellConfigInstruction(shell: "global",
|
||||
shellConfigDirectory: "~/.ssh/",
|
||||
shellConfigFilename: "config",
|
||||
text: "Host *\n\tIdentityAgent \(socketPath)"),
|
||||
ShellConfigInstruction(shell: "zsh",
|
||||
shellConfigDirectory: "~/",
|
||||
shellConfigFilename: ".zshrc",
|
||||
text: "export SSH_AUTH_SOCK=\(socketPath)"),
|
||||
ShellConfigInstruction(shell: "bash",
|
||||
shellConfigDirectory: "~/",
|
||||
shellConfigFilename: ".bashrc",
|
||||
text: "export SSH_AUTH_SOCK=\(socketPath)"),
|
||||
ShellConfigInstruction(shell: "fish",
|
||||
shellConfigDirectory: "~/.config/fish",
|
||||
shellConfigFilename: "config.fish",
|
||||
text: "set -x SSH_AUTH_SOCK \(socketPath)"),
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
|
||||
@MainActor func addToShell(shellInstructions: ShellConfigInstruction) -> Bool {
|
||||
let openPanel = NSOpenPanel()
|
||||
// This is sync, so no need to strongly retain
|
||||
let delegate = Delegate(name: shellInstructions.shellConfigFilename)
|
||||
openPanel.delegate = delegate
|
||||
openPanel.message = "Select \(shellInstructions.shellConfigFilename) to let Secretive configure your shell automatically."
|
||||
openPanel.prompt = "Add to \(shellInstructions.shellConfigFilename)"
|
||||
openPanel.canChooseFiles = true
|
||||
openPanel.canChooseDirectories = false
|
||||
openPanel.showsHiddenFiles = true
|
||||
openPanel.directoryURL = URL(fileURLWithPath: shellInstructions.shellConfigDirectory)
|
||||
openPanel.nameFieldStringValue = shellInstructions.shellConfigFilename
|
||||
openPanel.allowedContentTypes = [.symbolicLink, .data, .plainText]
|
||||
openPanel.runModal()
|
||||
guard let fileURL = openPanel.urls.first else { return false }
|
||||
let handle: FileHandle
|
||||
do {
|
||||
handle = try FileHandle(forUpdating: fileURL)
|
||||
guard let existing = try handle.readToEnd(),
|
||||
let existingString = String(data: existing, encoding: .utf8) else { return false }
|
||||
guard !existingString.contains(shellInstructions.text) else {
|
||||
return true
|
||||
}
|
||||
try handle.seekToEnd()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
handle.write(Data("\n# Secretive Config\n\(shellInstructions.text)\n".utf8))
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
12
Sources/Secretive/Controllers/URLs.swift
Normal file
12
Sources/Secretive/Controllers/URLs.swift
Normal file
@@ -0,0 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
extension URL {
|
||||
|
||||
static var agentHomeURL: URL {
|
||||
URL(fileURLWithPath: URL.homeDirectory.path().replacingOccurrences(of: Bundle.hostBundleID, with: Bundle.agentBundleID))
|
||||
}
|
||||
|
||||
static var socketPath: String {
|
||||
URL.agentHomeURL.appendingPathComponent("socket.ssh").path()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user