mirror of
				https://github.com/maxgoedjen/secretive.git
				synced 2025-11-04 01:10:56 +00:00 
			
		
		
		
	XPC scaffolding
This commit is contained in:
		
							parent
							
								
									98bf285ad2
								
							
						
					
					
						commit
						d80d2ca656
					
				@ -24,6 +24,9 @@ let package = Package(
 | 
				
			|||||||
        .library(
 | 
					        .library(
 | 
				
			||||||
            name: "SecretAgentKitHeaders",
 | 
					            name: "SecretAgentKitHeaders",
 | 
				
			||||||
            targets: ["SecretAgentKitHeaders"]),
 | 
					            targets: ["SecretAgentKitHeaders"]),
 | 
				
			||||||
 | 
					        .library(
 | 
				
			||||||
 | 
					            name: "SecretAgentKitProtocol",
 | 
				
			||||||
 | 
					            targets: ["SecretAgentKitProtocol"]),
 | 
				
			||||||
        .library(
 | 
					        .library(
 | 
				
			||||||
            name: "Brief",
 | 
					            name: "Brief",
 | 
				
			||||||
            targets: ["Brief"]),
 | 
					            targets: ["Brief"]),
 | 
				
			||||||
@ -32,8 +35,7 @@ let package = Package(
 | 
				
			|||||||
    ],
 | 
					    ],
 | 
				
			||||||
    targets: [
 | 
					    targets: [
 | 
				
			||||||
        .target(
 | 
					        .target(
 | 
				
			||||||
            name: "SecretKit",
 | 
					            name: "SecretKit"
 | 
				
			||||||
            dependencies: []
 | 
					 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        .testTarget(
 | 
					        .testTarget(
 | 
				
			||||||
            name: "SecretKitTests",
 | 
					            name: "SecretKitTests",
 | 
				
			||||||
@ -49,18 +51,20 @@ let package = Package(
 | 
				
			|||||||
        ),
 | 
					        ),
 | 
				
			||||||
        .target(
 | 
					        .target(
 | 
				
			||||||
            name: "SecretAgentKit",
 | 
					            name: "SecretAgentKit",
 | 
				
			||||||
            dependencies: ["SecretKit", "SecretAgentKitHeaders"]
 | 
					            dependencies: ["SecretKit", "SecretAgentKitHeaders", "SecretAgentKitProtocol"]
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        .systemLibrary(
 | 
					        .systemLibrary(
 | 
				
			||||||
            name: "SecretAgentKitHeaders"
 | 
					            name: "SecretAgentKitHeaders"
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					        .target(
 | 
				
			||||||
 | 
					            name: "SecretAgentKitProtocol"
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
        .testTarget(
 | 
					        .testTarget(
 | 
				
			||||||
            name: "SecretAgentKitTests",
 | 
					            name: "SecretAgentKitTests",
 | 
				
			||||||
            dependencies: ["SecretAgentKit"])
 | 
					            dependencies: ["SecretAgentKit"])
 | 
				
			||||||
        ,
 | 
					        ,
 | 
				
			||||||
        .target(
 | 
					        .target(
 | 
				
			||||||
            name: "Brief",
 | 
					            name: "Brief"
 | 
				
			||||||
            dependencies: []
 | 
					 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        .testTarget(
 | 
					        .testTarget(
 | 
				
			||||||
            name: "BriefTests",
 | 
					            name: "BriefTests",
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@objc public protocol AgentProtocol {
 | 
				
			||||||
 | 
					    func updatedStore(withID: UUID) async throws
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct AgentProtocolStoreNotFoundError: Error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public init() {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -58,11 +58,13 @@ public class AnySecretStoreModifiable: AnySecretStore, SecretStoreModifiable {
 | 
				
			|||||||
    private let _create: (String, Bool) throws -> Void
 | 
					    private let _create: (String, Bool) throws -> Void
 | 
				
			||||||
    private let _delete: (AnySecret) throws -> Void
 | 
					    private let _delete: (AnySecret) throws -> Void
 | 
				
			||||||
    private let _update: (AnySecret, String) throws -> Void
 | 
					    private let _update: (AnySecret, String) throws -> Void
 | 
				
			||||||
 | 
					    private let _reload: () throws -> Void
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public init<SecretStoreType>(modifiable secretStore: SecretStoreType) where SecretStoreType: SecretStoreModifiable {
 | 
					    public init<SecretStoreType>(modifiable secretStore: SecretStoreType) where SecretStoreType: SecretStoreModifiable {
 | 
				
			||||||
        _create = { try secretStore.create(name: $0, requiresAuthentication: $1) }
 | 
					        _create = { try secretStore.create(name: $0, requiresAuthentication: $1) }
 | 
				
			||||||
        _delete = { try secretStore.delete(secret: $0.base as! SecretStoreType.SecretType) }
 | 
					        _delete = { try secretStore.delete(secret: $0.base as! SecretStoreType.SecretType) }
 | 
				
			||||||
        _update = { try secretStore.update(secret: $0.base as! SecretStoreType.SecretType, name: $1) }
 | 
					        _update = { try secretStore.update(secret: $0.base as! SecretStoreType.SecretType, name: $1) }
 | 
				
			||||||
 | 
					        _reload = { try secretStore.reload() }
 | 
				
			||||||
        super.init(secretStore)
 | 
					        super.init(secretStore)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -78,4 +80,8 @@ public class AnySecretStoreModifiable: AnySecretStore, SecretStoreModifiable {
 | 
				
			|||||||
        try _update(secret, name)
 | 
					        try _update(secret, name)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public func reload() throws {
 | 
				
			||||||
 | 
					        try _reload()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,9 @@ public protocol SecretStoreModifiable: SecretStore {
 | 
				
			|||||||
    ///   - name: The new name for the Secret.
 | 
					    ///   - name: The new name for the Secret.
 | 
				
			||||||
    func update(secret: SecretType, name: String) throws
 | 
					    func update(secret: SecretType, name: String) throws
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Reloads the secrets from the backing store.
 | 
				
			||||||
 | 
					    func reload() throws
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extension NSNotification.Name {
 | 
					extension NSNotification.Name {
 | 
				
			||||||
 | 
				
			|||||||
@ -23,9 +23,6 @@ extension SecureEnclave {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /// Initializes a Store.
 | 
					        /// Initializes a Store.
 | 
				
			||||||
        public init() {
 | 
					        public init() {
 | 
				
			||||||
            DistributedNotificationCenter.default().addObserver(forName: .secretStoreUpdated, object: nil, queue: .main) { _ in
 | 
					 | 
				
			||||||
                self.reloadSecrets(notify: false)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            loadSecrets()
 | 
					            loadSecrets()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,7 +65,7 @@ extension SecureEnclave {
 | 
				
			|||||||
                throw KeychainError(statusCode: nil)
 | 
					                throw KeychainError(statusCode: nil)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            try savePublicKey(publicKey, name: name)
 | 
					            try savePublicKey(publicKey, name: name)
 | 
				
			||||||
            reloadSecrets()
 | 
					            reload()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public func delete(secret: Secret) throws {
 | 
					        public func delete(secret: Secret) throws {
 | 
				
			||||||
@ -80,7 +77,7 @@ extension SecureEnclave {
 | 
				
			|||||||
            if status != errSecSuccess {
 | 
					            if status != errSecSuccess {
 | 
				
			||||||
                throw KeychainError(statusCode: status)
 | 
					                throw KeychainError(statusCode: status)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            reloadSecrets()
 | 
					            reload()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public func update(secret: Secret, name: String) throws {
 | 
					        public func update(secret: Secret, name: String) throws {
 | 
				
			||||||
@ -97,7 +94,12 @@ extension SecureEnclave {
 | 
				
			|||||||
            if status != errSecSuccess {
 | 
					            if status != errSecSuccess {
 | 
				
			||||||
                throw KeychainError(statusCode: status)
 | 
					                throw KeychainError(statusCode: status)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            reloadSecrets()
 | 
					            reload()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public func reload() {
 | 
				
			||||||
 | 
					            secrets.removeAll()
 | 
				
			||||||
 | 
					            loadSecrets()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> SignedData {
 | 
					        public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> SignedData {
 | 
				
			||||||
@ -170,16 +172,6 @@ extension SecureEnclave {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extension SecureEnclave.Store {
 | 
					extension SecureEnclave.Store {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Reloads all secrets from the store.
 | 
					 | 
				
			||||||
    /// - Parameter notify: A boolean indicating whether a distributed notification should be posted, notifying other processes (ie, the SecretAgent) to reload their stores as well.
 | 
					 | 
				
			||||||
    private func reloadSecrets(notify: Bool = true) {
 | 
					 | 
				
			||||||
        secrets.removeAll()
 | 
					 | 
				
			||||||
        loadSecrets()
 | 
					 | 
				
			||||||
        if notify {
 | 
					 | 
				
			||||||
            DistributedNotificationCenter.default().post(name: .secretStoreUpdated, object: nil)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Loads all secrets from the store.
 | 
					    /// Loads all secrets from the store.
 | 
				
			||||||
    private func loadSecrets() {
 | 
					    private func loadSecrets() {
 | 
				
			||||||
        let attributes = [
 | 
					        let attributes = [
 | 
				
			||||||
 | 
				
			|||||||
@ -7,8 +7,11 @@ import SmartCardSecretKit
 | 
				
			|||||||
import SecretAgentKit
 | 
					import SecretAgentKit
 | 
				
			||||||
import Brief
 | 
					import Brief
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import SecretKit
 | 
				
			||||||
 | 
					import SecretAgentKitProtocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NSApplicationMain
 | 
					@NSApplicationMain
 | 
				
			||||||
class AppDelegate: NSObject, NSApplicationDelegate {
 | 
					class AppDelegate: NSObject, NSApplicationDelegate, AgentProtocol {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private let storeList: SecretStoreList = {
 | 
					    private let storeList: SecretStoreList = {
 | 
				
			||||||
        let list = SecretStoreList()
 | 
					        let list = SecretStoreList()
 | 
				
			||||||
@ -27,9 +30,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
 | 
				
			|||||||
        return SocketController(path: path)
 | 
					        return SocketController(path: path)
 | 
				
			||||||
    }()
 | 
					    }()
 | 
				
			||||||
    private var updateSink: AnyCancellable?
 | 
					    private var updateSink: AnyCancellable?
 | 
				
			||||||
 | 
					    private let logger = Logger()
 | 
				
			||||||
 | 
					    var delegate: ServiceDelegate? = nil
 | 
				
			||||||
 | 
					    let listener = NSXPCListener(machServiceName: Bundle.main.bundleIdentifier!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func applicationDidFinishLaunching(_ aNotification: Notification) {
 | 
					    func applicationDidFinishLaunching(_ aNotification: Notification) {
 | 
				
			||||||
        Logger().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:)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -39,13 +45,37 @@ class AppDelegate: NSObject, NSApplicationDelegate {
 | 
				
			|||||||
            guard let update = update else { return }
 | 
					            guard let update = update else { return }
 | 
				
			||||||
            self.notifier.notify(update: update, ignore: self.updater.ignore(release:))
 | 
					            self.notifier.notify(update: update, ignore: self.updater.ignore(release:))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        connect()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func reloadKeys() {
 | 
					    func connect() {
 | 
				
			||||||
        // TODO: This
 | 
					        delegate = ServiceDelegate(exportedObject: self)
 | 
				
			||||||
//        storeList.reloadAll()
 | 
					        listener.delegate = delegate
 | 
				
			||||||
        try? publicKeyFileStoreController.generatePublicKeys(for: storeList.stores.flatMap({ $0.secrets }), clear: true)
 | 
					        listener.resume()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func updatedStore(withID id: UUID) async throws {
 | 
				
			||||||
 | 
					        logger.debug("Reloading keys for store with id: \(id)")
 | 
				
			||||||
 | 
					        guard let store = storeList.modifiableStore, store.id == id else { throw AgentProtocolStoreNotFoundError() }
 | 
				
			||||||
 | 
					        try store.reload()
 | 
				
			||||||
 | 
					        try publicKeyFileStoreController.generatePublicKeys(for: storeList.stores.flatMap({ $0.secrets }), clear: true)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,10 @@
 | 
				
			|||||||
<dict>
 | 
					<dict>
 | 
				
			||||||
	<key>com.apple.security.app-sandbox</key>
 | 
						<key>com.apple.security.app-sandbox</key>
 | 
				
			||||||
	<true/>
 | 
						<true/>
 | 
				
			||||||
 | 
						<key>com.apple.security.application-groups</key>
 | 
				
			||||||
 | 
						<array>
 | 
				
			||||||
 | 
							<string>$(TeamIdentifierPrefix)com.maxgoedjen.secretive</string>
 | 
				
			||||||
 | 
						</array>
 | 
				
			||||||
	<key>com.apple.security.network.client</key>
 | 
						<key>com.apple.security.network.client</key>
 | 
				
			||||||
	<true/>
 | 
						<true/>
 | 
				
			||||||
	<key>com.apple.security.smartcard</key>
 | 
						<key>com.apple.security.smartcard</key>
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@
 | 
				
			|||||||
		50153E22250DECA300525160 /* SecretListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E21250DECA300525160 /* SecretListItemView.swift */; };
 | 
							50153E22250DECA300525160 /* SecretListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E21250DECA300525160 /* SecretListItemView.swift */; };
 | 
				
			||||||
		5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
 | 
							5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
 | 
				
			||||||
		50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; };
 | 
							50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; };
 | 
				
			||||||
		50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; };
 | 
							50571E0524393D1500F76F6C /* AgentLaunchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* AgentLaunchController.swift */; };
 | 
				
			||||||
		50617D8323FCE48E0099B055 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* App.swift */; };
 | 
							50617D8323FCE48E0099B055 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* App.swift */; };
 | 
				
			||||||
		50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; };
 | 
							50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; };
 | 
				
			||||||
		50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
 | 
							50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
 | 
				
			||||||
@ -36,6 +36,8 @@
 | 
				
			|||||||
		5066A6F7251829B1004B5A36 /* ShellConfigurationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5066A6F6251829B1004B5A36 /* ShellConfigurationController.swift */; };
 | 
							5066A6F7251829B1004B5A36 /* ShellConfigurationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5066A6F6251829B1004B5A36 /* ShellConfigurationController.swift */; };
 | 
				
			||||||
		506772C72424784600034DED /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 506772C62424784600034DED /* Credits.rtf */; };
 | 
							506772C72424784600034DED /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 506772C62424784600034DED /* Credits.rtf */; };
 | 
				
			||||||
		506772C92425BB8500034DED /* NoStoresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506772C82425BB8500034DED /* NoStoresView.swift */; };
 | 
							506772C92425BB8500034DED /* NoStoresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506772C82425BB8500034DED /* NoStoresView.swift */; };
 | 
				
			||||||
 | 
							50736F652782C05000A723B6 /* AgentCommunicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50736F642782C05000A723B6 /* AgentCommunicationController.swift */; };
 | 
				
			||||||
 | 
							50736F672782C31800A723B6 /* SecretAgentKitProtocol in Frameworks */ = {isa = PBXBuildFile; productRef = 50736F662782C31800A723B6 /* SecretAgentKitProtocol */; };
 | 
				
			||||||
		5079BA0F250F29BF00EA86F4 /* StoreListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5079BA0E250F29BF00EA86F4 /* StoreListView.swift */; };
 | 
							5079BA0F250F29BF00EA86F4 /* StoreListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5079BA0E250F29BF00EA86F4 /* StoreListView.swift */; };
 | 
				
			||||||
		508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
 | 
							508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
 | 
				
			||||||
		508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
 | 
							508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
 | 
				
			||||||
@ -111,7 +113,7 @@
 | 
				
			|||||||
		50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
 | 
							50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
 | 
							5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = "<group>"; };
 | 
							50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		50571E0424393D1500F76F6C /* LaunchAgentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAgentController.swift; sourceTree = "<group>"; };
 | 
							50571E0424393D1500F76F6C /* AgentLaunchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentLaunchController.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
							50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
				
			||||||
		50617D8223FCE48E0099B055 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
 | 
							50617D8223FCE48E0099B055 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
 | 
							50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
 | 
				
			||||||
@ -128,6 +130,7 @@
 | 
				
			|||||||
		5066A6F6251829B1004B5A36 /* ShellConfigurationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellConfigurationController.swift; sourceTree = "<group>"; };
 | 
							5066A6F6251829B1004B5A36 /* ShellConfigurationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellConfigurationController.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		506772C62424784600034DED /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
 | 
							506772C62424784600034DED /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
 | 
				
			||||||
		506772C82425BB8500034DED /* NoStoresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStoresView.swift; sourceTree = "<group>"; };
 | 
							506772C82425BB8500034DED /* NoStoresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStoresView.swift; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							50736F642782C05000A723B6 /* AgentCommunicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentCommunicationController.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		5079BA0E250F29BF00EA86F4 /* StoreListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreListView.swift; sourceTree = "<group>"; };
 | 
							5079BA0E250F29BF00EA86F4 /* StoreListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreListView.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
 | 
							508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
 | 
							508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
 | 
				
			||||||
@ -155,6 +158,7 @@
 | 
				
			|||||||
			buildActionMask = 2147483647;
 | 
								buildActionMask = 2147483647;
 | 
				
			||||||
			files = (
 | 
								files = (
 | 
				
			||||||
				5003EF3B278005E800DF2006 /* SecretKit in Frameworks */,
 | 
									5003EF3B278005E800DF2006 /* SecretKit in Frameworks */,
 | 
				
			||||||
 | 
									50736F672782C31800A723B6 /* SecretAgentKitProtocol in Frameworks */,
 | 
				
			||||||
				501421622781262300BBAA70 /* Brief in Frameworks */,
 | 
									501421622781262300BBAA70 /* Brief in Frameworks */,
 | 
				
			||||||
				5003EF5F2780081600DF2006 /* SecureEnclaveSecretKit in Frameworks */,
 | 
									5003EF5F2780081600DF2006 /* SecureEnclaveSecretKit in Frameworks */,
 | 
				
			||||||
				5003EF612780081600DF2006 /* SmartCardSecretKit in Frameworks */,
 | 
									5003EF612780081600DF2006 /* SmartCardSecretKit in Frameworks */,
 | 
				
			||||||
@ -283,9 +287,10 @@
 | 
				
			|||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
				508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
 | 
									508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
 | 
				
			||||||
 | 
									50736F642782C05000A723B6 /* AgentCommunicationController.swift */,
 | 
				
			||||||
				5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */,
 | 
									5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */,
 | 
				
			||||||
				50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */,
 | 
									50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */,
 | 
				
			||||||
				50571E0424393D1500F76F6C /* LaunchAgentController.swift */,
 | 
									50571E0424393D1500F76F6C /* AgentLaunchController.swift */,
 | 
				
			||||||
				5066A6F6251829B1004B5A36 /* ShellConfigurationController.swift */,
 | 
									5066A6F6251829B1004B5A36 /* ShellConfigurationController.swift */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			path = Controllers;
 | 
								path = Controllers;
 | 
				
			||||||
@ -345,6 +350,7 @@
 | 
				
			|||||||
				5003EF5E2780081600DF2006 /* SecureEnclaveSecretKit */,
 | 
									5003EF5E2780081600DF2006 /* SecureEnclaveSecretKit */,
 | 
				
			||||||
				5003EF602780081600DF2006 /* SmartCardSecretKit */,
 | 
									5003EF602780081600DF2006 /* SmartCardSecretKit */,
 | 
				
			||||||
				501421612781262300BBAA70 /* Brief */,
 | 
									501421612781262300BBAA70 /* Brief */,
 | 
				
			||||||
 | 
									50736F662782C31800A723B6 /* SecretAgentKitProtocol */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			productName = Secretive;
 | 
								productName = Secretive;
 | 
				
			||||||
			productReference = 50617D7F23FCE48E0099B055 /* Secretive.app */;
 | 
								productReference = 50617D7F23FCE48E0099B055 /* Secretive.app */;
 | 
				
			||||||
@ -485,8 +491,9 @@
 | 
				
			|||||||
				50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
 | 
									50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
 | 
				
			||||||
				5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
 | 
									5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
 | 
				
			||||||
				50153E20250AFCB200525160 /* UpdateView.swift in Sources */,
 | 
									50153E20250AFCB200525160 /* UpdateView.swift in Sources */,
 | 
				
			||||||
				50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */,
 | 
									50571E0524393D1500F76F6C /* AgentLaunchController.swift in Sources */,
 | 
				
			||||||
				5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */,
 | 
									5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */,
 | 
				
			||||||
 | 
									50736F652782C05000A723B6 /* AgentCommunicationController.swift in Sources */,
 | 
				
			||||||
				50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */,
 | 
									50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */,
 | 
				
			||||||
				50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */,
 | 
									50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */,
 | 
				
			||||||
				50617D8323FCE48E0099B055 /* App.swift in Sources */,
 | 
									50617D8323FCE48E0099B055 /* App.swift in Sources */,
 | 
				
			||||||
@ -830,6 +837,7 @@
 | 
				
			|||||||
			buildSettings = {
 | 
								buildSettings = {
 | 
				
			||||||
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 | 
									ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 | 
				
			||||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
									ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
				
			||||||
 | 
									CODE_SIGN_ENTITLEMENTS = Secretive/Secretive.entitlements;
 | 
				
			||||||
				CODE_SIGN_STYLE = Manual;
 | 
									CODE_SIGN_STYLE = Manual;
 | 
				
			||||||
				COMBINE_HIDPI_IMAGES = YES;
 | 
									COMBINE_HIDPI_IMAGES = YES;
 | 
				
			||||||
				CURRENT_PROJECT_VERSION = 1;
 | 
									CURRENT_PROJECT_VERSION = 1;
 | 
				
			||||||
@ -874,6 +882,7 @@
 | 
				
			|||||||
			isa = XCBuildConfiguration;
 | 
								isa = XCBuildConfiguration;
 | 
				
			||||||
			buildSettings = {
 | 
								buildSettings = {
 | 
				
			||||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
									ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
				
			||||||
 | 
									CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements;
 | 
				
			||||||
				CODE_SIGN_STYLE = Manual;
 | 
									CODE_SIGN_STYLE = Manual;
 | 
				
			||||||
				COMBINE_HIDPI_IMAGES = YES;
 | 
									COMBINE_HIDPI_IMAGES = YES;
 | 
				
			||||||
				DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
 | 
									DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\"";
 | 
				
			||||||
@ -885,7 +894,7 @@
 | 
				
			|||||||
					"@executable_path/../Frameworks",
 | 
										"@executable_path/../Frameworks",
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
				MARKETING_VERSION = 1;
 | 
									MARKETING_VERSION = 1;
 | 
				
			||||||
				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
 | 
									PRODUCT_BUNDLE_IDENTIFIER = Z72PRUAWF6.com.maxgoedjen.Secretive.SecretAgent;
 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
									PRODUCT_NAME = "$(TARGET_NAME)";
 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
									SWIFT_VERSION = 5.0;
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
@ -908,7 +917,7 @@
 | 
				
			|||||||
					"@executable_path/../Frameworks",
 | 
										"@executable_path/../Frameworks",
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
				MARKETING_VERSION = 1;
 | 
									MARKETING_VERSION = 1;
 | 
				
			||||||
				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
 | 
									PRODUCT_BUNDLE_IDENTIFIER = Z72PRUAWF6.com.maxgoedjen.Secretive.SecretAgent;
 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
									PRODUCT_NAME = "$(TARGET_NAME)";
 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
									SWIFT_VERSION = 5.0;
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
@ -932,7 +941,7 @@
 | 
				
			|||||||
					"@executable_path/../Frameworks",
 | 
										"@executable_path/../Frameworks",
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
				MARKETING_VERSION = 1;
 | 
									MARKETING_VERSION = 1;
 | 
				
			||||||
				PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
 | 
									PRODUCT_BUNDLE_IDENTIFIER = Z72PRUAWF6.com.maxgoedjen.Secretive.SecretAgent;
 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
									PRODUCT_NAME = "$(TARGET_NAME)";
 | 
				
			||||||
				PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
 | 
									PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
									SWIFT_VERSION = 5.0;
 | 
				
			||||||
@ -1021,6 +1030,10 @@
 | 
				
			|||||||
			isa = XCSwiftPackageProductDependency;
 | 
								isa = XCSwiftPackageProductDependency;
 | 
				
			||||||
			productName = Brief;
 | 
								productName = Brief;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
							50736F662782C31800A723B6 /* SecretAgentKitProtocol */ = {
 | 
				
			||||||
 | 
								isa = XCSwiftPackageProductDependency;
 | 
				
			||||||
 | 
								productName = SecretAgentKitProtocol;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
/* End XCSwiftPackageProductDependency section */
 | 
					/* End XCSwiftPackageProductDependency section */
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	rootObject = 50617D7723FCE48D0099B055 /* Project object */;
 | 
						rootObject = 50617D7723FCE48D0099B055 /* Project object */;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,8 @@ struct Secretive: App {
 | 
				
			|||||||
        return list
 | 
					        return list
 | 
				
			||||||
    }()
 | 
					    }()
 | 
				
			||||||
    private let agentStatusChecker = AgentStatusChecker()
 | 
					    private let agentStatusChecker = AgentStatusChecker()
 | 
				
			||||||
 | 
					    private let agentLaunchController = AgentLaunchController()
 | 
				
			||||||
 | 
					    private let agentCommunicationController = AgentCommunicationController()
 | 
				
			||||||
    private let justUpdatedChecker = JustUpdatedChecker()
 | 
					    private let justUpdatedChecker = JustUpdatedChecker()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @AppStorage("defaultsHasRunSetup") var hasRunSetup = false
 | 
					    @AppStorage("defaultsHasRunSetup") var hasRunSetup = false
 | 
				
			||||||
@ -27,6 +29,7 @@ struct Secretive: App {
 | 
				
			|||||||
                .environmentObject(storeList)
 | 
					                .environmentObject(storeList)
 | 
				
			||||||
                .environmentObject(Updater(checkOnLaunch: hasRunSetup))
 | 
					                .environmentObject(Updater(checkOnLaunch: hasRunSetup))
 | 
				
			||||||
                .environmentObject(agentStatusChecker)
 | 
					                .environmentObject(agentStatusChecker)
 | 
				
			||||||
 | 
					                .environmentObject(agentCommunicationController)
 | 
				
			||||||
                .onAppear {
 | 
					                .onAppear {
 | 
				
			||||||
                    if !hasRunSetup {
 | 
					                    if !hasRunSetup {
 | 
				
			||||||
                        showingSetup = true
 | 
					                        showingSetup = true
 | 
				
			||||||
@ -35,11 +38,17 @@ struct Secretive: App {
 | 
				
			|||||||
                .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in
 | 
					                .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in
 | 
				
			||||||
                    guard hasRunSetup else { return }
 | 
					                    guard hasRunSetup else { return }
 | 
				
			||||||
                    agentStatusChecker.check()
 | 
					                    agentStatusChecker.check()
 | 
				
			||||||
                    if agentStatusChecker.running && justUpdatedChecker.justUpdated {
 | 
					                    if justUpdatedChecker.justUpdated || !agentStatusChecker.running {
 | 
				
			||||||
                        // Relaunch the agent, since it'll be running from earlier update still
 | 
					                        // Two conditions in which we reinstall/attempt a force launch:
 | 
				
			||||||
                        reinstallAgent()
 | 
					                        // 1: The app was just updated, and an old version of the agent is alive. Reinstall will deactivate this and activate a new one.
 | 
				
			||||||
                    } else if !agentStatusChecker.running && !agentStatusChecker.developmentBuild {
 | 
					                        // 2: The agent is not running for some reason. We'll attempt to reinstall it, or relaunch directly if that fails.
 | 
				
			||||||
                        forceLaunchAgent()
 | 
					                        reinstallAgent {
 | 
				
			||||||
 | 
					                            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 | 
				
			||||||
 | 
					                                agentCommunicationController.configure()
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        agentCommunicationController.configure()
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -60,6 +69,13 @@ struct Secretive: App {
 | 
				
			|||||||
                    showingSetup = true
 | 
					                    showingSetup = true
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            CommandGroup(after: .help) {
 | 
				
			||||||
 | 
					                Button("TEST") {
 | 
				
			||||||
 | 
					                    Task {
 | 
				
			||||||
 | 
					                        try await agentCommunicationController.agent.updatedStore(withID: storeList.modifiableStore?.id as? UUID ?? UUID())
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            SidebarCommands()
 | 
					            SidebarCommands()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -68,27 +84,24 @@ struct Secretive: App {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extension Secretive {
 | 
					extension Secretive {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private func reinstallAgent() {
 | 
					    private func reinstallAgent(completion: @escaping () -> Void) {
 | 
				
			||||||
        justUpdatedChecker.check()
 | 
					        justUpdatedChecker.check()
 | 
				
			||||||
        LaunchAgentController().install {
 | 
					        agentLaunchController.install {
 | 
				
			||||||
            // Wait a second for launchd to kick in (next runloop isn't enough).
 | 
					            // Wait a second for launchd to kick in (next runloop isn't enough).
 | 
				
			||||||
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 | 
					            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 | 
				
			||||||
                agentStatusChecker.check()
 | 
					                agentStatusChecker.check()
 | 
				
			||||||
                if !agentStatusChecker.running {
 | 
					                if !agentStatusChecker.running {
 | 
				
			||||||
                    forceLaunchAgent()
 | 
					                    agentLaunchController.forceLaunch { _ in
 | 
				
			||||||
 | 
					                        agentStatusChecker.check()
 | 
				
			||||||
 | 
					                        completion()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    completion()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private func forceLaunchAgent() {
 | 
					 | 
				
			||||||
        // We've run setup, we didn't just update, launchd is just not doing it's thing.
 | 
					 | 
				
			||||||
        // Force a launch directly.
 | 
					 | 
				
			||||||
        LaunchAgentController().forceLaunch { _ in
 | 
					 | 
				
			||||||
            agentStatusChecker.check()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					import Combine
 | 
				
			||||||
 | 
					import AppKit
 | 
				
			||||||
 | 
					import SecretKit
 | 
				
			||||||
 | 
					import SecretAgentKitProtocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protocol AgentCommunicationControllerProtocol: ObservableObject {
 | 
				
			||||||
 | 
					    var agent: AgentProtocol { get }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AgentCommunicationController: ObservableObject, AgentCommunicationControllerProtocol {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let agent: AgentProtocol
 | 
				
			||||||
 | 
					    private let connection: NSXPCConnection
 | 
				
			||||||
 | 
					    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 }
 | 
				
			||||||
 | 
					        running = true
 | 
				
			||||||
 | 
					        connection.resume()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -4,7 +4,7 @@ import AppKit
 | 
				
			|||||||
import OSLog
 | 
					import OSLog
 | 
				
			||||||
import SecretKit
 | 
					import SecretKit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct LaunchAgentController {
 | 
					struct AgentLaunchController {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    func install(completion: (() -> Void)? = nil) {
 | 
					    func install(completion: (() -> Void)? = nil) {
 | 
				
			||||||
        Logger().debug("Installing agent")
 | 
					        Logger().debug("Installing agent")
 | 
				
			||||||
@ -20,7 +20,7 @@ struct LaunchAgentController {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func forceLaunch(completion: ((Bool) -> Void)?) {
 | 
					    func forceLaunch(completion: ((Bool) -> Void)?) {
 | 
				
			||||||
        Logger().debug("Agent is not running, attempting to force launch")
 | 
					        Logger().debug("Agent is still not running, attempting to force launch")
 | 
				
			||||||
        let url = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app")
 | 
					        let url = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app")
 | 
				
			||||||
        let config = NSWorkspace.OpenConfiguration()
 | 
					        let config = NSWorkspace.OpenConfiguration()
 | 
				
			||||||
        config.activates = false
 | 
					        config.activates = false
 | 
				
			||||||
@ -9,6 +9,7 @@ protocol JustUpdatedCheckerProtocol: ObservableObject {
 | 
				
			|||||||
class JustUpdatedChecker: ObservableObject, JustUpdatedCheckerProtocol {
 | 
					class JustUpdatedChecker: ObservableObject, JustUpdatedCheckerProtocol {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Published var justUpdated: Bool = false
 | 
					    @Published var justUpdated: Bool = false
 | 
				
			||||||
 | 
					    var alreadyRelaunchedForDebug = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init() {
 | 
					    init() {
 | 
				
			||||||
        check()
 | 
					        check()
 | 
				
			||||||
@ -18,7 +19,12 @@ class JustUpdatedChecker: ObservableObject, JustUpdatedCheckerProtocol {
 | 
				
			|||||||
        let lastBuild = UserDefaults.standard.object(forKey: Constants.previousVersionUserDefaultsKey) as? String ?? "None"
 | 
					        let lastBuild = UserDefaults.standard.object(forKey: Constants.previousVersionUserDefaultsKey) as? String ?? "None"
 | 
				
			||||||
        let currentBuild = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
 | 
					        let currentBuild = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
 | 
				
			||||||
        UserDefaults.standard.set(currentBuild, forKey: Constants.previousVersionUserDefaultsKey)
 | 
					        UserDefaults.standard.set(currentBuild, forKey: Constants.previousVersionUserDefaultsKey)
 | 
				
			||||||
        justUpdated = lastBuild != currentBuild
 | 
					        if currentBuild != Constants.debugVersionKey {
 | 
				
			||||||
 | 
					            justUpdated = lastBuild != currentBuild
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            justUpdated = !alreadyRelaunchedForDebug
 | 
				
			||||||
 | 
					            alreadyRelaunchedForDebug = true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -29,6 +35,7 @@ extension JustUpdatedChecker {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    enum Constants {
 | 
					    enum Constants {
 | 
				
			||||||
        static let previousVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastBuild"
 | 
					        static let previousVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastBuild"
 | 
				
			||||||
 | 
					        static let debugVersionKey = "GITHUB_CI_VERSION"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,6 @@ import Foundation
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extension Bundle {
 | 
					extension Bundle {
 | 
				
			||||||
    public var agentBundleID: String {(self.bundleIdentifier?.replacingOccurrences(of: "Host", with: "SecretAgent"))!}
 | 
					    public var agentBundleID: String { "Z72PRUAWF6.com.maxgoedjen.Secretive.SecretAgent" }
 | 
				
			||||||
    public var hostBundleID: String {(self.bundleIdentifier?.replacingOccurrences(of: "SecretAgent", with: "Host"))!}
 | 
					    public var hostBundleID: String {(self.bundleIdentifier?.replacingOccurrences(of: "SecretAgent", with: "Host"))!}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -45,6 +45,7 @@ extension Preview {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class StoreModifiable: Store, SecretStoreModifiable {
 | 
					    class StoreModifiable: Store, SecretStoreModifiable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        override var name: String { "Modifiable Preview Store" }
 | 
					        override var name: String { "Modifiable Preview Store" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        func create(name: String, requiresAuthentication: Bool) throws {
 | 
					        func create(name: String, requiresAuthentication: Bool) throws {
 | 
				
			||||||
@ -55,6 +56,10 @@ extension Preview {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        func update(secret: Preview.Secret, name: String) throws {
 | 
					        func update(secret: Preview.Secret, name: String) throws {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        func reload() throws {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,10 @@
 | 
				
			|||||||
<dict>
 | 
					<dict>
 | 
				
			||||||
	<key>com.apple.security.app-sandbox</key>
 | 
						<key>com.apple.security.app-sandbox</key>
 | 
				
			||||||
	<true/>
 | 
						<true/>
 | 
				
			||||||
 | 
						<key>com.apple.security.application-groups</key>
 | 
				
			||||||
 | 
						<array>
 | 
				
			||||||
 | 
							<string>$(TeamIdentifierPrefix)com.maxgoedjen.secretive</string>
 | 
				
			||||||
 | 
						</array>
 | 
				
			||||||
	<key>com.apple.security.files.user-selected.read-write</key>
 | 
						<key>com.apple.security.files.user-selected.read-write</key>
 | 
				
			||||||
	<true/>
 | 
						<true/>
 | 
				
			||||||
	<key>com.apple.security.network.client</key>
 | 
						<key>com.apple.security.network.client</key>
 | 
				
			||||||
 | 
				
			|||||||
@ -87,7 +87,7 @@ extension ContentView {
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
                    .popover(isPresented: $showingCreation, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
 | 
					                    .popover(isPresented: $showingCreation, attachmentAnchor: .point(.bottom), arrowEdge: .bottom) {
 | 
				
			||||||
                        if let modifiable = storeList.modifiableStore {
 | 
					                        if let modifiable = storeList.modifiableStore {
 | 
				
			||||||
                            CreateSecretView(store: modifiable, showing: $showingCreation)
 | 
					                            CreateSecretView<AnySecretStoreModifiable, AgentCommunicationController>(store: modifiable, showing: $showingCreation)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,10 @@
 | 
				
			|||||||
import SwiftUI
 | 
					import SwiftUI
 | 
				
			||||||
import SecretKit
 | 
					import SecretKit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
 | 
					struct CreateSecretView<StoreType: SecretStoreModifiable, AgentCommunicationControllerType: AgentCommunicationControllerProtocol>: View {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @ObservedObject var store: StoreType
 | 
					    @ObservedObject var store: StoreType
 | 
				
			||||||
 | 
					    @EnvironmentObject private var agentCommunicationController: AgentCommunicationControllerType
 | 
				
			||||||
    @Binding var showing: Bool
 | 
					    @Binding var showing: Bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @State private var name = ""
 | 
					    @State private var name = ""
 | 
				
			||||||
@ -52,6 +53,9 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    func save() {
 | 
					    func save() {
 | 
				
			||||||
        try! store.create(name: name, requiresAuthentication: requiresAuthentication)
 | 
					        try! store.create(name: name, requiresAuthentication: requiresAuthentication)
 | 
				
			||||||
 | 
					        Task {
 | 
				
			||||||
 | 
					            try! await agentCommunicationController.agent.updatedStore(withID: store.id)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        showing = false
 | 
					        showing = false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -156,7 +156,7 @@ struct SecretAgentSetupView: View {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func install() {
 | 
					    func install() {
 | 
				
			||||||
        LaunchAgentController().install()
 | 
					        AgentLaunchController().install()
 | 
				
			||||||
        buttonAction()
 | 
					        buttonAction()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user