mirror of
https://github.com/maxgoedjen/secretive.git
synced 2024-11-24 06:27:08 +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 }
|
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:))
|
||||||
}
|
}
|
||||||
|
// TODO: REMOVE
|
||||||
|
notifier.notify(update: Release(name: "Test", prerelease: false, html_url: URL(string: "https://example.com")!, body: ""), ignore: nil)
|
||||||
connect()
|
connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +57,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, AgentProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updatedStore(withID id: UUID) async throws {
|
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)")
|
logger.debug("Reloading keys for store with id: \(id)")
|
||||||
guard let store = storeList.modifiableStore, store.id == id else { throw AgentProtocolStoreNotFoundError() }
|
guard let store = storeList.modifiableStore, store.id == id else { throw AgentProtocolStoreNotFoundError() }
|
||||||
try store.reload()
|
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
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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:
|
// 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.
|
// 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.
|
// 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) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||||
agentCommunicationController.configure()
|
agentCommunicationController.configure()
|
||||||
}
|
}
|
||||||
@ -72,7 +75,7 @@ struct Secretive: App {
|
|||||||
CommandGroup(after: .help) {
|
CommandGroup(after: .help) {
|
||||||
Button("TEST") {
|
Button("TEST") {
|
||||||
Task {
|
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 {
|
extension Secretive {
|
||||||
|
|
||||||
private func reinstallAgent(completion: @escaping () -> Void) {
|
private func reinstallAgent(uninstallFirst: Bool, completion: @escaping () -> Void) {
|
||||||
justUpdatedChecker.check()
|
justUpdatedChecker.check()
|
||||||
agentLaunchController.install {
|
agentLaunchController.install(uninstallFirst: uninstallFirst) {
|
||||||
// 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()
|
||||||
|
@ -1,34 +1,35 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import AppKit
|
import AppKit
|
||||||
|
import OSLog
|
||||||
import SecretKit
|
import SecretKit
|
||||||
import SecretAgentKitProtocol
|
import SecretAgentKitProtocol
|
||||||
|
|
||||||
protocol AgentCommunicationControllerProtocol: ObservableObject {
|
protocol AgentCommunicationControllerProtocol: ObservableObject {
|
||||||
var agent: AgentProtocol { get }
|
var agent: AgentProtocol? { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AgentCommunicationController: ObservableObject, AgentCommunicationControllerProtocol {
|
class AgentCommunicationController: ObservableObject, AgentCommunicationControllerProtocol {
|
||||||
|
|
||||||
let agent: AgentProtocol
|
private(set) var agent: AgentProtocol? = nil
|
||||||
private let connection: NSXPCConnection
|
private var connection: NSXPCConnection? = nil
|
||||||
private var running = false
|
private var running = false
|
||||||
|
|
||||||
init() {
|
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() {
|
func configure() {
|
||||||
guard !running else { return }
|
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
|
running = true
|
||||||
connection.resume()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,19 @@ import SecretKit
|
|||||||
|
|
||||||
struct AgentLaunchController {
|
struct AgentLaunchController {
|
||||||
|
|
||||||
func install(completion: (() -> Void)? = nil) {
|
func install(uninstallFirst: Bool = true, completion: (() -> Void)? = nil) {
|
||||||
Logger().debug("Installing agent")
|
Logger().debug("Installing agent")
|
||||||
_ = setEnabled(false)
|
if uninstallFirst {
|
||||||
|
_ = setEnabled(false)
|
||||||
|
}
|
||||||
// This is definitely a bit of a "seems to work better" thing but:
|
// 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
|
// Seems to more reliably hit if these are on separate runloops, otherwise it seems like it sometimes doesn't kill old
|
||||||
// and start new?
|
// and start new?
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
_ = setEnabled(true)
|
_ = setEnabled(true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||||
completion?()
|
completion?()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -36,6 +40,12 @@ struct AgentLaunchController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func killNonInstanceAgents(agents: [NSRunningApplication]) {
|
||||||
|
for agent in agents {
|
||||||
|
agent.terminate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func setEnabled(_ enabled: Bool) -> Bool {
|
private func setEnabled(_ enabled: Bool) -> Bool {
|
||||||
SMLoginItemSetEnabled(Bundle.main.agentBundleID as CFString, enabled)
|
SMLoginItemSetEnabled(Bundle.main.agentBundleID as CFString, enabled)
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,18 @@ class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol {
|
|||||||
let agents = secretAgentProcesses
|
let agents = secretAgentProcesses
|
||||||
for agent in agents {
|
for agent in agents {
|
||||||
guard let url = agent.bundleURL else { continue }
|
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 agent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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.
|
// Whether Secretive is being run in an Xcode environment.
|
||||||
var developmentBuild: Bool {
|
var developmentBuild: Bool {
|
||||||
|
@ -54,7 +54,7 @@ struct CreateSecretView<StoreType: SecretStoreModifiable, AgentCommunicationCont
|
|||||||
func save() {
|
func save() {
|
||||||
try! store.create(name: name, requiresAuthentication: requiresAuthentication)
|
try! store.create(name: name, requiresAuthentication: requiresAuthentication)
|
||||||
Task {
|
Task {
|
||||||
try! await agentCommunicationController.agent.updatedStore(withID: store.id)
|
try! await agentCommunicationController.agent!.updatedStore(withID: store.id)
|
||||||
}
|
}
|
||||||
showing = false
|
showing = false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user