diff --git a/Sources/Packages/Resources/Localizable.xcstrings b/Sources/Packages/Resources/Localizable.xcstrings index d66c69a..6d7a54b 100644 --- a/Sources/Packages/Resources/Localizable.xcstrings +++ b/Sources/Packages/Resources/Localizable.xcstrings @@ -1845,191 +1845,6 @@ } } }, - "agent_details_running_since_title" : { - "extractionState" : "manual", - "localizations" : { - "af" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "ar" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "ca" : { - "stringUnit" : { - "state" : "translated", - "value" : "Funcionant des de" - } - }, - "cs" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "da" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Läuft seit" - } - }, - "el" : { - "stringUnit" : { - "state" : "translated", - "value" : "Εκτελείται Από" - } - }, - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "es" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "fi" : { - "stringUnit" : { - "state" : "translated", - "value" : "Käynnissä alkaen" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Actif depuis" - } - }, - "he" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "hu" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "it" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "最後に起動した日時" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "실행 시각" - } - }, - "nb" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "nl" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Uruchomiony od" - } - }, - "pt" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : "Rodando desde" - } - }, - "ro" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Запущено с" - } - }, - "sr" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "sv" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "tr" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "uk" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "vi" : { - "stringUnit" : { - "state" : "new", - "value" : "Running Since" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "运行时间始于" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "執行時間始於" - } - } - } - }, "agent_details_socket_path_title" : { "extractionState" : "manual", "localizations" : { @@ -2770,7 +2585,7 @@ } } }, - "agent_not_running_notice_detail_description" : { + "agent_not_configured_notice_detail_description" : { "extractionState" : "manual", "localizations" : { "af" : { @@ -2787,7 +2602,7 @@ }, "ca" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "L'agent segur (SecretAgent) és un procés que funciona en rerefons per signar peticions, tal que no hages de tindre Secretive obert tot el temps.\n\n**Secretive no funcionarà correctament a menys que l'agent estiga instal·lat i en funcionament.**" } }, @@ -2805,20 +2620,20 @@ }, "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent ist ein Hintergrund-Prozess, der Anfragen signiert, sodass Du Secretive nicht durchgehend geöffnet haben musst.\n\n**Secretive wird nicht richtig funktionieren, wenn der Agent nicht installiert und ausgeführt wird.**" } }, "el" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Το SecretAgent είναι μια διεργασία που εκτελείται στο παρασκήνιο για να υπογράφει αιτήματα. Δεν χρειάζεται να κρατάτε παράθυρο του Secretive ανοιχτό συνεχώς.\n\n**Το Secretive δεν θα μπορεί να λειτουργήσει σωστά εκτός και αν o Agent είναι εγκατεστημένος και εκτελείται.**" } }, "en" : { "stringUnit" : { - "state" : "new", - "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**Secretive will not be able to function properly unless the agent is installed and running.**" + "state" : "translated", + "value" : "SecretAgent is a process that runs in the background to sign requests, so you don't need to keep Secretive open all the time.\n\n**Secretive will not be able to function properly unless the agent is configured.**" } }, "es" : { @@ -2829,13 +2644,13 @@ }, "fi" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent-agenttiprosessi toimii taustalla ja allekirjoittaa pyyntöjä, jotta Secretive-käyttöliittymää ei tarvitse pitää aina auki.\n\n**Secretive ei toimi oikein, jollei agentti ole asennettu ja käynnissä.**" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent est un processus qui s'exécute en arrière-plan pour signer les demandes, de sorte que vous n'ayez pas besoin de garder Secretive ouvert en permanence.\n\n**Secretive ne pourra pas fonctionner correctement sans que l'agent soit installé et fonctionne.**" } }, @@ -2859,13 +2674,13 @@ }, "ja" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgentはバックグラウンドで稼働し署名を行います。Secretiveアプリを常に実行する必要はありません。\n\n**Secretiveアプリはエージェントがインストールされて稼働しない限り正しく動作しません。**" } }, "ko" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent는 백그라운드에서 실행되어 요청에 서명하는 프로세스이므로 Secretive를 항상 열어 둘 필요는 없습니다.\n\n**Secretive 에이전트가 설치되어 실행 중이어야 Secretive가 제대로 작동합니다.**" } }, @@ -2883,7 +2698,7 @@ }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent to proces działający w tle, który podpisuje żądania, dzięki czemu nie musisz mieć otwartego programu Secretive przez cały czas.\n\n**Program Secretive nie będzie działał poprawnie, jeśli agent nie zostanie zainstalowany i uruchomiony.**" } }, @@ -2895,7 +2710,7 @@ }, "pt-BR" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent é um processo que é executado em segundo plano para assinar pedidos, então não há necessidade de manter Secretive aberto o tempo todo.\n\n**Secretive não funcionará corretamente a menos que o agente esteja instalado e executando.**" } }, @@ -2907,7 +2722,7 @@ }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent это процесс, который работает в фоне чтобы подписывать запросы. Так Вам не придется все время держать Secretive открытым.\n\n**Secretive не сможет нормально функционировать, пока агент не установлен и не запущен.**" } }, @@ -2943,19 +2758,19 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent是个在后台处理签名请求的进程,让您无需将Secretive一直保持在前台。\n\n**需要安装并运行Agent,否则Secretive无法正常工作。**" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent是個在後台處理簽名請求的行程,讓您無需將Secretive一直保持在前台。\n\n**需要安裝並執行Agent,否則Secretive無法正常工作。**" } } } }, - "agent_not_running_notice_title" : { + "agent_not_configured_notice_title" : { "extractionState" : "manual", "localizations" : { "af" : { @@ -2972,7 +2787,7 @@ }, "ca" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent inactiu" } }, @@ -2990,20 +2805,20 @@ }, "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent wird Nicht Ausgeführt" } }, "el" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Ο Agent Δεν Εκτελείται" } }, "en" : { "stringUnit" : { - "state" : "new", - "value" : "Agent Is Not Running" + "state" : "translated", + "value" : "Agent Is Not Configured" } }, "es" : { @@ -3014,13 +2829,13 @@ }, "fi" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agentti ei ole käynnissä" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "L'agent n'est pas actif" } }, @@ -3038,19 +2853,19 @@ }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent non è in esecuzione" } }, "ja" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "エージェントが稼働していません" } }, "ko" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent가 실행되고 있지 않음" } }, @@ -3068,7 +2883,7 @@ }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent nie jest uruchomiony" } }, @@ -3080,7 +2895,7 @@ }, "pt-BR" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent não está rodando" } }, @@ -3092,7 +2907,7 @@ }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Агент не запущен" } }, @@ -3128,19 +2943,19 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent尚未运行" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent尚未執行" } } } }, - "agent_running_notice_detail_description" : { + "agent_ready_notice_detail_description" : { "extractionState" : "manual", "localizations" : { "af" : { @@ -3325,7 +3140,7 @@ } } }, - "agent_running_notice_detail_title" : { + "agent_ready_notice_detail_title" : { "extractionState" : "manual", "localizations" : { "af" : { @@ -3342,7 +3157,7 @@ }, "ca" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "L'agent secret està actiu" } }, @@ -3360,20 +3175,20 @@ }, "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent wird Ausgeführt" } }, "el" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Ο Πράκτορας εκτελείται" } }, "en" : { "stringUnit" : { - "state" : "new", - "value" : "Secret Agent is Running" + "state" : "translated", + "value" : "Secret Agent is Ready" } }, "es" : { @@ -3384,13 +3199,13 @@ }, "fi" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent on käynnissä" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent est actif" } }, @@ -3408,19 +3223,19 @@ }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent è in esecuzione" } }, "ja" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "エージェントは稼働中" } }, "ko" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent가 실행 중입니다." } }, @@ -3438,7 +3253,7 @@ }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent jest uruchomiony" } }, @@ -3450,7 +3265,7 @@ }, "pt-BR" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent está rodando" } }, @@ -3462,7 +3277,7 @@ }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "SecretAgent запущен" } }, @@ -3498,19 +3313,19 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent运行中" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Secret Agent執行中" } } } }, - "agent_running_notice_title" : { + "agent_ready_notice_title" : { "extractionState" : "manual", "localizations" : { "af" : { @@ -3527,7 +3342,7 @@ }, "ca" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent actiu" } }, @@ -3545,7 +3360,7 @@ }, "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent wird Ausgeführt" } }, @@ -3557,8 +3372,8 @@ }, "en" : { "stringUnit" : { - "state" : "new", - "value" : "Agent is Running" + "state" : "translated", + "value" : "Agent is Ready" } }, "es" : { @@ -3569,13 +3384,13 @@ }, "fi" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agentti on käynnissä" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "L'agent est actif" } }, @@ -3593,19 +3408,19 @@ }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent è in esecuzione" } }, "ja" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "エージェントは稼働中" } }, "ko" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent가 실행중" } }, @@ -3623,7 +3438,7 @@ }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent jest uruchomiony" } }, @@ -3635,7 +3450,7 @@ }, "pt-BR" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent está rodando" } }, @@ -3647,7 +3462,7 @@ }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Агент запущен" } }, @@ -3683,13 +3498,13 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent运行中" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Agent執行中" } } diff --git a/Sources/Secretive/App.swift b/Sources/Secretive/App.swift index 4f8eaff..370cd9d 100644 --- a/Sources/Secretive/App.swift +++ b/Sources/Secretive/App.swift @@ -1,15 +1,31 @@ import SwiftUI -import ServiceManagement +@unsafe @preconcurrency import ServiceManagement import SecretKit import SecureEnclaveSecretKit import SmartCardSecretKit import Brief import CertificateKit +@Observable +final class LaunchService: Sendable { + private let service = SMAppService.agent(plistName: "com.maxgoedjen.Secretive.SecretAgent.plist") + var status: SMAppService.Status { + service.status + } + + func configure() { + try? service.unregister() + try! service.register() + } + + func disable() { + try? service.unregister() + } +} + @main struct Secretive: App { -// @Environment(\.agentLaunchController) var agentLaunchController @Environment(\.justUpdatedChecker) var justUpdatedChecker @SceneBuilder var body: some Scene { @@ -17,13 +33,8 @@ struct Secretive: App { ContentView() .environment(EnvironmentValues._secretStoreList) .environment(EnvironmentValues._certificateStore) - .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in - Task { - let service = SMAppService.agent(plistName: "com.maxgoedjen.Secretive.SecretAgent.plist") - try? service.unregister() - try! service.register() - print("Status: \(service.status)") - } + .onAppear { + EnvironmentValues._launchService.configure() } } .commands { @@ -111,6 +122,9 @@ extension EnvironmentValues { private static let _justUpdatedChecker = JustUpdatedChecker() @Entry var justUpdatedChecker: any JustUpdatedCheckerProtocol = _justUpdatedChecker + fileprivate static let _launchService = LaunchService() + @Entry var launchService: LaunchService = _launchService + @MainActor var secretStoreList: SecretStoreList { EnvironmentValues._secretStoreList } diff --git a/Sources/Secretive/Views/Views/AgentStatusView.swift b/Sources/Secretive/Views/Views/AgentStatusView.swift index 8b4ba18..3eb4ee3 100644 --- a/Sources/Secretive/Views/Views/AgentStatusView.swift +++ b/Sources/Secretive/Views/Views/AgentStatusView.swift @@ -2,10 +2,10 @@ import SwiftUI struct AgentStatusView: View { - @Environment(\.agentLaunchController) private var agentLaunchController: any AgentLaunchControllerProtocol + @Environment(\.launchService) private var launchService var body: some View { - if agentLaunchController.running { + if launchService.status == .enabled { AgentRunningView() } else { AgentNotRunningView() @@ -14,54 +14,53 @@ struct AgentStatusView: View { } struct AgentRunningView: View { - @Environment(\.agentLaunchController) private var agentLaunchController: any AgentLaunchControllerProtocol + @Environment(\.launchService) private var launchService @AppStorage("explicitlyDisabled") var explicitlyDisabled = false var body: some View { Form { Section { - if let process = agentLaunchController.process { - ConfigurationItemView( - title: .agentDetailsLocationTitle, - value: process.bundleURL!.path(), - action: .revealInFinder(process.bundleURL!.path()), - ) +// if let process = agentLaunchController.process { +// ConfigurationItemView( +// title: .agentDetailsLocationTitle, +// value: process.bundleURL!.path(), +// action: .revealInFinder(process.bundleURL!.path()), +// ) ConfigurationItemView( title: .agentDetailsSocketPathTitle, value: URL.socketPath, action: .copy(URL.socketPath), ) - ConfigurationItemView( - title: .agentDetailsVersionTitle, - value: Bundle(url: process.bundleURL!)!.infoDictionary!["CFBundleShortVersionString"] as! String - ) - if let launchDate = process.launchDate { - ConfigurationItemView( - title: .agentDetailsRunningSinceTitle, - value: launchDate.formatted() - ) - } - } +// ConfigurationItemView( +// title: .agentDetailsVersionTitle, +// value: Bundle(url: process.bundleURL!)!.infoDictionary!["CFBundleShortVersionString"] as! String +// ) +// if let launchDate = process.launchDate { +// ConfigurationItemView( +// title: .agentDetailsRunningSinceTitle, +// value: launchDate.formatted() +// ) +// } +// } } header: { - Text(.agentRunningNoticeDetailTitle) + Text(.agentReadyNoticeDetailTitle) .font(.headline) .padding(.top) } footer: { VStack(alignment: .leading, spacing: 10) { - Text(.agentRunningNoticeDetailDescription) + Text(.agentReadyNoticeDetailDescription) HStack { Spacer() Menu(.agentDetailsRestartAgentButton) { Button(.agentDetailsDisableAgentButton) { Task { explicitlyDisabled = true - try? await agentLaunchController - .uninstall() + launchService.disable() } } } primaryAction: { Task { - try? await agentLaunchController.forceLaunch() + launchService.configure() } } } @@ -78,7 +77,6 @@ struct AgentRunningView: View { struct AgentNotRunningView: View { - @Environment(\.agentLaunchController) private var agentLaunchController @State var triedRestart = false @State var loading = false @AppStorage("explicitlyDisabled") var explicitlyDisabled = false @@ -87,12 +85,12 @@ struct AgentNotRunningView: View { Form { Section { } header: { - Text(.agentNotRunningNoticeTitle) + Text(.agentNotConfiguredNoticeTitle) .font(.headline) .padding(.top) } footer: { VStack(alignment: .leading, spacing: 10) { - Text(.agentNotRunningNoticeDetailDescription) + Text(.agentNotConfiguredNoticeDetailDescription) HStack { if !triedRestart { Spacer() diff --git a/Sources/Secretive/Views/Views/ContentView.swift b/Sources/Secretive/Views/Views/ContentView.swift index ef9d8f5..f321ab7 100644 --- a/Sources/Secretive/Views/Views/ContentView.swift +++ b/Sources/Secretive/Views/Views/ContentView.swift @@ -19,6 +19,7 @@ struct ContentView: View { @Environment(\.certificateStore) private var certificateStore @Environment(\.updater) private var updater @Environment(\.agentLaunchController) private var agentLaunchController + @Environment(\.launchService) private var launchService @AppStorage("defaultsHasRunSetup") private var hasRunSetup = false @State private var showingCreation = false @@ -147,15 +148,15 @@ extension ContentView { showingAgentInfo = true }, label: { HStack { - if agentLaunchController.running { - Text(.agentRunningNoticeTitle) + if launchService.status == .enabled { + Text(.agentReadyNoticeTitle) .font(.headline) .foregroundColor(colorScheme == .light ? Color(white: 0.3) : .white) Circle() .frame(width: 10, height: 10) .foregroundColor(Color.green) } else { - Text(.agentNotRunningNoticeTitle) + Text(.agentNotConfiguredNoticeTitle) .font(.headline) Circle() .frame(width: 10, height: 10) @@ -165,8 +166,8 @@ extension ContentView { }) .buttonStyle( ToolbarStatusButtonStyle( - lightColor: agentLaunchController.running ? .black.opacity(0.05) : .red.opacity(0.75), - darkColor: agentLaunchController.running ? .white.opacity(0.05) : .red.opacity(0.5), + lightColor: launchService.status == .enabled ? .black.opacity(0.05) : .red.opacity(0.75), + darkColor: launchService.status == .enabled ? .white.opacity(0.05) : .red.opacity(0.5), ) ) .popover(isPresented: $showingAgentInfo, attachmentAnchor: attachmentAnchor, arrowEdge: .bottom) {