diff --git a/.gitignore b/.gitignore index 56c7c8a..bab7d6d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ goldwarden __pycache__ .flatpak-builder flatpak-pip-generator -repo \ No newline at end of file +repo +__debug* \ No newline at end of file diff --git a/agent/actions/logins.go b/agent/actions/logins.go index b2619bf..f472322 100644 --- a/agent/actions/logins.go +++ b/agent/actions/logins.go @@ -97,16 +97,16 @@ func handleGetLoginCipher(request messages.IPCMessage, cfg *config.Config, vault } func handleListLoginsRequest(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) { - if approved, err := pinentry.GetApproval("Access Vault", fmt.Sprintf("%s on %s>%s>%s is trying access ALL CREDENTIALS", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved { - response, err = messages.IPCMessageFromPayload(messages.ActionResponse{ - Success: false, - Message: "not approved", - }) - if err != nil { - return messages.IPCMessage{}, err - } - return response, nil - } + // if approved, err := pinentry.GetApproval("Access Vault", fmt.Sprintf("%s on %s>%s>%s is trying access ALL CREDENTIALS", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved { + // response, err = messages.IPCMessageFromPayload(messages.ActionResponse{ + // Success: false, + // Message: "not approved", + // }) + // if err != nil { + // return messages.IPCMessage{}, err + // } + // return response, nil + // } logins := vault.GetLogins() decryptedLoginCiphers := make([]messages.DecryptedLoginCipher, 0) diff --git a/agent/bitwarden/http.go b/agent/bitwarden/http.go index 610879f..2e6d1a7 100644 --- a/agent/bitwarden/http.go +++ b/agent/bitwarden/http.go @@ -10,7 +10,6 @@ import ( "io/ioutil" "net/http" "net/url" - "os" "strings" "time" ) @@ -114,7 +113,7 @@ func makeAuthenticatedHTTPRequest(ctx context.Context, req *http.Request, recv i return &errStatusCode{res.StatusCode, body} } if err := json.Unmarshal(body, recv); err != nil { - fmt.Fprintln(os.Stderr, string(body)) + fmt.Println(string(body)) return err } return nil diff --git a/agent/config/config.go b/agent/config/config.go index ac81136..9b5a77e 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -49,6 +49,7 @@ type RuntimeConfig struct { UseMemguard bool SSHAgentSocketPath string GoldwardenSocketPath string + DaemonAuthToken string } type ConfigFile struct { diff --git a/agent/sockets/callingcontext.go b/agent/sockets/callingcontext.go index 7453446..7516be7 100644 --- a/agent/sockets/callingcontext.go +++ b/agent/sockets/callingcontext.go @@ -17,6 +17,7 @@ type CallingContext struct { ParentProcessPid int GrandParentProcessPid int Error bool + Authenticated bool } func GetCallingContext(connection net.Conn) CallingContext { @@ -30,6 +31,7 @@ func GetCallingContext(connection net.Conn) CallingContext { ParentProcessPid: 0, GrandParentProcessPid: 0, Error: true, + Authenticated: false, } if err != nil { return errorContext diff --git a/agent/systemauth/pinentry/go-pinentry.go b/agent/systemauth/pinentry/go-pinentry.go index 8e96bca..673950a 100644 --- a/agent/systemauth/pinentry/go-pinentry.go +++ b/agent/systemauth/pinentry/go-pinentry.go @@ -8,7 +8,7 @@ import ( "github.com/twpayne/go-pinentry" ) -func GetPassword(title string, description string) (string, error) { +func getPassword(title string, description string) (string, error) { client, err := pinentry.NewClient( pinentry.WithBinaryNameFromGnuPGAgentConf(), pinentry.WithGPGTTY(), @@ -38,7 +38,7 @@ func GetPassword(title string, description string) (string, error) { } } -func GetApproval(title string, description string) (bool, error) { +func getApproval(title string, description string) (bool, error) { if systemAuthDisabled { return true, nil } diff --git a/agent/systemauth/pinentry/keybase-pinentry.go b/agent/systemauth/pinentry/keybase-pinentry.go index 605016f..88218ef 100644 --- a/agent/systemauth/pinentry/keybase-pinentry.go +++ b/agent/systemauth/pinentry/keybase-pinentry.go @@ -10,7 +10,7 @@ import ( pinentry "github.com/quexten/goldwarden/agent/systemauth/pinentry/keybase-pinentry" ) -func GetPassword(title string, description string) (string, error) { +func getPassword(title string, description string) (string, error) { pinentryInstance := pinentry.New("", logger.New(""), "") result, err := pinentryInstance.Get(keybase1.SecretEntryArg{ Prompt: title, @@ -28,7 +28,7 @@ func GetPassword(title string, description string) (string, error) { return result.Text, nil } -func GetApproval(title string, description string) (bool, error) { +func getApproval(title string, description string) (bool, error) { pinentryInstance := pinentry.New("", logger.New(""), "") result, err := pinentryInstance.Get(keybase1.SecretEntryArg{ Prompt: title, diff --git a/agent/systemauth/pinentry/pinentry.go b/agent/systemauth/pinentry/pinentry.go index 088e1f0..24c3ec1 100644 --- a/agent/systemauth/pinentry/pinentry.go +++ b/agent/systemauth/pinentry/pinentry.go @@ -1,6 +1,7 @@ package pinentry import ( + "errors" "os" "github.com/quexten/goldwarden/logging" @@ -9,8 +10,52 @@ import ( var log = logging.GetLogger("Goldwarden", "Pinentry") var systemAuthDisabled = false +type Pinentry struct { + GetPassword func(title string, description string) (string, error) + GetApproval func(title string, description string) (bool, error) +} + +var externalPinentry Pinentry = Pinentry{} + func init() { if os.Getenv("GOLDWARDEN_SYSTEM_AUTH_DISABLED") == "true" { systemAuthDisabled = true } } + +func SetExternalPinentry(pinentry Pinentry) error { + if externalPinentry.GetPassword != nil { + return errors.New("External pinentry already set") + } + + externalPinentry = pinentry + return nil +} + +func GetPassword(title string, description string) (string, error) { + password, err := getPassword(title, description) + if err == nil { + return password, nil + } + + if externalPinentry.GetPassword != nil { + return externalPinentry.GetPassword(title, description) + } + + // return "", errors.New("Not implemented") + return password, nil +} + +func GetApproval(title string, description string) (bool, error) { + approval, err := getApproval(title, description) + if err == nil { + return approval, nil + } + + if externalPinentry.GetApproval != nil { + return externalPinentry.GetApproval(title, description) + } + + // return true, errors.New("Not implemented") + return approval, nil +} diff --git a/agent/systemauth/pinentry/unimplemented.go b/agent/systemauth/pinentry/unimplemented.go index 9dd143c..a54a7fa 100644 --- a/agent/systemauth/pinentry/unimplemented.go +++ b/agent/systemauth/pinentry/unimplemented.go @@ -4,12 +4,12 @@ package pinentry import "errors" -func GetPassword(title string, description string) (string, error) { +func getPassword(title string, description string) (string, error) { log.Info("Asking for password is not implemented on this platform") return "", errors.New("Not implemented") } -func GetApproval(title string, description string) (bool, error) { +func getApproval(title string, description string) (bool, error) { log.Info("Asking for approval is not implemented on this platform") return true, errors.New("Not implemented") } diff --git a/agent/systemauth/systemauth.go b/agent/systemauth/systemauth.go index 78e2995..c3655ac 100644 --- a/agent/systemauth/systemauth.go +++ b/agent/systemauth/systemauth.go @@ -65,6 +65,10 @@ func (s *SessionStore) verifySession(ctx sockets.CallingContext, sessionType Ses // with session func GetPermission(sessionType SessionType, ctx sockets.CallingContext, config *config.Config) (bool, error) { + if ctx.Authenticated { + return true, nil + } + log.Info("Checking permission for " + ctx.ProcessName + " with session type " + string(sessionType)) var actionDescription = "" biometricsApprovalType := biometrics.AccessVault diff --git a/agent/unixsocketagent.go b/agent/unixsocketagent.go index 101007d..e80924c 100644 --- a/agent/unixsocketagent.go +++ b/agent/unixsocketagent.go @@ -16,6 +16,8 @@ import ( "github.com/quexten/goldwarden/agent/processsecurity" "github.com/quexten/goldwarden/agent/sockets" "github.com/quexten/goldwarden/agent/ssh" + "github.com/quexten/goldwarden/agent/systemauth" + "github.com/quexten/goldwarden/agent/systemauth/pinentry" "github.com/quexten/goldwarden/agent/vault" "github.com/quexten/goldwarden/ipc/messages" "github.com/quexten/goldwarden/logging" @@ -44,7 +46,7 @@ func writeError(c net.Conn, errMsg error) error { return nil } -func serveAgentSession(c net.Conn, ctx context.Context, vault *vault.Vault, cfg *config.Config) { +func serveAgentSession(c net.Conn, vault *vault.Vault, cfg *config.Config) { for { buf := make([]byte, 1024*1024) nr, err := c.Read(buf) @@ -61,7 +63,204 @@ func serveAgentSession(c net.Conn, ctx context.Context, vault *vault.Vault, cfg continue } - responseBytes := []byte{} + // todo refactor to other file + if msg.Type == messages.MessageTypeForEmptyPayload(messages.SessionAuthRequest{}) { + log.Info("Received session auth request") + req := messages.ParsePayload(msg).(messages.SessionAuthRequest) + fmt.Println("Daemontoken", cfg.ConfigFile.RuntimeConfig.DaemonAuthToken) + fmt.Println("Token", req.Token) + fmt.Println(len(cfg.ConfigFile.RuntimeConfig.DaemonAuthToken), len(req.Token)) + payload := messages.SessionAuthResponse{ + Verified: cfg.ConfigFile.RuntimeConfig.DaemonAuthToken == req.Token, + } + log.Info("Verified: %t", payload.Verified) + callingContext := sockets.GetCallingContext(c) + systemauth.CreatePinSession(callingContext) + + responsePayload, err := messages.IPCMessageFromPayload(payload) + if err != nil { + writeError(c, err) + continue + } + payloadBytes, err := json.Marshal(responsePayload) + if err != nil { + writeError(c, err) + continue + } + + _, err = c.Write(payloadBytes) + if err != nil { + log.Error("Failed writing to socket " + err.Error()) + } + continue + } + + // todo refactor to other file + if msg.Type == messages.MessageTypeForEmptyPayload(messages.PinentryRegistrationRequest{}) { + log.Info("Received pinentry registration request") + + getPasswordChan := make(chan struct { + title string + description string + }) + getPasswordReturnChan := make(chan struct { + password string + err error + }) + getApprovalChan := make(chan struct { + title string + description string + }) + getApprovalReturnChan := make(chan struct { + approved bool + err error + }) + + pe := pinentry.Pinentry{ + GetPassword: func(title string, description string) (string, error) { + getPasswordChan <- struct { + title string + description string + }{title, description} + returnValue := <-getPasswordReturnChan + return returnValue.password, returnValue.err + }, + GetApproval: func(title string, description string) (bool, error) { + getApprovalChan <- struct { + title string + description string + }{title, description} + returnValue := <-getApprovalReturnChan + return returnValue.approved, returnValue.err + }, + } + + pinnentrySetError := pinentry.SetExternalPinentry(pe) + payload := messages.PinentryRegistrationResponse{ + Success: pinnentrySetError == nil, + } + log.Info("Pinentry registration success: %t", payload.Success) + + responsePayload, err := messages.IPCMessageFromPayload(payload) + if err != nil { + writeError(c, err) + continue + } + payloadBytes, err := json.Marshal(responsePayload) + if err != nil { + writeError(c, err) + continue + } + + _, err = c.Write(payloadBytes) + if err != nil { + log.Error("Failed writing to socket " + err.Error()) + } + _, err = c.Write([]byte("\n")) + time.Sleep(50 * time.Millisecond) //todo fix properly + + if pinnentrySetError != nil { + return + } + + for { + fmt.Println("Waiting for pinentry request") + select { + case getPasswordRequest := <-getPasswordChan: + log.Info("Received getPassword request") + payload := messages.PinentryPinRequest{ + Message: getPasswordRequest.description, + } + payloadPayload, err := messages.IPCMessageFromPayload(payload) + if err != nil { + writeError(c, err) + continue + } + + payloadBytes, err := json.Marshal(payloadPayload) + if err != nil { + writeError(c, err) + continue + } + + _, err = c.Write(payloadBytes) + if err != nil { + log.Error("Failed writing to socket " + err.Error()) + } + + buf := make([]byte, 1024*1024) + nr, err := c.Read(buf) + if err != nil { + return + } + + data := buf[0:nr] + + var msg messages.IPCMessage + err = json.Unmarshal(data, &msg) + if err != nil { + writeError(c, err) + continue + } + + if msg.Type == messages.MessageTypeForEmptyPayload(messages.PinentryPinResponse{}) { + getPasswordResponse := messages.ParsePayload(msg).(messages.PinentryPinResponse) + getPasswordReturnChan <- struct { + password string + err error + }{getPasswordResponse.Pin, nil} + } + case getApprovalRequest := <-getApprovalChan: + log.Info("Received getApproval request") + payload := messages.PinentryApprovalRequest{ + Message: getApprovalRequest.description, + } + payloadPayload, err := messages.IPCMessageFromPayload(payload) + if err != nil { + writeError(c, err) + continue + } + + payloadBytes, err := json.Marshal(payloadPayload) + if err != nil { + writeError(c, err) + continue + } + + _, err = c.Write(payloadBytes) + if err != nil { + log.Error("Failed writing to socket " + err.Error()) + } + + buf := make([]byte, 1024*1024) + nr, err := c.Read(buf) + if err != nil { + return + } + + data := buf[0:nr] + + var msg messages.IPCMessage + err = json.Unmarshal(data, &msg) + if err != nil { + writeError(c, err) + continue + } + + if msg.Type == messages.MessageTypeForEmptyPayload(messages.PinentryApprovalResponse{}) { + getApprovalResponse := messages.ParsePayload(msg).(messages.PinentryApprovalResponse) + getApprovalReturnChan <- struct { + approved bool + err error + }{getApprovalResponse.Approved, nil} + } + } + } + + continue + } + + var responseBytes []byte if action, actionFound := actions.AgentActionsRegistry.Get(msg.Type); actionFound { callingContext := sockets.GetCallingContext(c) payload, err := action(msg, cfg, vault, &callingContext) @@ -291,7 +490,7 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error { l, err := net.Listen("unix", path) if err != nil { - println("listen error", err.Error()) + fmt.Println("listen error", err.Error()) return err } defer l.Close() @@ -301,10 +500,10 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error { for { fd, err := l.Accept() if err != nil { - println("accept error", err.Error()) + fmt.Println("accept error", err.Error()) } - go serveAgentSession(fd, ctx, vault, &cfg) + go serveAgentSession(fd, vault, &cfg) } }() diff --git a/agent/virtualagent.go b/agent/virtualagent.go deleted file mode 100644 index f6de33d..0000000 --- a/agent/virtualagent.go +++ /dev/null @@ -1,169 +0,0 @@ -package agent - -import ( - "context" - "encoding/json" - "fmt" - "os/user" - "time" - - "github.com/quexten/goldwarden/agent/actions" - "github.com/quexten/goldwarden/agent/bitwarden" - "github.com/quexten/goldwarden/agent/bitwarden/crypto" - "github.com/quexten/goldwarden/agent/config" - "github.com/quexten/goldwarden/agent/processsecurity" - "github.com/quexten/goldwarden/agent/sockets" - "github.com/quexten/goldwarden/agent/vault" - "github.com/quexten/goldwarden/ipc/messages" -) - -func writeErrorToLog(err error) { - log.Error(err.Error()) -} - -func serveVirtualAgent(recv chan []byte, send chan []byte, ctx context.Context, vault *vault.Vault, cfg *config.Config) { - for { - data := <-recv - - var msg messages.IPCMessage - err := json.Unmarshal(data, &msg) - if err != nil { - writeErrorToLog(err) - continue - } - - responseBytes := []byte{} - if action, actionFound := actions.AgentActionsRegistry.Get(msg.Type); actionFound { - user, _ := user.Current() - process := "goldwarden" - parent := "SINGLE_PROC_MODE" - grandparent := "SINGLE_PROC_MODE" - callingContext := sockets.CallingContext{ - UserName: user.Name, - ProcessName: process, - ParentProcessName: parent, - GrandParentProcessName: grandparent, - } - payload, err := action(msg, cfg, vault, &callingContext) - if err != nil { - writeErrorToLog(err) - continue - } - responseBytes, err = json.Marshal(payload) - if err != nil { - writeErrorToLog(err) - continue - } - } else { - payload := messages.ActionResponse{ - Success: false, - Message: "Action not found", - } - payloadBytes, err := json.Marshal(payload) - if err != nil { - writeErrorToLog(err) - continue - } - responseBytes = payloadBytes - } - - send <- responseBytes - } -} - -func StartVirtualAgent(runtimeConfig config.RuntimeConfig) (chan []byte, chan []byte) { - ctx := context.Background() - - var keyring crypto.Keyring - if runtimeConfig.UseMemguard { - keyring = crypto.NewMemguardKeyring(nil) - } else { - keyring = crypto.NewMemoryKeyring(nil) - } - - var vault = vault.NewVault(&keyring) - cfg, err := config.ReadConfig(runtimeConfig) - if err != nil { - var cfg = config.DefaultConfig(runtimeConfig.UseMemguard) - cfg.WriteConfig() - } - cfg.ConfigFile.RuntimeConfig = runtimeConfig - if cfg.ConfigFile.RuntimeConfig.ApiURI != "" { - cfg.ConfigFile.ApiUrl = cfg.ConfigFile.RuntimeConfig.ApiURI - } - if cfg.ConfigFile.RuntimeConfig.IdentityURI != "" { - cfg.ConfigFile.IdentityUrl = cfg.ConfigFile.RuntimeConfig.IdentityURI - } - if cfg.ConfigFile.RuntimeConfig.NotificationsURI != "" { - cfg.ConfigFile.NotificationsUrl = cfg.ConfigFile.RuntimeConfig.NotificationsURI - } - if cfg.ConfigFile.RuntimeConfig.DeviceUUID != "" { - cfg.ConfigFile.DeviceUUID = cfg.ConfigFile.RuntimeConfig.DeviceUUID - } - - if !cfg.IsLocked() && !cfg.ConfigFile.RuntimeConfig.DoNotPersistConfig { - log.Warn("Config is not locked. SET A PIN!!") - token, err := cfg.GetToken() - if err == nil { - if token.AccessToken != "" { - bitwarden.RefreshToken(ctx, &cfg) - userSymmetricKey, err := cfg.GetUserSymmetricKey() - if err != nil { - fmt.Println(err) - } - var protectedUserSymetricKey crypto.SymmetricEncryptionKey - if keyring.IsMemguard { - protectedUserSymetricKey, err = crypto.MemguardSymmetricEncryptionKeyFromBytes(userSymmetricKey) - } else { - protectedUserSymetricKey, err = crypto.MemorySymmetricEncryptionKeyFromBytes(userSymmetricKey) - } - - err = bitwarden.DoFullSync(context.WithValue(ctx, bitwarden.AuthToken{}, token.AccessToken), vault, &cfg, &protectedUserSymetricKey, true) - if err != nil { - fmt.Println(err) - } - } - } - } - processsecurity.DisableDumpable() - err = processsecurity.MonitorLocks(func() { - cfg.Lock() - vault.Clear() - vault.Keyring.Lock() - }) - if err != nil { - log.Warn("Could not monitor screensaver: %s", err.Error()) - } - - go func() { - for { - time.Sleep(TokenRefreshInterval) - if !cfg.IsLocked() { - bitwarden.RefreshToken(ctx, &cfg) - } - } - }() - - go func() { - for { - time.Sleep(FullSyncInterval) - if !cfg.IsLocked() { - token, err := cfg.GetToken() - if err != nil { - log.Warn("Could not get token: %s", err.Error()) - continue - } - - bitwarden.DoFullSync(context.WithValue(ctx, bitwarden.AuthToken{}, token.AccessToken), vault, &cfg, nil, false) - } - } - }() - - recv := make(chan []byte) - send := make(chan []byte) - - go func() { - go serveVirtualAgent(recv, send, ctx, vault, &cfg) - }() - return recv, send -} diff --git a/client/client.go b/client/client.go deleted file mode 100644 index c0ce142..0000000 --- a/client/client.go +++ /dev/null @@ -1,5 +0,0 @@ -package client - -type Client interface { - SendToAgent(request interface{}) (interface{}, error) -} diff --git a/client/unixsocketclient.go b/client/unixsocketclient.go index f24be0d..2b87ac9 100644 --- a/client/unixsocketclient.go +++ b/client/unixsocketclient.go @@ -3,7 +3,6 @@ package client import ( "encoding/json" "io" - "log" "net" "github.com/quexten/goldwarden/agent/config" @@ -16,13 +15,17 @@ type UnixSocketClient struct { runtimeConfig *config.RuntimeConfig } +type UnixSocketConnection struct { + conn net.Conn +} + func NewUnixSocketClient(runtimeConfig *config.RuntimeConfig) UnixSocketClient { return UnixSocketClient{ runtimeConfig: runtimeConfig, } } -func reader(r io.Reader) interface{} { +func Reader(r io.Reader) interface{} { buf := make([]byte, READ_BUFFER) for { n, err := r.Read(buf[:]) @@ -40,25 +43,49 @@ func reader(r io.Reader) interface{} { } func (client UnixSocketClient) SendToAgent(request interface{}) (interface{}, error) { - c, err := net.Dial("unix", client.runtimeConfig.GoldwardenSocketPath) + c, err := client.Connect() if err != nil { return nil, err } defer c.Close() - - message, err := messages.IPCMessageFromPayload(request) - if err != nil { - panic(err) - } - messageJson, err := json.Marshal(message) - if err != nil { - panic(err) - } - - _, err = c.Write(messageJson) - if err != nil { - log.Fatal("write error:", err) - } - result := reader(c) - return messages.ParsePayload(result.(messages.IPCMessage)), nil + return c.SendCommand(request) +} + +func (client UnixSocketClient) Connect() (UnixSocketConnection, error) { + c, err := net.Dial("unix", client.runtimeConfig.GoldwardenSocketPath) + if err != nil { + return UnixSocketConnection{}, err + } + return UnixSocketConnection{conn: c}, nil +} + +func (conn UnixSocketConnection) SendCommand(request interface{}) (interface{}, error) { + err := conn.WriteMessage(request) + if err != nil { + return nil, err + } + return conn.ReadMessage(), nil +} + +func (conn UnixSocketConnection) ReadMessage() interface{} { + result := Reader(conn.conn) + payload := messages.ParsePayload(result.(messages.IPCMessage)) + return payload +} + +func (conn UnixSocketConnection) WriteMessage(message interface{}) error { + messagePacket, err := messages.IPCMessageFromPayload(message) + if err != nil { + panic(err) + } + messageJson, err := json.Marshal(messagePacket) + if err != nil { + panic(err) + } + _, err = conn.conn.Write(messageJson) + return err +} + +func (conn UnixSocketConnection) Close() { + conn.conn.Close() } diff --git a/client/virtualclient.go b/client/virtualclient.go deleted file mode 100644 index 8113901..0000000 --- a/client/virtualclient.go +++ /dev/null @@ -1,45 +0,0 @@ -package client - -import ( - "encoding/json" - - "github.com/quexten/goldwarden/ipc/messages" -) - -func NewVirtualClient(recv chan []byte, send chan []byte) VirtualClient { - return VirtualClient{ - recv, - send, - } -} - -type VirtualClient struct { - recv chan []byte - send chan []byte -} - -func virtualReader(recv chan []byte) interface{} { - for { - var message messages.IPCMessage - err := json.Unmarshal(<-recv, &message) - if err != nil { - panic(err) - } - return message - } -} - -func (client VirtualClient) SendToAgent(request interface{}) (interface{}, error) { - message, err := messages.IPCMessageFromPayload(request) - if err != nil { - panic(err) - } - messageJson, err := json.Marshal(message) - if err != nil { - panic(err) - } - - client.send <- messageJson - result := virtualReader(client.recv) - return messages.ParsePayload(result.(messages.IPCMessage)), nil -} diff --git a/cmd/autofill.go b/cmd/autofill.go index c569e70..cf33b9d 100644 --- a/cmd/autofill.go +++ b/cmd/autofill.go @@ -10,9 +10,10 @@ import ( ) var autofillCmd = &cobra.Command{ - Use: "autotype", - Short: "Autotype credentials", - Long: `Autotype credentials`, + Hidden: true, + Use: "autotype", + Short: "Autotype credentials", + Long: `Autotype credentials`, Run: func(cmd *cobra.Command, args []string) { username, _ := cmd.Flags().GetString("username") // get pasword from env diff --git a/cmd/config.go b/cmd/config.go index 01812b0..a54ed02 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -1,6 +1,7 @@ package cmd import ( + "encoding/json" "fmt" "strings" @@ -30,12 +31,12 @@ var setApiUrlCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting api url failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting api url failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -63,12 +64,12 @@ var setIdentityURLCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting identity url failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting identity url failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -96,12 +97,12 @@ var setNotificationsURLCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting notifications url failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting notifications url failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -129,12 +130,12 @@ var setVaultURLCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting vault url failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting vault url failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -162,12 +163,12 @@ var setURLsAutomaticallyCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting urls automatically failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting urls automatically failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -188,14 +189,15 @@ var getEnvironmentCmd = &cobra.Command{ switch result := result.(type) { case messages.GetConfigEnvironmentResponse: - fmt.Println("{") - fmt.Println(" \"api\": \"" + result.ApiURL + "\",") - fmt.Println(" \"identity\": \"" + result.IdentityURL + "\",") - fmt.Println(" \"notifications\": \"" + result.NotificationsURL + "\",") - fmt.Println(" \"vault\": \"" + result.VaultURL + "\"") - fmt.Println("}") + response := map[string]string{} + response["api"] = result.ApiURL + response["identity"] = result.IdentityURL + response["notifications"] = result.NotificationsURL + response["vault"] = result.VaultURL + responseJSON, _ := json.Marshal(response) + fmt.Println(string(responseJSON)) default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, } @@ -226,12 +228,12 @@ var setApiClientIDCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting api client id failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting api client id failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -263,12 +265,12 @@ var setApiSecretCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Done") + fmt.Println("Done") } else { - println("Setting api secret failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Setting api secret failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, @@ -289,13 +291,14 @@ var getRuntimeConfigCmd = &cobra.Command{ switch result := result.(type) { case messages.GetRuntimeConfigResponse: - fmt.Println("{") - fmt.Println(" \"useMemguard\": " + fmt.Sprintf("%t", result.UseMemguard) + ",") - fmt.Println(" \"SSHAgentSocketPath\": \"" + result.SSHAgentSocketPath + "\",") - fmt.Println(" \"goldwardenSocketPath\": \"" + result.GoldwardenSocketPath + "\"") - fmt.Println("}") + response := map[string]interface{}{} + response["useMemguard"] = result.UseMemguard + response["SSHAgentSocketPath"] = result.SSHAgentSocketPath + response["goldwardenSocketPath"] = result.GoldwardenSocketPath + responseJSON, _ := json.Marshal(response) + fmt.Println(string(responseJSON)) default: - println("Wrong IPC response type") + fmt.Println("Wrong IPC response type") } }, } diff --git a/cmd/daemonize.go b/cmd/daemonize.go index 8f8dde1..8f4b9e9 100644 --- a/cmd/daemonize.go +++ b/cmd/daemonize.go @@ -19,11 +19,11 @@ var daemonizeCmd = &cobra.Command{ sshDisabled := runtimeConfig.DisableSSHAgent if websocketDisabled { - println("Websocket disabled") + fmt.Println("Websocket disabled") } if sshDisabled { - println("SSH agent disabled") + fmt.Println("SSH agent disabled") } cleanup := func() { diff --git a/cmd/login.go b/cmd/login.go index 746e97f..9fc53b2 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -4,6 +4,8 @@ Copyright © 2023 NAME HERE package cmd import ( + "fmt" + "github.com/quexten/goldwarden/ipc/messages" "github.com/spf13/cobra" ) @@ -17,7 +19,7 @@ var loginCmd = &cobra.Command{ request := messages.DoLoginRequest{} email, _ := cmd.Flags().GetString("email") if email == "" { - println("Error: No email specified") + fmt.Println("Error: No email specified") return } @@ -34,12 +36,12 @@ var loginCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Logged in") + fmt.Println("Logged in") } else { - println("Login failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Login failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong IPC response type for login") + fmt.Println("Wrong IPC response type for login") } }, } diff --git a/cmd/logins.go b/cmd/logins.go index 15b5c58..9f96a86 100644 --- a/cmd/logins.go +++ b/cmd/logins.go @@ -53,7 +53,7 @@ var getLoginCmd = &cobra.Command{ } break case messages.ActionResponse: - println("Error: " + resp.(messages.ActionResponse).Message) + fmt.Println("Error: " + resp.(messages.ActionResponse).Message) return } }, @@ -72,8 +72,8 @@ var listLoginsCmd = &cobra.Command{ return } - fmt.Println("[") - for index, login := range logins { + var toPrintLogins []map[string]string + for _, login := range logins { data := map[string]string{ "name": stringsx.Clean(login.Name), "uuid": stringsx.Clean(login.UUID), @@ -82,23 +82,14 @@ var listLoginsCmd = &cobra.Command{ "totp": stringsx.Clean(login.TOTPSeed), "uri": stringsx.Clean(login.URI), } - jsonString, err := json.Marshal(data) - if err != nil { - handleSendToAgentError(err) - return - } - fmt.Print(string(jsonString)) - if index != len(logins)-1 { - fmt.Println(",") - } else { - fmt.Println() - } + toPrintLogins = append(toPrintLogins, data) } - fmt.Println("]") + toPrintJSON, _ := json.Marshal(toPrintLogins) + fmt.Println(string(toPrintJSON)) }, } -func ListLogins(client client.Client) ([]messages.DecryptedLoginCipher, error) { +func ListLogins(client client.UnixSocketClient) ([]messages.DecryptedLoginCipher, error) { resp, err := client.SendToAgent(messages.ListLoginsRequest{}) if err != nil { return []messages.DecryptedLoginCipher{}, err diff --git a/cmd/pin.go b/cmd/pin.go index d039835..d495147 100644 --- a/cmd/pin.go +++ b/cmd/pin.go @@ -1,6 +1,8 @@ package cmd import ( + "fmt" + "github.com/quexten/goldwarden/ipc/messages" "github.com/spf13/cobra" ) @@ -25,12 +27,12 @@ var setPinCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Pin updated") + fmt.Println("Pin updated") } else { - println("Pin updating failed: " + result.(messages.ActionResponse).Message) + fmt.Println("Pin updating failed: " + result.(messages.ActionResponse).Message) } default: - println("Wrong response type") + fmt.Println("Wrong response type") } }, } @@ -48,9 +50,9 @@ var pinStatusCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: - println("Pin status: " + result.(messages.ActionResponse).Message) + fmt.Println("Pin status: " + result.(messages.ActionResponse).Message) default: - println("Wrong response type") + fmt.Println("Wrong response type") } }, } diff --git a/cmd/root.go b/cmd/root.go index f8e2931..888326a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,16 +1,16 @@ package cmd import ( + "fmt" "os" - "github.com/quexten/goldwarden/agent" "github.com/quexten/goldwarden/agent/config" "github.com/quexten/goldwarden/client" "github.com/quexten/goldwarden/ipc/messages" "github.com/spf13/cobra" ) -var commandClient client.Client +var commandClient client.UnixSocketClient var runtimeConfig config.RuntimeConfig var rootCmd = &cobra.Command{ @@ -24,13 +24,7 @@ var rootCmd = &cobra.Command{ func Execute(cfg config.RuntimeConfig) { runtimeConfig = cfg - goldwardenSingleProcess := os.Getenv("GOLDWARDEN_SINGLE_PROCESS") - if goldwardenSingleProcess == "true" { - recv, send := agent.StartVirtualAgent(runtimeConfig) - commandClient = client.NewVirtualClient(send, recv) - } else { - commandClient = client.NewUnixSocketClient(&cfg) - } + commandClient = client.NewUnixSocketClient(&cfg) err := rootCmd.Execute() if err != nil { @@ -62,8 +56,8 @@ func loginIfRequired() error { func handleSendToAgentError(err error) { if err != nil { - println("Error: " + err.Error()) - println("Is the daemon running?") + fmt.Println("Error: " + err.Error()) + fmt.Println("Is the daemon running?") return } } diff --git a/cmd/run.go b/cmd/run.go index dfb49c8..381d0c0 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -4,6 +4,7 @@ Copyright © 2023 NAME HERE package cmd import ( + "fmt" "os" "os/exec" @@ -19,7 +20,7 @@ var runCmd = &cobra.Command{ The variables are stored as a secure note. Consult the documentation for more information.`, Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { - println("Error: No command specified") + fmt.Println("Error: No command specified") return } @@ -43,7 +44,7 @@ var runCmd = &cobra.Command{ env = append(env, key+"="+value) } case messages.ActionResponse: - println("Error: " + result.(messages.ActionResponse).Message) + fmt.Println("Error: " + result.(messages.ActionResponse).Message) return } diff --git a/cmd/send.go b/cmd/send.go index aa098a0..388a535 100644 --- a/cmd/send.go +++ b/cmd/send.go @@ -39,7 +39,7 @@ var sendCreateCmd = &cobra.Command{ fmt.Println("Send created: " + result.(messages.CreateSendResponse).URL) break case messages.ActionResponse: - println("Error: " + result.(messages.ActionResponse).Message) + fmt.Println("Error: " + result.(messages.ActionResponse).Message) return } }, diff --git a/cmd/session.go b/cmd/session.go new file mode 100644 index 0000000..42daa1b --- /dev/null +++ b/cmd/session.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/quexten/goldwarden/ipc/messages" + "github.com/spf13/cobra" +) + +// sessionCmd represents the run command +var sessionCmd = &cobra.Command{ + Use: "session", + Hidden: true, + Short: "Starts a new session", + Long: `Starts a new session.`, + Run: func(cmd *cobra.Command, args []string) { + for { + reader := bufio.NewReader(os.Stdin) + text, _ := reader.ReadString('\n') + text = strings.TrimSuffix(text, "\n") + args := strings.Split(text, " ") + rootCmd.SetArgs(args) + rootCmd.Execute() + } + }, +} + +var pinentry = &cobra.Command{ + Use: "pinentry", + Hidden: true, + Short: "Registers as a pinentry program", + Long: `Registers as a pinentry program.`, + Run: func(cmd *cobra.Command, args []string) { + conn, err := commandClient.Connect() + if err != nil { + panic(err) + } + defer conn.Close() + _, err = conn.SendCommand(messages.PinentryRegistrationRequest{}) + if err != nil { + panic(err) + } + + for { + response := conn.ReadMessage() + switch response.(type) { + case messages.PinentryPinRequest: + fmt.Println("pin-request" + "," + response.(messages.PinentryPinRequest).Message) + case messages.PinentryApprovalRequest: + fmt.Println("approval-request" + "," + response.(messages.PinentryApprovalRequest).Message) + } + + // read line + reader := bufio.NewReader(os.Stdin) + text, _ := reader.ReadString('\n') + text = strings.TrimSuffix(text, "\n") + + switch response.(type) { + case messages.PinentryPinRequest: + err = conn.WriteMessage(messages.PinentryPinResponse{Pin: text}) + case messages.PinentryApprovalRequest: + err = conn.WriteMessage(messages.PinentryApprovalResponse{Approved: text == "true"}) + } + } + }, +} + +var authenticateSession = &cobra.Command{ + Use: "authenticate-session", + Hidden: true, + Short: "Authenticates a session", + Long: `Authenticates a session.`, + Run: func(cmd *cobra.Command, args []string) { + token := args[0] + response, err := commandClient.SendToAgent(messages.SessionAuthRequest{Token: token}) + if err != nil { + panic(err) + } + fmt.Println(response.(messages.SessionAuthResponse).Verified) + }, +} + +func init() { + rootCmd.AddCommand(sessionCmd) + rootCmd.AddCommand(pinentry) + rootCmd.AddCommand(authenticateSession) +} diff --git a/cmd/ssh.go b/cmd/ssh.go index 376892e..3bb74c7 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -47,7 +47,7 @@ var sshAddCmd = &cobra.Command{ } break case messages.ActionResponse: - println("Error: " + result.(messages.ActionResponse).Message) + fmt.Println("Error: " + result.(messages.ActionResponse).Message) return } }, @@ -74,7 +74,7 @@ var listSSHCmd = &cobra.Command{ } break case messages.ActionResponse: - println("Error: " + result.(messages.ActionResponse).Message) + fmt.Println("Error: " + result.(messages.ActionResponse).Message) return } }, diff --git a/cmd/vault.go b/cmd/vault.go index 0da79b3..305ed5d 100644 --- a/cmd/vault.go +++ b/cmd/vault.go @@ -1,6 +1,7 @@ package cmd import ( + "encoding/json" "fmt" "time" @@ -30,12 +31,12 @@ var unlockCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Unlocked") + fmt.Println("Unlocked") } else { - println("Not unlocked: " + result.(messages.ActionResponse).Message) + fmt.Println("Not unlocked: " + result.(messages.ActionResponse).Message) } default: - println("Wrong response type") + fmt.Println("Wrong response type") } }, } @@ -56,12 +57,12 @@ var lockCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Locked") + fmt.Println("Locked") } else { - println("Not locked: " + result.(messages.ActionResponse).Message) + fmt.Println("Not locked: " + result.(messages.ActionResponse).Message) } default: - println("Wrong response type") + fmt.Println("Wrong response type") } }, } @@ -82,12 +83,12 @@ var purgeCmd = &cobra.Command{ switch result.(type) { case messages.ActionResponse: if result.(messages.ActionResponse).Success { - println("Purged") + fmt.Println("Purged") } else { - println("Not purged: " + result.(messages.ActionResponse).Message) + fmt.Println("Not purged: " + result.(messages.ActionResponse).Message) } default: - println("Wrong response type") + fmt.Println("Wrong response type") } }, } @@ -107,18 +108,19 @@ var statusCmd = &cobra.Command{ switch result.(type) { case messages.VaultStatusResponse: + response := map[string]interface{}{} status := result.(messages.VaultStatusResponse) - fmt.Println("{") - fmt.Println(" \"locked\":", status.Locked, ",") - fmt.Println(" \"loginEntries\":", status.NumberOfLogins, ",") - fmt.Println(" \"noteEntries\":", status.NumberOfNotes, ",") - fmt.Println(" \"lastSynced\": \"" + time.Unix(status.LastSynced, 0).String() + "\",") - fmt.Println(" \"websocketConnected\":", status.WebsockedConnected, ",") - fmt.Println(" \"pinSet\":", status.PinSet, ",") - fmt.Println(" \"loggedIn\":", status.LoggedIn) - fmt.Println("}") + response["locked"] = status.Locked + response["loginEntries"] = status.NumberOfLogins + response["noteEntries"] = status.NumberOfNotes + response["lastSynced"] = time.Unix(status.LastSynced, 0).String() + response["websocketConnected"] = status.WebsockedConnected + response["pinSet"] = status.PinSet + response["loggedIn"] = status.LoggedIn + responseJSON, _ := json.Marshal(response) + fmt.Println(string(responseJSON)) default: - println("Wrong response type") + fmt.Println("Wrong response type") } }, } diff --git a/com.quexten.Goldwarden.yml b/com.quexten.Goldwarden.yml index b5f4d70..8346b58 100644 --- a/com.quexten.Goldwarden.yml +++ b/com.quexten.Goldwarden.yml @@ -2,7 +2,7 @@ id: com.quexten.Goldwarden runtime: org.gnome.Platform runtime-version: '45' sdk: org.gnome.Sdk -command: main.py +command: goldwarden_ui_main.py finish-args: # Allow network access for sync - --share=network @@ -28,7 +28,7 @@ finish-args: # biometric / user password auth - --system-talk-name=org.freedesktop.PolicyKit1 modules: - - ./ui/python3-requirements.json + - ./gui/python3-requirements.json - name: wl-clipboard buildsystem: meson config-opts: @@ -40,18 +40,18 @@ modules: - name: goldwarden-python-ui buildsystem: simple build-commands: - - cp -R ./ui/* /app/bin - - chmod +x /app/bin/main.py - - install -D ./ui/com.quexten.Goldwarden.desktop /app/share/applications/com.quexten.Goldwarden.desktop - - install -D ./ui/goldwarden.svg /app/share/icons/hicolor/scalable/apps/com.quexten.Goldwarden.svg - - install -Dm644 ./ui/com.quexten.Goldwarden.metainfo.xml -t /app/share/metainfo/ + - cp -R ./gui/* /app/bin + - chmod +x /app/bin/goldwarden_ui_main.py + - install -D ./gui/com.quexten.Goldwarden.desktop /app/share/applications/com.quexten.Goldwarden.desktop + - install -D ./gui/goldwarden.svg /app/share/icons/hicolor/scalable/apps/com.quexten.Goldwarden.svg + - install -Dm644 ./gui/com.quexten.Goldwarden.metainfo.xml -t /app/share/metainfo/ sources: - type: dir path: ./ - name: goldwarden-core-daemon buildsystem: simple build-commands: - - install -D goldwarden /app/bin/goldwarden + - install -D goldwarden /app/bin/src/goldwarden sources: - type: file path: ./goldwarden \ No newline at end of file diff --git a/ui/com.quexten.Goldwarden.desktop b/gui/com.quexten.Goldwarden.desktop similarity index 89% rename from ui/com.quexten.Goldwarden.desktop rename to gui/com.quexten.Goldwarden.desktop index 8b2af0b..5df1eb5 100644 --- a/ui/com.quexten.Goldwarden.desktop +++ b/gui/com.quexten.Goldwarden.desktop @@ -2,7 +2,7 @@ Name=Goldwarden Comment=A Bitwarden compatible desktop password manager Keywords=password;ssh;auto-type;keys; -Exec=main.py +Exec=goldwarden_ui_main.py Terminal=false Type=Application Icon=com.quexten.Goldwarden diff --git a/ui/com.quexten.Goldwarden.metainfo.xml b/gui/com.quexten.Goldwarden.metainfo.xml similarity index 100% rename from ui/com.quexten.Goldwarden.metainfo.xml rename to gui/com.quexten.Goldwarden.metainfo.xml diff --git a/ui/goldwarden.svg b/gui/goldwarden.svg similarity index 100% rename from ui/goldwarden.svg rename to gui/goldwarden.svg diff --git a/gui/goldwarden_ui_main.py b/gui/goldwarden_ui_main.py new file mode 100644 index 0000000..d6df4d2 --- /dev/null +++ b/gui/goldwarden_ui_main.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +import src.linux.main as linux_main + +linux_main.main() \ No newline at end of file diff --git a/gui/python3-requirements.json b/gui/python3-requirements.json new file mode 100644 index 0000000..1989579 --- /dev/null +++ b/gui/python3-requirements.json @@ -0,0 +1,14 @@ +{ + "name": "python3-tendo", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"tendo==0.3.0\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/ce/3f/761077d55732b0b1a673b15d4fdaa947a7c1eb5c9a23b7142df557019823/tendo-0.3.0-py3-none-any.whl", + "sha256": "026b70b355ea4c9da7c2123fa2d5c280c8983c1b34e329ff49260e2e78b93be7" + } + ] +} \ No newline at end of file diff --git a/gui/requirements.txt b/gui/requirements.txt new file mode 100644 index 0000000..66aeab9 --- /dev/null +++ b/gui/requirements.txt @@ -0,0 +1 @@ +tendo==0.3.0 \ No newline at end of file diff --git a/ui/components.py b/gui/src/gui/components.py similarity index 100% rename from ui/components.py rename to gui/src/gui/components.py diff --git a/gui/src/gui/pinentry.py b/gui/src/gui/pinentry.py new file mode 100644 index 0000000..a1abb0a --- /dev/null +++ b/gui/src/gui/pinentry.py @@ -0,0 +1,69 @@ +import gi +gi.require_version('Gtk', '4.0') +gi.require_version('Adw', '1') +import gc +import time +from gi.repository import Gtk, Adw, GLib, Notify, Gdk +from threading import Thread +import sys +import os + +message = sys.stdin.readline() + +class MyApp(Adw.Application): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.connect('activate', self.on_activate) + + def on_activate(self, app): + self.pinentry_window = MainWindow(application=app) + self.pinentry_window.present() + self.app = app + +class MainWindow(Gtk.ApplicationWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.stack = Gtk.Stack() + self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) + self.set_child(self.stack) + + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) + self.stack.add_child(box) + + label = Gtk.Label(label=message) + box.append(label) + + # Create the password entry + self.password_entry = Gtk.Entry() + self.password_entry.set_placeholder_text("Enter your password") + self.password_entry.set_visibility(False) # Hide the password + box.append(self.password_entry) + + # Create a button box for cancel and approve buttons + button_box = Gtk.Box(spacing=6) + box.append(button_box) + + # Cancel button + cancel_button = Gtk.Button(label="Cancel") + cancel_button.set_hexpand(True) # Make the button expand horizontally + def on_cancel_button_clicked(button): + print("", flush=True) + os._exit(0) + cancel_button.connect("clicked", on_cancel_button_clicked) + button_box.append(cancel_button) + + # Approve button + approve_button = Gtk.Button(label="Approve") + approve_button.set_hexpand(True) # Make the button expand horizontally + def on_approve_button_clicked(button): + print(self.password_entry.get_text(), flush=True) + os._exit(0) + approve_button.connect("clicked", on_approve_button_clicked) + button_box.append(approve_button) + + self.set_default_size(700, 200) + self.set_title("Goldwarden Pinentry") + +app = MyApp(application_id="com.quexten.Goldwarden.pinentry") +app.run(sys.argv) \ No newline at end of file diff --git a/gui/src/gui/pinentry_approval.py b/gui/src/gui/pinentry_approval.py new file mode 100644 index 0000000..17bd2e2 --- /dev/null +++ b/gui/src/gui/pinentry_approval.py @@ -0,0 +1,63 @@ +import gi +gi.require_version('Gtk', '4.0') +gi.require_version('Adw', '1') +import gc +import time +from gi.repository import Gtk, Adw, GLib, Notify, Gdk +from threading import Thread +import sys +import os + +message = sys.stdin.readline() + +class MyApp(Adw.Application): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.connect('activate', self.on_activate) + + def on_activate(self, app): + self.pinentry_window = MainWindow(application=app) + self.pinentry_window.present() + self.app = app + +class MainWindow(Gtk.ApplicationWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.stack = Gtk.Stack() + self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) + self.set_child(self.stack) + + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) + self.stack.add_child(box) + + label = Gtk.Label(label=message) + box.append(label) + + # Create a button box for cancel and approve buttons + button_box = Gtk.Box(spacing=6) + box.append(button_box) + + # Cancel button + cancel_button = Gtk.Button(label="Cancel") + cancel_button.set_hexpand(True) # Make the button expand horizontally + def on_cancel_button_clicked(button): + print("false", flush=True) + os._exit(0) + cancel_button.connect("clicked", on_cancel_button_clicked) + button_box.append(cancel_button) + + # Approve button + approve_button = Gtk.Button(label="Approve") + approve_button.set_hexpand(True) # Make the button expand horizontally + def on_approve_button_clicked(button): + print("true", flush=True) + os._exit(0) + approve_button.connect("clicked", on_approve_button_clicked) + button_box.append(approve_button) + + self.set_default_size(700, 200) + self.set_title("Goldwarden Approval") + +app = MyApp(application_id="com.quexten.Goldwarden.pinentry") +app.run(sys.argv) \ No newline at end of file diff --git a/ui/autofill.py b/gui/src/gui/quickaccess.py similarity index 92% rename from ui/autofill.py rename to gui/src/gui/quickaccess.py index 3e696d6..2163349 100644 --- a/ui/autofill.py +++ b/gui/src/gui/quickaccess.py @@ -4,28 +4,36 @@ gi.require_version('Adw', '1') import gc import time from gi.repository import Gtk, Adw, GLib, Notify, Gdk -import goldwarden -import clipboard +from ..services import goldwarden +from ..linux import clipboard from threading import Thread import sys import os -import totp +from ..services import totp Notify.init("Goldwarden") +token = sys.stdin.readline() +goldwarden.create_authenticated_connection(token) + class MyApp(Adw.Application): def __init__(self, **kwargs): super().__init__(**kwargs) self.connect('activate', self.on_activate) - def on_activate(self, app): - self.autofill_window = MainWindow(application=app) - self.autofill_window.logins = [] - self.autofill_window.present() + def update_logins(self): logins = goldwarden.get_vault_logins() if logins == None: os._exit(0) return - app.autofill_window.logins = logins + self.app.autofill_window.logins = logins + + def on_activate(self, app): + self.autofill_window = MainWindow(application=app) + self.autofill_window.logins = [] + self.autofill_window.present() + self.app = app + thread = Thread(target=self.update_logins) + thread.start() class MainWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): @@ -85,6 +93,9 @@ class MainWindow(Gtk.ApplicationWindow): keycont = Gtk.EventControllerKey() def handle_keypress(cotroller, keyval, keycode, state, user_data): + # if ctrl is pressed + if state == 4: + print("ctrl") if keycode == 36: print("enter") self.hide() @@ -130,7 +141,7 @@ class MainWindow(Gtk.ApplicationWindow): self.history_list.get_style_context().add_class("boxed-list") self.box.append(self.history_list) self.set_default_size(700, 700) - self.set_title("Goldwarden") + self.set_title("Goldwarden Quick Access") app = MyApp(application_id="com.quexten.Goldwarden.autofill-menu") app.run(sys.argv) \ No newline at end of file diff --git a/ui/settings.py b/gui/src/gui/settings.py similarity index 96% rename from ui/settings.py rename to gui/src/gui/settings.py index b122e7d..6af226b 100644 --- a/ui/settings.py +++ b/gui/src/gui/settings.py @@ -6,12 +6,16 @@ gi.require_version('Adw', '1') import gc from gi.repository import Gtk, Adw, GLib, Gdk -import goldwarden +from ..services import goldwarden from threading import Thread import subprocess -import components +from . import components import os +root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir)) +token = sys.stdin.readline() +goldwarden.create_authenticated_connection(None) + class SettingsWinvdow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -46,7 +50,11 @@ class SettingsWinvdow(Gtk.ApplicationWindow): self.autotype_button = Gtk.Button() self.autotype_button.set_label("Quick Access") self.autotype_button.set_margin_top(10) - self.autotype_button.connect("clicked", lambda button: subprocess.Popen(["python3", "/app/bin/autofill.py"], start_new_session=True)) + def quickaccess_button_clicked(): + p = subprocess.Popen(["python3", "-m", "src.gui.quickaccess"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{token}\n".encode()) + p.stdin.flush() + self.autotype_button.connect("clicked", lambda button: quickaccess_button_clicked()) self.autotype_button.get_style_context().add_class("suggested-action") self.action_preferences_group.add(self.autotype_button) @@ -201,6 +209,7 @@ class SettingsWinvdow(Gtk.ApplicationWindow): pin_set = goldwarden.is_pin_enabled() status = goldwarden.get_vault_status() + print("status", status) runtimeCfg = goldwarden.get_runtime_config() if runtimeCfg != None: self.ssh_row.set_subtitle("Listening at "+runtimeCfg["SSHAgentSocketPath"]) diff --git a/ui/autotype/autotype.py b/gui/src/linux/autotype/libportal_autotype.py similarity index 100% rename from ui/autotype/autotype.py rename to gui/src/linux/autotype/libportal_autotype.py diff --git a/ui/background.py b/gui/src/linux/background.py similarity index 100% rename from ui/background.py rename to gui/src/linux/background.py diff --git a/ui/clipboard.py b/gui/src/linux/clipboard.py similarity index 100% rename from ui/clipboard.py rename to gui/src/linux/clipboard.py diff --git a/gui/src/linux/main.py b/gui/src/linux/main.py new file mode 100644 index 0000000..15e90fd --- /dev/null +++ b/gui/src/linux/main.py @@ -0,0 +1,55 @@ +#!/usr/bin/python +import time +import subprocess +from tendo import singleton +from .monitors import dbus_autofill_monitor +from .monitors import dbus_monitor +import sys +from src.services import goldwarden +from src.services import pinentry +from threading import Thread +import os +import secrets +import time +import os + +root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir)) +is_flatpak = os.path.exists("/.flatpak-info") + +def main(): + token = secrets.token_hex(32) + if not os.environ.get("GOLDWARDEN_DAEMON_AUTH_TOKEN") == None: + token = os.environ["GOLDWARDEN_DAEMON_AUTH_TOKEN"] + + # check if already running + try: + me = singleton.SingleInstance() + except: + import dbus + + bus = dbus.SessionBus() + the_object = bus.get_object("com.quexten.Goldwarden.gui", "/com/quexten/Goldwarden/gui") + the_interface = dbus.Interface(the_object, "com.quexten.Goldwarden.gui.actions") + reply = the_interface.settings() + exit() + + goldwarden.run_daemon_background(token) + # start daemons + dbus_autofill_monitor.run_daemon(token) # todo: remove after migration + dbus_monitor.run_daemon(token) + pinentry.daemonize() + + if not "--hidden" in sys.argv: + p = subprocess.Popen(["python3", "-m", "src.gui.settings"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{token}\n".encode()) + p.stdin.flush() + + if is_flatpak: + # to autostart the appes + try: + subprocess.Popen(["python3", f'{source_path}/background.py'], start_new_session=True) + except Exception as e: + pass + + while True: + time.sleep(60) diff --git a/ui/monitors/dbus_autofill_monitor.py b/gui/src/linux/monitors/dbus_autofill_monitor.py similarity index 67% rename from ui/monitors/dbus_autofill_monitor.py rename to gui/src/linux/monitors/dbus_autofill_monitor.py index bdc0dcc..d050eaf 100644 --- a/ui/monitors/dbus_autofill_monitor.py +++ b/gui/src/linux/monitors/dbus_autofill_monitor.py @@ -10,7 +10,7 @@ import dbus.service from dbus.mainloop.glib import DBusGMainLoop from threading import Thread -on_autofill = lambda: None +daemon_token = None class GoldwardenDBUSService(dbus.service.Object): def __init__(self): @@ -19,11 +19,20 @@ class GoldwardenDBUSService(dbus.service.Object): @dbus.service.method('com.quexten.Goldwarden.Autofill') def autofill(self): - on_autofill() + p = subprocess.Popen(["python3", "-m", "src.gui.quickaccess"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{daemon_token}\n".encode()) + p.stdin.flush() return "" -def run_daemon(): +def daemon(): DBusGMainLoop(set_as_default=True) service = GoldwardenDBUSService() from gi.repository import GLib, GObject as gobject gobject.MainLoop().run() + +def run_daemon(token): + global daemon_token + daemon_token = token + thread = Thread(target=daemon) + thread.start() + \ No newline at end of file diff --git a/gui/src/linux/monitors/dbus_monitor.py b/gui/src/linux/monitors/dbus_monitor.py new file mode 100644 index 0000000..766fb85 --- /dev/null +++ b/gui/src/linux/monitors/dbus_monitor.py @@ -0,0 +1,41 @@ +from gi.repository import Gtk +import dbus +import dbus.service +from dbus.mainloop.glib import DBusGMainLoop +from threading import Thread +import subprocess +import os + +root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir, os.pardir)) +daemon_token = None + +class GoldwardenDBUSService(dbus.service.Object): + def __init__(self): + bus_name = dbus.service.BusName('com.quexten.Goldwarden.gui', bus=dbus.SessionBus()) + dbus.service.Object.__init__(self, bus_name, '/com/quexten/Goldwarden/gui') + + @dbus.service.method('com.quexten.Goldwarden.gui.actions') + def quickaccess(self): + p = subprocess.Popen(["python3", "-m", "src.gui.quickaccess"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{daemon_token}\n".encode()) + p.stdin.flush() + return "" + + @dbus.service.method('com.quexten.Goldwarden.gui.actions') + def settings(self): + p = subprocess.Popen(["python3", "-m", "src.gui.settings"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{daemon_token}\n".encode()) + p.stdin.flush() + return "" + +def daemon(): + DBusGMainLoop(set_as_default=True) + service = GoldwardenDBUSService() + from gi.repository import GLib, GObject as gobject + gobject.MainLoop().run() + +def run_daemon(token): + global daemon_token + daemon_token = token + thread = Thread(target=daemon) + thread.start() \ No newline at end of file diff --git a/ui/monitors/global_shortcut_portal.py b/gui/src/linux/monitors/global_shortcut_portal.py similarity index 100% rename from ui/monitors/global_shortcut_portal.py rename to gui/src/linux/monitors/global_shortcut_portal.py diff --git a/gui/src/services/goldwarden.py b/gui/src/services/goldwarden.py new file mode 100644 index 0000000..4937412 --- /dev/null +++ b/gui/src/services/goldwarden.py @@ -0,0 +1,196 @@ +import subprocess +import json +import os +from pathlib import Path +from threading import Thread + +is_flatpak = os.path.exists("/.flatpak-info") +log_directory = str(Path.home()) + "/.local/share/goldwarden" +if is_flatpak: + log_directory = str(Path.home()) + "/.var/app/com.quexten.goldwarden/data/goldwarden" +os.makedirs(log_directory, exist_ok=True) + +BINARY_PATHS = [ + "/app/bin/goldwarden", + "/usr/bin/goldwarden", + str(Path.home()) + "/go/src/github.com/quexten/goldwarden/goldwarden" +] + +BINARY_PATH = "" +BINARY_PATH = None +for path in BINARY_PATHS: + if os.path.exists(path): + BINARY_PATH = path + break +if BINARY_PATH == None: + raise Exception("Could not find goldwarden binary") +authenticated_connection = None + +def create_authenticated_connection(token): + global authenticated_connection + authenticated_connection = subprocess.Popen([f"{BINARY_PATH}", "session"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + if not token == None: + authenticated_connection.stdin.write("authenticate-session " + token + "\n") + authenticated_connection.stdin.flush() + # read entire message + result = authenticated_connection.stdout.readline() + if "true" not in result: + raise Exception("Failed to authenticate") + +def send_authenticated_command(cmd): + if authenticated_connection == None: + print("No daemon connection running, please restart the application completely.") + return "" + + authenticated_connection.stdin.write(cmd + "\n") + authenticated_connection.stdin.flush() + result = authenticated_connection.stdout.readline() + return result + +def set_api_url(url): + send_authenticated_command(f"config set-api-url {url}") + +def set_identity_url(url): + send_authenticated_command(f"config set-identity-url {url}") + +def set_notification_url(url): + send_authenticated_command(f"config set-notifications-url {url}") + +def set_vault_url(url): + send_authenticated_command(f"config set-vault-url {url}") + +def set_url(url): + send_authenticated_command(f"config set-url {url}") + +def get_environment(): + result = send_authenticated_command(f"config get-environment") + try: + return json.loads(result) + except Exception as e: + return None + +def set_client_id(client_id): + send_authenticated_command(f"config set-client-id \"{client_id}\"") + +def set_client_secret(client_secret): + send_authenticated_command(f"config set-client-secret \"{client_secret}\"") + +def login_with_password(email, password): + result = send_authenticated_command(f"vault login --email {email}") + if result.returncode != 0: + raise Exception("Failed to initialize repository, err", result.stderr) + if len(result.stderr.strip()) > 0: + print(result.stderr) + if "password" in result.stderr: + return "badpass" + else: + if "Logged in" in result.stderr: + print("ok") + return "ok" + return "error" + print("ok") + return "ok" + +def login_passwordless(email): + send_authenticated_command(f"vault login --email {email} --passwordless") + +def is_pin_enabled(): + result = send_authenticated_command("vault pin status") + return "enabled" in result + +def enable_pin(): + send_authenticated_command(f"vault pin set") + +def unlock(): + send_authenticated_command(f"vault unlock") + +def lock(): + send_authenticated_command(f"vault lock") + +def purge(): + send_authenticated_command(f"vault purge") + +def get_vault_status(): + result = send_authenticated_command(f"vault status") + try: + return json.loads(result) + except Exception as e: + return None + +def get_vault_logins(): + result = send_authenticated_command(f"logins list") + try: + return json.loads(result) + except Exception as e: + return None + +def get_runtime_config(): + result = send_authenticated_command(f"config get-runtime-config") + try: + return json.loads(result) + except Exception as e: + return None + +def autotype(username, password): + env = os.environ.copy() + # todo convert to stdin + env["PASSWORD"] = password + goldwarden_cmd = f"{BINARY_PATH} autotype --username {username}" + result = subprocess.run(goldwarden_cmd.split(), capture_output=True, text=True, env=env) + print(result.stderr) + print(result.stdout) + if result.returncode != 0: + raise Exception("Failed to initialize repository, err", result.stderr) + +def is_daemon_running(): + result = send_authenticated_command(f"vault status") + daemon_not_running = ("daemon running" in result) + return not daemon_not_running + +def listen_for_pinentry(on_pinentry, on_pin_approval): + print("listening for pinentry", BINARY_PATH) + pinentry_process = subprocess.Popen([f"{BINARY_PATH}", "pinentry"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + while True: + line = pinentry_process.stdout.readline() + # starts with pin-request + if line.startswith("pin-request"): + text = line.split(",")[1].strip() + pin = on_pinentry(text) + if pin == None: + pin = "" + pinentry_process.stdin.write(pin + "\n") + pinentry_process.stdin.flush() + if line.startswith("approval-request"): + text = line.split(",")[1].strip() + approval = on_pin_approval(text) + if approval: + pinentry_process.stdin.write("true\n") + pinentry_process.stdin.flush() + else: + pinentry_process.stdin.write("false\n") + pinentry_process.stdin.flush() + +def run_daemon(token): + #todo replace with stdin + daemon_env = os.environ.copy() + daemon_env["GOLDWARDEN_DAEMON_AUTH_TOKEN"] = token + + print("starting goldwarden daemon", BINARY_PATH) + + # print while running + result = subprocess.Popen([f"{BINARY_PATH}", "daemonize"], stdout=subprocess.PIPE, text=True, env=daemon_env) + + # write log to file until process exits + log_file = open(f"{log_directory}/daemon.log", "w") + while result.poll() == None: + # read stdout and stder + stdout = result.stdout.readline() + log_file.write(stdout) + log_file.flush() + log_file.close() + print("quitting goldwarden daemon") + return result.returncode + +def run_daemon_background(token): + thread = Thread(target=lambda: run_daemon(token)) + thread.start() \ No newline at end of file diff --git a/gui/src/services/pinentry.py b/gui/src/services/pinentry.py new file mode 100644 index 0000000..b8920f0 --- /dev/null +++ b/gui/src/services/pinentry.py @@ -0,0 +1,34 @@ +import subprocess +import os +from src.services import goldwarden +from threading import Thread +import time + +root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir)) + +def get_pin(message): + p = subprocess.Popen(["python3", "-m", "src.gui.pinentry"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{message}\n".encode()) + p.stdin.flush() + pin = p.stdout.readline().decode().strip() + if pin == "": + return None + return pin + +def get_approval(message): + p = subprocess.Popen(["python3", "-m", "src.gui.pinentry_approval"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True) + p.stdin.write(f"{message}\n".encode()) + p.stdin.flush() + result = p.stdout.readline().decode().strip() + if result == "true": + return True + return False + +def daemon(): + goldwarden.listen_for_pinentry(get_pin, get_approval) + +def daemonize(): + #todo fix this + time.sleep(3) + thread = Thread(target=daemon) + thread.start() \ No newline at end of file diff --git a/ui/totp.py b/gui/src/services/totp.py similarity index 100% rename from ui/totp.py rename to gui/src/services/totp.py diff --git a/ui/style.css b/gui/style.css similarity index 100% rename from ui/style.css rename to gui/style.css diff --git a/ipc/messages/session.go b/ipc/messages/session.go new file mode 100644 index 0000000..7b76149 --- /dev/null +++ b/ipc/messages/session.go @@ -0,0 +1,108 @@ +package messages + +import "encoding/json" + +type SessionAuthRequest struct { + Token string +} + +type SessionAuthResponse struct { + Verified bool +} + +type PinentryRegistrationRequest struct { +} + +type PinentryRegistrationResponse struct { + Success bool +} + +type PinentryPinRequest struct { + Message string +} + +type PinentryPinResponse struct { + Pin string +} + +type PinentryApprovalRequest struct { + Message string +} + +type PinentryApprovalResponse struct { + Approved bool +} + +func init() { + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req SessionAuthRequest + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, SessionAuthRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req SessionAuthResponse + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, SessionAuthResponse{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req PinentryRegistrationRequest + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, PinentryRegistrationRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req PinentryRegistrationResponse + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, PinentryRegistrationResponse{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req PinentryPinRequest + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, PinentryPinRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req PinentryPinResponse + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, PinentryPinResponse{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req PinentryApprovalRequest + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, PinentryApprovalRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req PinentryApprovalResponse + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, PinentryApprovalResponse{}) +} diff --git a/main.go b/main.go index 4c84457..29e81ae 100644 --- a/main.go +++ b/main.go @@ -36,6 +36,7 @@ func main() { UseMemguard: os.Getenv("GOLDWARDEN_NO_MEMGUARD") != "true", SSHAgentSocketPath: os.Getenv("GOLDWARDEN_SSH_AUTH_SOCK"), GoldwardenSocketPath: os.Getenv("GOLDWARDEN_SOCKET_PATH"), + DaemonAuthToken: os.Getenv("GOLDWARDEN_DAEMON_AUTH_TOKEN"), ConfigDirectory: configPath, } @@ -62,7 +63,6 @@ func main() { userHome, _ := os.UserHomeDir() runtimeConfig.ConfigDirectory = userHome + "/.var/app/com.quexten.Goldwarden/config/goldwarden.json" runtimeConfig.ConfigDirectory = strings.ReplaceAll(runtimeConfig.ConfigDirectory, "~", userHome) - println("Flatpak Config directory: " + runtimeConfig.ConfigDirectory) runtimeConfig.SSHAgentSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/ssh-auth-sock" runtimeConfig.GoldwardenSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock" } diff --git a/ui/main.py b/ui/main.py deleted file mode 100644 index 978722f..0000000 --- a/ui/main.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/python -import time -import subprocess -from tendo import singleton -import monitors.dbus_autofill_monitor -import sys -import goldwarden -from threading import Thread -import os - -isflatpak = os.path.exists("/.flatpak-info") -pathprefix = "/app/bin/" if isflatpak else "./" - -try: - subprocess.Popen(["python3", f'{pathprefix}background.py'], start_new_session=True) -except: - pass - -is_hidden = "--hidden" in sys.argv - -if not is_hidden: - try: - subprocess.Popen(["python3", f'{pathprefix}settings.py'], start_new_session=True) - except: - subprocess.Popen(["python3", f'{pathprefix}settings.py'], start_new_session=True) - pass - -try: - me = singleton.SingleInstance() -except: - exit() - -def run_daemon(): - # todo: do a proper check - if is_hidden: - time.sleep(20) - print("IS daemon running", goldwarden.is_daemon_running()) - if not goldwarden.is_daemon_running(): - print("running daemon") - goldwarden.run_daemon() - print("daemon running") - -thread = Thread(target=run_daemon) -thread.start() - -def on_autofill(): - subprocess.Popen(["python3", f'{pathprefix}autofill.py'], start_new_session=True) - -monitors.dbus_autofill_monitor.on_autofill = lambda: on_autofill() -monitors.dbus_autofill_monitor.run_daemon() - -while True: - time.sleep(60) \ No newline at end of file diff --git a/ui/python3-requirements.json b/ui/python3-requirements.json deleted file mode 100644 index 10db252..0000000 --- a/ui/python3-requirements.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "python3-requirements", - "buildsystem": "simple", - "build-commands": [], - "modules": [ - { - "name": "python3-ChaCha20", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"ChaCha20==1.1.1\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/7d/93/2c5c7203bcb1ece177a49d14b32f0e0511f7d4eaf8446c15f7d64af082ad/ChaCha20-1.1.1.tar.gz", - "sha256": "6d6b1ef373058540369c14d2369ab14ee4ffaeae4dc53d8a18b5b617bd06c6bb" - } - ] - }, - { - "name": "python3-chacha20poly1305", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"chacha20poly1305==0.0.3\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/38/2c/5b4eb73c5cb30ded3082af025e76f529764971c57c02b101e842ff998f63/chacha20poly1305-0.0.3.tar.gz", - "sha256": "f2f005c7cf4638ffa4ff06c02c78748068b642916795c6d16c7cc5e355e70edf" - } - ] - }, - { - "name": "python3-tendo", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"tendo==0.3.0\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/ce/3f/761077d55732b0b1a673b15d4fdaa947a7c1eb5c9a23b7142df557019823/tendo-0.3.0-py3-none-any.whl", - "sha256": "026b70b355ea4c9da7c2123fa2d5c280c8983c1b34e329ff49260e2e78b93be7" - } - ] - } - ] -} \ No newline at end of file diff --git a/ui/requirements.txt b/ui/requirements.txt deleted file mode 100644 index 432025d..0000000 --- a/ui/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -ChaCha20==1.1.1 -chacha20poly1305==0.0.3 -tendo==0.3.0 \ No newline at end of file