mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-09-16 09:20:56 +00:00
WIP
This commit is contained in:
parent
f0a6f2e43b
commit
cbf903deb7
@ -1,6 +1,9 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"Add Automatically" : {
|
||||
|
||||
},
|
||||
"agent_not_running_notice_title" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@ -4323,6 +4326,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"setup_ssh_add_to_config_button_%@" : {
|
||||
|
||||
},
|
||||
"setup_ssh_added_manually_button" : {
|
||||
"extractionState" : "manual",
|
||||
@ -5189,9 +5195,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Test" : {
|
||||
|
||||
},
|
||||
"unnamed_secret" : {
|
||||
"extractionState" : "manual",
|
||||
|
@ -49,6 +49,7 @@
|
||||
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */; };
|
||||
50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79324026B7600D209EA /* Preview Assets.xcassets */; };
|
||||
50A3B79724026B7600D209EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50A3B79524026B7600D209EA /* Main.storyboard */; };
|
||||
50AE97002E5C1A420018C710 /* ConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50AE96FF2E5C1A420018C710 /* ConfigurationView.swift */; };
|
||||
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; };
|
||||
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; };
|
||||
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; };
|
||||
@ -137,6 +138,7 @@
|
||||
50A3B79624026B7600D209EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
50A3B79824026B7600D209EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
50A3B79924026B7600D209EA /* SecretAgent.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecretAgent.entitlements; sourceTree = "<group>"; };
|
||||
50AE96FF2E5C1A420018C710 /* ConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationView.swift; sourceTree = "<group>"; };
|
||||
50B8550C24138C4F009958AC /* DeleteSecretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteSecretView.swift; sourceTree = "<group>"; };
|
||||
50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyStoreView.swift; sourceTree = "<group>"; };
|
||||
50C385A42407A76D00AF2719 /* SecretDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretDetailView.swift; sourceTree = "<group>"; };
|
||||
@ -251,6 +253,7 @@
|
||||
506772C82425BB8500034DED /* NoStoresView.swift */,
|
||||
50153E1F250AFCB200525160 /* UpdateView.swift */,
|
||||
5066A6C12516F303004B5A36 /* SetupView.swift */,
|
||||
50AE96FF2E5C1A420018C710 /* ConfigurationView.swift */,
|
||||
5066A6C72516FE6E004B5A36 /* CopyableView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
@ -443,6 +446,7 @@
|
||||
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */,
|
||||
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
|
||||
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
|
||||
50AE97002E5C1A420018C710 /* ConfigurationView.swift in Sources */,
|
||||
50153E20250AFCB200525160 /* UpdateView.swift in Sources */,
|
||||
50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */,
|
||||
5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */,
|
||||
|
@ -71,7 +71,7 @@ struct Secretive: App {
|
||||
NSWorkspace.shared.open(Constants.helpURL)
|
||||
}
|
||||
}
|
||||
CommandGroup(after: .help) {
|
||||
CommandGroup(before: .help) {
|
||||
Button(.appMenuSetupButton) {
|
||||
showingSetup = true
|
||||
}
|
||||
|
@ -24,13 +24,14 @@ import Observation
|
||||
}
|
||||
|
||||
// All processes, including ones from older versions, etc
|
||||
var secretAgentProcesses: [NSRunningApplication] {
|
||||
NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.agentBundleID)
|
||||
var allSecretAgentProcesses: [NSRunningApplication] {
|
||||
NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.agentBundleID)
|
||||
}
|
||||
|
||||
// The process corresponding to this instance of Secretive
|
||||
var instanceSecretAgentProcess: NSRunningApplication? {
|
||||
let agents = secretAgentProcesses
|
||||
// FIXME: CHECK VERSION
|
||||
let agents = allSecretAgentProcesses
|
||||
for agent in agents {
|
||||
guard let url = agent.bundleURL else { continue }
|
||||
if url.absoluteString.hasPrefix(Bundle.main.bundleURL.absoluteString) {
|
||||
@ -40,7 +41,6 @@ import Observation
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Whether Secretive is being run in an Xcode environment.
|
||||
var developmentBuild: Bool {
|
||||
Bundle.main.bundleURL.absoluteString.contains("/Library/Developer/Xcode")
|
||||
|
@ -36,7 +36,7 @@ struct LaunchAgentController {
|
||||
}
|
||||
|
||||
private func setEnabled(_ enabled: Bool) -> Bool {
|
||||
let service = SMAppService.loginItem(identifier: Bundle.main.agentBundleID)
|
||||
let service = SMAppService.loginItem(identifier: Bundle.agentBundleID)
|
||||
do {
|
||||
if enabled {
|
||||
try service.register()
|
||||
|
@ -4,7 +4,7 @@ import SecretKit
|
||||
|
||||
struct ShellConfigurationController {
|
||||
|
||||
let socketPath = (NSHomeDirectory().replacingOccurrences(of: Bundle.main.hostBundleID, with: Bundle.main.agentBundleID) as NSString).appendingPathComponent("socket.ssh") as String
|
||||
let socketPath = (NSHomeDirectory().replacingOccurrences(of: Bundle.hostBundleID, with: Bundle.agentBundleID) as NSString).appendingPathComponent("socket.ssh") as String
|
||||
|
||||
var shellInstructions: [ShellConfigInstruction] {
|
||||
[
|
||||
|
@ -1,7 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
extension Bundle {
|
||||
public var agentBundleID: String {(self.bundleIdentifier?.replacingOccurrences(of: "Host", with: "SecretAgent"))!}
|
||||
public var hostBundleID: String {(self.bundleIdentifier?.replacingOccurrences(of: "SecretAgent", with: "Host"))!}
|
||||
public static var agentBundleID: String {
|
||||
Bundle.main.bundleIdentifier!.replacingOccurrences(of: "Host", with: "SecretAgent")
|
||||
}
|
||||
|
||||
public static var hostBundleID: String {
|
||||
Bundle.main.bundleIdentifier!.replacingOccurrences(of: "SecretAgent", with: "Host")
|
||||
}
|
||||
}
|
||||
|
47
Sources/Secretive/Views/ConfigurationView.swift
Normal file
47
Sources/Secretive/Views/ConfigurationView.swift
Normal file
@ -0,0 +1,47 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ConfigurationView: View {
|
||||
|
||||
@Binding var visible: Bool
|
||||
|
||||
@State var running = true
|
||||
@State var sshConfig = false
|
||||
|
||||
@Environment(\.agentStatusChecker) var agentStatusChecker
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
NewStepView(title: "setup_agent_title", description: "setup_agent_description") {
|
||||
OnboardingButton("setup_agent_install_button", running) {
|
||||
Task {
|
||||
_ = await LaunchAgentController().forceLaunch()
|
||||
agentStatusChecker.check()
|
||||
running = agentStatusChecker.running
|
||||
}
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
Divider()
|
||||
NewStepView(title: "setup_ssh_title", description: "setup_ssh_description") {
|
||||
HStack {
|
||||
OnboardingButton("setup_ssh_added_manually_button", false) {
|
||||
sshConfig = true
|
||||
}
|
||||
OnboardingButton("Add Automatically", false) {
|
||||
// let controller = ShellConfigurationController()
|
||||
// if controller.addToShell(shellInstructions: selectedShellInstruction) {
|
||||
// }
|
||||
sshConfig = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(.white.opacity(0.1), in: RoundedRectangle(cornerRadius: 10))
|
||||
.frame(minWidth: 500, idealWidth: 500, minHeight: 500, idealHeight: 500)
|
||||
.padding()
|
||||
.task {
|
||||
running = agentStatusChecker.running
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,8 +6,8 @@ struct SecretDetailView<SecretType: Secret>: View {
|
||||
let secret: SecretType
|
||||
|
||||
private let keyWriter = OpenSSHPublicKeyWriter()
|
||||
private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: NSHomeDirectory().replacingOccurrences(of: Bundle.main.hostBundleID, with: Bundle.main.agentBundleID))
|
||||
|
||||
private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.agentHomePath)
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
Form {
|
||||
@ -37,6 +37,14 @@ struct SecretDetailView<SecretType: Secret>: View {
|
||||
|
||||
}
|
||||
|
||||
extension URL {
|
||||
|
||||
static var agentHomePath: String {
|
||||
URL.homeDirectory.path().replacingOccurrences(of: Bundle.hostBundleID, with: Bundle.agentBundleID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
struct SecretDetailView_Previews: PreviewProvider {
|
||||
|
@ -2,6 +2,124 @@ import SwiftUI
|
||||
|
||||
struct SetupView: View {
|
||||
|
||||
@Binding var visible: Bool
|
||||
@Binding var setupComplete: Bool
|
||||
|
||||
@State var installed = false
|
||||
@State var updates = false
|
||||
@State var sshConfig = false
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
NewStepView(title: "setup_agent_title", description: "setup_agent_description") {
|
||||
OnboardingButton("setup_agent_install_button", installed) {
|
||||
Task {
|
||||
await LaunchAgentController().install()
|
||||
installed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
NewStepView(title: "setup_updates_title", description: "setup_updates_description") {
|
||||
OnboardingButton("setup_updates_ok", false) {
|
||||
Task {
|
||||
updates = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
NewStepView(title: "setup_ssh_title", description: "setup_ssh_description") {
|
||||
HStack {
|
||||
OnboardingButton("setup_ssh_added_manually_button", false) {
|
||||
sshConfig = true
|
||||
}
|
||||
OnboardingButton("Add Automatically", false) {
|
||||
// let controller = ShellConfigurationController()
|
||||
// if controller.addToShell(shellInstructions: selectedShellInstruction) {
|
||||
// }
|
||||
sshConfig = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(.white.opacity(0.1), in: RoundedRectangle(cornerRadius: 10))
|
||||
.frame(minWidth: 500, idealWidth: 500, minHeight: 500, idealHeight: 500)
|
||||
.padding()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct OnboardingButton: View {
|
||||
|
||||
let label: LocalizedStringResource
|
||||
let complete: Bool
|
||||
let action: () -> Void
|
||||
|
||||
init(_ label: LocalizedStringResource, _ complete: Bool, action: @escaping () -> Void) {
|
||||
self.label = label
|
||||
self.complete = complete
|
||||
self.action = action
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
HStack(spacing: 6) {
|
||||
Text(label)
|
||||
if complete {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 2)
|
||||
}
|
||||
.disabled(complete)
|
||||
.styled
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension View {
|
||||
|
||||
@ViewBuilder
|
||||
var styled: some View {
|
||||
if #available(macOS 26.0, *) {
|
||||
buttonStyle(.glassProminent)
|
||||
} else {
|
||||
buttonStyle(.borderedProminent)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct NewStepView<Content: View>: View {
|
||||
|
||||
let title: LocalizedStringResource
|
||||
let description: LocalizedStringResource
|
||||
let actions: Content
|
||||
|
||||
init(title: LocalizedStringResource, description: LocalizedStringResource, actions: () -> Content) {
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.actions = actions()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title)
|
||||
.bold()
|
||||
Text(description)
|
||||
}
|
||||
Spacer(minLength: 20)
|
||||
actions
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct OldSetupView: View {
|
||||
|
||||
@State var stepIndex = 0
|
||||
@Binding var visible: Bool
|
||||
@Binding var setupComplete: Bool
|
||||
@ -61,7 +179,7 @@ struct StepView: View {
|
||||
Circle()
|
||||
.foregroundColor(.green)
|
||||
.frame(width: Constants.circleWidth, height: Constants.circleWidth)
|
||||
Text(.setupStepCompleteSymbol)
|
||||
Text("setup_step_complete_symbol")
|
||||
.foregroundColor(.white)
|
||||
.bold()
|
||||
} else {
|
||||
@ -101,14 +219,14 @@ extension StepView {
|
||||
|
||||
struct SetupStepView<Content> : View where Content : View {
|
||||
|
||||
let title: LocalizedStringResource
|
||||
let title: LocalizedStringKey
|
||||
let image: Image
|
||||
let bodyText: LocalizedStringResource
|
||||
let buttonTitle: LocalizedStringResource
|
||||
let bodyText: LocalizedStringKey
|
||||
let buttonTitle: LocalizedStringKey
|
||||
let buttonAction: () -> Void
|
||||
let content: Content
|
||||
|
||||
init(title: LocalizedStringResource, image: Image, bodyText: LocalizedStringResource, buttonTitle: LocalizedStringResource, buttonAction: @escaping () -> Void = {}, @ViewBuilder content: () -> Content) {
|
||||
init(title: LocalizedStringKey, image: Image, bodyText: LocalizedStringKey, buttonTitle: LocalizedStringKey, buttonAction: @escaping () -> Void = {}, @ViewBuilder content: () -> Content) {
|
||||
self.title = title
|
||||
self.image = image
|
||||
self.bodyText = bodyText
|
||||
@ -145,12 +263,12 @@ struct SecretAgentSetupView: View {
|
||||
let buttonAction: () -> Void
|
||||
|
||||
var body: some View {
|
||||
SetupStepView(title: .setupAgentTitle,
|
||||
SetupStepView(title: "setup_agent_title",
|
||||
image: Image(nsImage: NSApplication.shared.applicationIconImage),
|
||||
bodyText: .setupAgentDescription,
|
||||
buttonTitle: .setupAgentInstallButton,
|
||||
bodyText: "setup_agent_description",
|
||||
buttonTitle: "setup_agent_install_button",
|
||||
buttonAction: install) {
|
||||
Text(.setupAgentActivityMonitorDescription)
|
||||
Text("setup_agent_activity_monitor_description")
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
}
|
||||
@ -172,12 +290,12 @@ struct SSHAgentSetupView: View {
|
||||
@State private var selectedShellInstruction: ShellConfigInstruction = controller.shellInstructions.first!
|
||||
|
||||
var body: some View {
|
||||
SetupStepView(title: .setupSshTitle,
|
||||
SetupStepView(title: "setup_ssh_title",
|
||||
image: Image(systemName: "terminal"),
|
||||
bodyText: .setupSshDescription,
|
||||
buttonTitle: .setupSshAddedManuallyButton,
|
||||
bodyText: "setup_ssh_description",
|
||||
buttonTitle: "setup_ssh_added_manually_button",
|
||||
buttonAction: buttonAction) {
|
||||
Link(.setupThirdPartyFaqLink, destination: URL(string: "https://github.com/maxgoedjen/secretive/blob/main/APP_CONFIG.md")!)
|
||||
Link("setup_third_party_faq_link", destination: URL(string: "https://github.com/maxgoedjen/secretive/blob/main/APP_CONFIG.md")!)
|
||||
Picker(selection: $selectedShellInstruction, label: EmptyView()) {
|
||||
ForEach(SSHAgentSetupView.controller.shellInstructions) { instruction in
|
||||
Text(instruction.shell)
|
||||
@ -185,8 +303,8 @@ struct SSHAgentSetupView: View {
|
||||
.padding()
|
||||
}
|
||||
}.pickerStyle(SegmentedPickerStyle())
|
||||
CopyableView(title: .setupSshAddToConfigButton(configPath: selectedShellInstruction.shellConfigPath), image: Image(systemName: "greaterthan.square"), text: selectedShellInstruction.text)
|
||||
Button(.setupSshAddForMeButton) {
|
||||
CopyableView(title: "setup_ssh_add_to_config_button_\(selectedShellInstruction.shellConfigPath)", image: Image(systemName: "greaterthan.square"), text: selectedShellInstruction.text)
|
||||
Button("setup_ssh_add_for_me_button") {
|
||||
let controller = ShellConfigurationController()
|
||||
if controller.addToShell(shellInstructions: selectedShellInstruction) {
|
||||
buttonAction()
|
||||
@ -216,12 +334,12 @@ struct UpdaterExplainerView: View {
|
||||
let buttonAction: () -> Void
|
||||
|
||||
var body: some View {
|
||||
SetupStepView(title: .setupUpdatesTitle,
|
||||
SetupStepView(title: "setup_updates_title",
|
||||
image: Image(systemName: "dot.radiowaves.left.and.right"),
|
||||
bodyText: .setupUpdatesDescription,
|
||||
buttonTitle: .setupUpdatesOk,
|
||||
bodyText: "setup_updates_description",
|
||||
buttonTitle: "setup_updates_ok",
|
||||
buttonAction: buttonAction) {
|
||||
Link(.setupUpdatesReadmore, destination: SetupView.Constants.updaterFAQURL)
|
||||
Link("setup_updates_readmore", destination: SetupView.Constants.updaterFAQURL)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user