mirror of
				https://github.com/maxgoedjen/secretive.git
				synced 2025-11-03 17:00:56 +00:00 
			
		
		
		
	.
This commit is contained in:
		
							parent
							
								
									d80d2ca656
								
							
						
					
					
						commit
						df4661a718
					
				@ -45,6 +45,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, AgentProtocol {
 | 
			
		||||
            guard let update = update else { return }
 | 
			
		||||
            self.notifier.notify(update: update, ignore: self.updater.ignore(release:))
 | 
			
		||||
        }
 | 
			
		||||
        // TODO: REMOVE
 | 
			
		||||
        notifier.notify(update: Release(name: "Test", prerelease: false, html_url: URL(string: "https://example.com")!, body: ""), ignore: nil)
 | 
			
		||||
        connect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -55,6 +57,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, AgentProtocol {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func updatedStore(withID id: UUID) async throws {
 | 
			
		||||
        // TODO: REMOVE
 | 
			
		||||
        notifier.notify(update: Release(name: "UPDATESTORE", prerelease: false, html_url: URL(string: "https://example.com")!, body: ""), ignore: nil)
 | 
			
		||||
        logger.debug("Reloading keys for store with id: \(id)")
 | 
			
		||||
        guard let store = storeList.modifiableStore, store.id == id else { throw AgentProtocolStoreNotFoundError() }
 | 
			
		||||
        try store.reload()
 | 
			
		||||
@ -63,19 +67,20 @@ class AppDelegate: NSObject, NSApplicationDelegate, AgentProtocol {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    class ServiceDelegate: NSObject, NSXPCListenerDelegate {
 | 
			
		||||
// TODO: MOVE
 | 
			
		||||
class ServiceDelegate: NSObject, NSXPCListenerDelegate {
 | 
			
		||||
 | 
			
		||||
        let exported: AgentProtocol
 | 
			
		||||
 | 
			
		||||
        init(exportedObject: AgentProtocol) {
 | 
			
		||||
            self.exported = exportedObject
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
 | 
			
		||||
            newConnection.exportedInterface = NSXPCInterface(with: AgentProtocol.self)
 | 
			
		||||
            newConnection.exportedObject = exported
 | 
			
		||||
            newConnection.resume()
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
    let exported: AgentProtocol
 | 
			
		||||
 | 
			
		||||
    init(exportedObject: AgentProtocol) {
 | 
			
		||||
        self.exported = exportedObject
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
 | 
			
		||||
        newConnection.exportedInterface = NSXPCInterface(with: AgentProtocol.self)
 | 
			
		||||
        newConnection.exportedObject = exported
 | 
			
		||||
        newConnection.resume()
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,10 @@ struct Secretive: App {
 | 
			
		||||
                        // Two conditions in which we reinstall/attempt a force launch:
 | 
			
		||||
                        // 1: The app was just updated, and an old version of the agent is alive. Reinstall will deactivate this and activate a new one.
 | 
			
		||||
                        // 2: The agent is not running for some reason. We'll attempt to reinstall it, or relaunch directly if that fails.
 | 
			
		||||
                        reinstallAgent {
 | 
			
		||||
                        reinstallAgent(uninstallFirst: agentStatusChecker.running) {
 | 
			
		||||
                            if agentStatusChecker.noninstanceSecretAgentProcesses.isEmpty {
 | 
			
		||||
                                agentLaunchController.killNonInstanceAgents(agents: agentStatusChecker.noninstanceSecretAgentProcesses)
 | 
			
		||||
                            }
 | 
			
		||||
                            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 | 
			
		||||
                                agentCommunicationController.configure()
 | 
			
		||||
                            }
 | 
			
		||||
@ -72,7 +75,7 @@ struct Secretive: App {
 | 
			
		||||
            CommandGroup(after: .help) {
 | 
			
		||||
                Button("TEST") {
 | 
			
		||||
                    Task {
 | 
			
		||||
                        try await agentCommunicationController.agent.updatedStore(withID: storeList.modifiableStore?.id as? UUID ?? UUID())
 | 
			
		||||
                        try await agentCommunicationController.agent?.updatedStore(withID: storeList.modifiableStore?.id ?? UUID())
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -84,9 +87,9 @@ struct Secretive: App {
 | 
			
		||||
 | 
			
		||||
extension Secretive {
 | 
			
		||||
 | 
			
		||||
    private func reinstallAgent(completion: @escaping () -> Void) {
 | 
			
		||||
    private func reinstallAgent(uninstallFirst: Bool, completion: @escaping () -> Void) {
 | 
			
		||||
        justUpdatedChecker.check()
 | 
			
		||||
        agentLaunchController.install {
 | 
			
		||||
        agentLaunchController.install(uninstallFirst: uninstallFirst) {
 | 
			
		||||
            // Wait a second for launchd to kick in (next runloop isn't enough).
 | 
			
		||||
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 | 
			
		||||
                agentStatusChecker.check()
 | 
			
		||||
 | 
			
		||||
@ -1,34 +1,35 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
import Combine
 | 
			
		||||
import AppKit
 | 
			
		||||
import OSLog
 | 
			
		||||
import SecretKit
 | 
			
		||||
import SecretAgentKitProtocol
 | 
			
		||||
 | 
			
		||||
protocol AgentCommunicationControllerProtocol: ObservableObject {
 | 
			
		||||
    var agent: AgentProtocol { get }
 | 
			
		||||
    var agent: AgentProtocol? { get }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class AgentCommunicationController: ObservableObject, AgentCommunicationControllerProtocol {
 | 
			
		||||
 | 
			
		||||
    let agent: AgentProtocol
 | 
			
		||||
    private let connection: NSXPCConnection
 | 
			
		||||
    private(set) var agent: AgentProtocol? = nil
 | 
			
		||||
    private var connection: NSXPCConnection? = nil
 | 
			
		||||
    private var running = false
 | 
			
		||||
 | 
			
		||||
    init() {
 | 
			
		||||
        connection = NSXPCConnection(machServiceName: Bundle.main.agentBundleID)
 | 
			
		||||
        connection.remoteObjectInterface = NSXPCInterface(with: AgentProtocol.self)
 | 
			
		||||
        connection.invalidationHandler = {
 | 
			
		||||
            print("INVALID")
 | 
			
		||||
        }
 | 
			
		||||
        agent = connection.remoteObjectProxyWithErrorHandler({ x in
 | 
			
		||||
            print(x)
 | 
			
		||||
        }) as! AgentProtocol
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func configure() {
 | 
			
		||||
        guard !running else { return }
 | 
			
		||||
        connection = NSXPCConnection(machServiceName: Bundle.main.agentBundleID)
 | 
			
		||||
        connection?.remoteObjectInterface = NSXPCInterface(with: AgentProtocol.self)
 | 
			
		||||
        connection?.invalidationHandler = {
 | 
			
		||||
            Logger().warning("XPC connection invalidated")
 | 
			
		||||
        }
 | 
			
		||||
        connection?.resume()
 | 
			
		||||
        agent = connection?.remoteObjectProxyWithErrorHandler({ error in
 | 
			
		||||
            Logger().error("\(String(describing: error))")
 | 
			
		||||
        }) as! AgentProtocol
 | 
			
		||||
        running = true
 | 
			
		||||
        connection.resume()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,19 @@ import SecretKit
 | 
			
		||||
 | 
			
		||||
struct AgentLaunchController {
 | 
			
		||||
    
 | 
			
		||||
    func install(completion: (() -> Void)? = nil) {
 | 
			
		||||
    func install(uninstallFirst: Bool = true, completion: (() -> Void)? = nil) {
 | 
			
		||||
        Logger().debug("Installing agent")
 | 
			
		||||
        _ = setEnabled(false)
 | 
			
		||||
        if uninstallFirst {
 | 
			
		||||
            _ = 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?
 | 
			
		||||
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
 | 
			
		||||
            _  = setEnabled(true)
 | 
			
		||||
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 | 
			
		||||
            completion?()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
@ -36,6 +40,12 @@ struct AgentLaunchController {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func killNonInstanceAgents(agents: [NSRunningApplication]) {
 | 
			
		||||
        for agent in agents {
 | 
			
		||||
            agent.terminate()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func setEnabled(_ enabled: Bool) -> Bool {
 | 
			
		||||
        SMLoginItemSetEnabled(Bundle.main.agentBundleID as CFString, enabled)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -30,13 +30,18 @@ class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol {
 | 
			
		||||
        let agents = secretAgentProcesses
 | 
			
		||||
        for agent in agents {
 | 
			
		||||
            guard let url = agent.bundleURL else { continue }
 | 
			
		||||
            if url.absoluteString.hasPrefix(Bundle.main.bundleURL.absoluteString) {
 | 
			
		||||
            if url.absoluteString.contains(Bundle.main.bundleURL.absoluteString) {
 | 
			
		||||
                return agent
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return nil
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // All processes, _NOT_ including one the instance agent.
 | 
			
		||||
    var noninstanceSecretAgentProcesses: [NSRunningApplication] {
 | 
			
		||||
        NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.agentBundleID)
 | 
			
		||||
            .filter({ !($0.bundleURL?.absoluteString.contains(Bundle.main.bundleURL.absoluteString) ?? false) })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Whether Secretive is being run in an Xcode environment.
 | 
			
		||||
    var developmentBuild: Bool {
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,7 @@ struct CreateSecretView<StoreType: SecretStoreModifiable, AgentCommunicationCont
 | 
			
		||||
    func save() {
 | 
			
		||||
        try! store.create(name: name, requiresAuthentication: requiresAuthentication)
 | 
			
		||||
        Task {
 | 
			
		||||
            try! await agentCommunicationController.agent.updatedStore(withID: store.id)
 | 
			
		||||
            try! await agentCommunicationController.agent!.updatedStore(withID: store.id)
 | 
			
		||||
        }
 | 
			
		||||
        showing = false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user