Add initial authenticated connection work
This commit is contained in:
parent
f3196863bb
commit
cf6221c080
35 changed files with 513 additions and 328 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,3 +4,4 @@ __pycache__
|
||||||
.flatpak-builder
|
.flatpak-builder
|
||||||
flatpak-pip-generator
|
flatpak-pip-generator
|
||||||
repo
|
repo
|
||||||
|
__debug*
|
||||||
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -114,7 +113,7 @@ func makeAuthenticatedHTTPRequest(ctx context.Context, req *http.Request, recv i
|
||||||
return &errStatusCode{res.StatusCode, body}
|
return &errStatusCode{res.StatusCode, body}
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(body, recv); err != nil {
|
if err := json.Unmarshal(body, recv); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, string(body))
|
fmt.Println(string(body))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ type RuntimeConfig struct {
|
||||||
UseMemguard bool
|
UseMemguard bool
|
||||||
SSHAgentSocketPath string
|
SSHAgentSocketPath string
|
||||||
GoldwardenSocketPath string
|
GoldwardenSocketPath string
|
||||||
|
DaemonAuthToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFile struct {
|
type ConfigFile struct {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ type CallingContext struct {
|
||||||
ParentProcessPid int
|
ParentProcessPid int
|
||||||
GrandParentProcessPid int
|
GrandParentProcessPid int
|
||||||
Error bool
|
Error bool
|
||||||
|
Authenticated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCallingContext(connection net.Conn) CallingContext {
|
func GetCallingContext(connection net.Conn) CallingContext {
|
||||||
|
|
@ -30,6 +31,7 @@ func GetCallingContext(connection net.Conn) CallingContext {
|
||||||
ParentProcessPid: 0,
|
ParentProcessPid: 0,
|
||||||
GrandParentProcessPid: 0,
|
GrandParentProcessPid: 0,
|
||||||
Error: true,
|
Error: true,
|
||||||
|
Authenticated: false,
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorContext
|
return errorContext
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,10 @@ func (s *SessionStore) verifySession(ctx sockets.CallingContext, sessionType Ses
|
||||||
|
|
||||||
// with session
|
// with session
|
||||||
func GetPermission(sessionType SessionType, ctx sockets.CallingContext, config *config.Config) (bool, error) {
|
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))
|
log.Info("Checking permission for " + ctx.ProcessName + " with session type " + string(sessionType))
|
||||||
var actionDescription = ""
|
var actionDescription = ""
|
||||||
biometricsApprovalType := biometrics.AccessVault
|
biometricsApprovalType := biometrics.AccessVault
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/quexten/goldwarden/agent/processsecurity"
|
"github.com/quexten/goldwarden/agent/processsecurity"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/ssh"
|
"github.com/quexten/goldwarden/agent/ssh"
|
||||||
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/ipc/messages"
|
"github.com/quexten/goldwarden/ipc/messages"
|
||||||
"github.com/quexten/goldwarden/logging"
|
"github.com/quexten/goldwarden/logging"
|
||||||
|
|
@ -44,7 +45,7 @@ func writeError(c net.Conn, errMsg error) error {
|
||||||
return nil
|
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 {
|
for {
|
||||||
buf := make([]byte, 1024*1024)
|
buf := make([]byte, 1024*1024)
|
||||||
nr, err := c.Read(buf)
|
nr, err := c.Read(buf)
|
||||||
|
|
@ -61,7 +62,38 @@ func serveAgentSession(c net.Conn, ctx context.Context, vault *vault.Vault, cfg
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBytes := []byte{}
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseBytes []byte
|
||||||
if action, actionFound := actions.AgentActionsRegistry.Get(msg.Type); actionFound {
|
if action, actionFound := actions.AgentActionsRegistry.Get(msg.Type); actionFound {
|
||||||
callingContext := sockets.GetCallingContext(c)
|
callingContext := sockets.GetCallingContext(c)
|
||||||
payload, err := action(msg, cfg, vault, &callingContext)
|
payload, err := action(msg, cfg, vault, &callingContext)
|
||||||
|
|
@ -291,7 +323,7 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error {
|
||||||
|
|
||||||
l, err := net.Listen("unix", path)
|
l, err := net.Listen("unix", path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("listen error", err.Error())
|
fmt.Println("listen error", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
@ -301,10 +333,11 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error {
|
||||||
for {
|
for {
|
||||||
fd, err := l.Accept()
|
fd, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("accept error", err.Error())
|
fmt.Println("accept error", err.Error())
|
||||||
}
|
}
|
||||||
|
fmt.Println("Accepted connection")
|
||||||
|
|
||||||
go serveAgentSession(fd, ctx, vault, &cfg)
|
go serveAgentSession(fd, vault, &cfg)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var autofillCmd = &cobra.Command{
|
var autofillCmd = &cobra.Command{
|
||||||
Use: "autotype",
|
Hidden: true,
|
||||||
Short: "Autotype credentials",
|
Use: "autotype",
|
||||||
Long: `Autotype credentials`,
|
Short: "Autotype credentials",
|
||||||
|
Long: `Autotype credentials`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
username, _ := cmd.Flags().GetString("username")
|
username, _ := cmd.Flags().GetString("username")
|
||||||
// get pasword from env
|
// get pasword from env
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -30,12 +31,12 @@ var setApiUrlCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting api url failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting api url failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -63,12 +64,12 @@ var setIdentityURLCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting identity url failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting identity url failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -96,12 +97,12 @@ var setNotificationsURLCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting notifications url failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting notifications url failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -129,12 +130,12 @@ var setVaultURLCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting vault url failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting vault url failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -162,12 +163,12 @@ var setURLsAutomaticallyCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting urls automatically failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting urls automatically failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -188,14 +189,15 @@ var getEnvironmentCmd = &cobra.Command{
|
||||||
|
|
||||||
switch result := result.(type) {
|
switch result := result.(type) {
|
||||||
case messages.GetConfigEnvironmentResponse:
|
case messages.GetConfigEnvironmentResponse:
|
||||||
fmt.Println("{")
|
response := map[string]string{}
|
||||||
fmt.Println(" \"api\": \"" + result.ApiURL + "\",")
|
response["api"] = result.ApiURL
|
||||||
fmt.Println(" \"identity\": \"" + result.IdentityURL + "\",")
|
response["identity"] = result.IdentityURL
|
||||||
fmt.Println(" \"notifications\": \"" + result.NotificationsURL + "\",")
|
response["notifications"] = result.NotificationsURL
|
||||||
fmt.Println(" \"vault\": \"" + result.VaultURL + "\"")
|
response["vault"] = result.VaultURL
|
||||||
fmt.Println("}")
|
responseJSON, _ := json.Marshal(response)
|
||||||
|
fmt.Println(string(responseJSON))
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -226,12 +228,12 @@ var setApiClientIDCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting api client id failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting api client id failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -263,12 +265,12 @@ var setApiSecretCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Done")
|
fmt.Println("Done")
|
||||||
} else {
|
} else {
|
||||||
println("Setting api secret failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Setting api secret failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -289,13 +291,14 @@ var getRuntimeConfigCmd = &cobra.Command{
|
||||||
|
|
||||||
switch result := result.(type) {
|
switch result := result.(type) {
|
||||||
case messages.GetRuntimeConfigResponse:
|
case messages.GetRuntimeConfigResponse:
|
||||||
fmt.Println("{")
|
response := map[string]interface{}{}
|
||||||
fmt.Println(" \"useMemguard\": " + fmt.Sprintf("%t", result.UseMemguard) + ",")
|
response["useMemguard"] = result.UseMemguard
|
||||||
fmt.Println(" \"SSHAgentSocketPath\": \"" + result.SSHAgentSocketPath + "\",")
|
response["SSHAgentSocketPath"] = result.SSHAgentSocketPath
|
||||||
fmt.Println(" \"goldwardenSocketPath\": \"" + result.GoldwardenSocketPath + "\"")
|
response["goldwardenSocketPath"] = result.GoldwardenSocketPath
|
||||||
fmt.Println("}")
|
responseJSON, _ := json.Marshal(response)
|
||||||
|
fmt.Println(string(responseJSON))
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type")
|
fmt.Println("Wrong IPC response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ var daemonizeCmd = &cobra.Command{
|
||||||
sshDisabled := runtimeConfig.DisableSSHAgent
|
sshDisabled := runtimeConfig.DisableSSHAgent
|
||||||
|
|
||||||
if websocketDisabled {
|
if websocketDisabled {
|
||||||
println("Websocket disabled")
|
fmt.Println("Websocket disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
if sshDisabled {
|
if sshDisabled {
|
||||||
println("SSH agent disabled")
|
fmt.Println("SSH agent disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup := func() {
|
cleanup := func() {
|
||||||
|
|
|
||||||
10
cmd/login.go
10
cmd/login.go
|
|
@ -4,6 +4,8 @@ Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/quexten/goldwarden/ipc/messages"
|
"github.com/quexten/goldwarden/ipc/messages"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
@ -17,7 +19,7 @@ var loginCmd = &cobra.Command{
|
||||||
request := messages.DoLoginRequest{}
|
request := messages.DoLoginRequest{}
|
||||||
email, _ := cmd.Flags().GetString("email")
|
email, _ := cmd.Flags().GetString("email")
|
||||||
if email == "" {
|
if email == "" {
|
||||||
println("Error: No email specified")
|
fmt.Println("Error: No email specified")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,12 +36,12 @@ var loginCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Logged in")
|
fmt.Println("Logged in")
|
||||||
} else {
|
} else {
|
||||||
println("Login failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Login failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong IPC response type for login")
|
fmt.Println("Wrong IPC response type for login")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ var getLoginCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
println("Error: " + resp.(messages.ActionResponse).Message)
|
fmt.Println("Error: " + resp.(messages.ActionResponse).Message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
12
cmd/pin.go
12
cmd/pin.go
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/quexten/goldwarden/ipc/messages"
|
"github.com/quexten/goldwarden/ipc/messages"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
@ -25,12 +27,12 @@ var setPinCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Pin updated")
|
fmt.Println("Pin updated")
|
||||||
} else {
|
} else {
|
||||||
println("Pin updating failed: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Pin updating failed: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
fmt.Println("Wrong response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -48,9 +50,9 @@ var pinStatusCmd = &cobra.Command{
|
||||||
|
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
println("Pin status: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Pin status: " + result.(messages.ActionResponse).Message)
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
fmt.Println("Wrong response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/quexten/goldwarden/agent"
|
"github.com/quexten/goldwarden/agent"
|
||||||
|
|
@ -62,8 +63,8 @@ func loginIfRequired() error {
|
||||||
|
|
||||||
func handleSendToAgentError(err error) {
|
func handleSendToAgentError(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Error: " + err.Error())
|
fmt.Println("Error: " + err.Error())
|
||||||
println("Is the daemon running?")
|
fmt.Println("Is the daemon running?")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ var runCmd = &cobra.Command{
|
||||||
The variables are stored as a secure note. Consult the documentation for more information.`,
|
The variables are stored as a secure note. Consult the documentation for more information.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
println("Error: No command specified")
|
fmt.Println("Error: No command specified")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ var runCmd = &cobra.Command{
|
||||||
env = append(env, key+"="+value)
|
env = append(env, key+"="+value)
|
||||||
}
|
}
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
println("Error: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Error: " + result.(messages.ActionResponse).Message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ var sendCreateCmd = &cobra.Command{
|
||||||
fmt.Println("Send created: " + result.(messages.CreateSendResponse).URL)
|
fmt.Println("Send created: " + result.(messages.CreateSendResponse).URL)
|
||||||
break
|
break
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
println("Error: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Error: " + result.(messages.ActionResponse).Message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
60
cmd/session.go
Normal file
60
cmd/session.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
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) {
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ var sshAddCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
println("Error: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Error: " + result.(messages.ActionResponse).Message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -74,7 +74,7 @@ var listSSHCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
println("Error: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Error: " + result.(messages.ActionResponse).Message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
40
cmd/vault.go
40
cmd/vault.go
|
|
@ -1,6 +1,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -30,12 +31,12 @@ var unlockCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Unlocked")
|
fmt.Println("Unlocked")
|
||||||
} else {
|
} else {
|
||||||
println("Not unlocked: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Not unlocked: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
fmt.Println("Wrong response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -56,12 +57,12 @@ var lockCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Locked")
|
fmt.Println("Locked")
|
||||||
} else {
|
} else {
|
||||||
println("Not locked: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Not locked: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
fmt.Println("Wrong response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -82,12 +83,12 @@ var purgeCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.ActionResponse:
|
case messages.ActionResponse:
|
||||||
if result.(messages.ActionResponse).Success {
|
if result.(messages.ActionResponse).Success {
|
||||||
println("Purged")
|
fmt.Println("Purged")
|
||||||
} else {
|
} else {
|
||||||
println("Not purged: " + result.(messages.ActionResponse).Message)
|
fmt.Println("Not purged: " + result.(messages.ActionResponse).Message)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
fmt.Println("Wrong response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -107,18 +108,19 @@ var statusCmd = &cobra.Command{
|
||||||
|
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.VaultStatusResponse:
|
case messages.VaultStatusResponse:
|
||||||
|
response := map[string]interface{}{}
|
||||||
status := result.(messages.VaultStatusResponse)
|
status := result.(messages.VaultStatusResponse)
|
||||||
fmt.Println("{")
|
response["locked"] = status.Locked
|
||||||
fmt.Println(" \"locked\":", status.Locked, ",")
|
response["loginEntries"] = status.NumberOfLogins
|
||||||
fmt.Println(" \"loginEntries\":", status.NumberOfLogins, ",")
|
response["noteEntries"] = status.NumberOfNotes
|
||||||
fmt.Println(" \"noteEntries\":", status.NumberOfNotes, ",")
|
response["lastSynced"] = time.Unix(status.LastSynced, 0).String()
|
||||||
fmt.Println(" \"lastSynced\": \"" + time.Unix(status.LastSynced, 0).String() + "\",")
|
response["websocketConnected"] = status.WebsockedConnected
|
||||||
fmt.Println(" \"websocketConnected\":", status.WebsockedConnected, ",")
|
response["pinSet"] = status.PinSet
|
||||||
fmt.Println(" \"pinSet\":", status.PinSet, ",")
|
response["loggedIn"] = status.LoggedIn
|
||||||
fmt.Println(" \"loggedIn\":", status.LoggedIn)
|
responseJSON, _ := json.Marshal(response)
|
||||||
fmt.Println("}")
|
fmt.Println(string(responseJSON))
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
fmt.Println("Wrong response type")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
ipc/messages/session.go
Normal file
31
ipc/messages/session.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
type SessionAuthRequest struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionAuthResponse struct {
|
||||||
|
Verified 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{})
|
||||||
|
}
|
||||||
4
main.go
4
main.go
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -36,6 +37,7 @@ func main() {
|
||||||
UseMemguard: os.Getenv("GOLDWARDEN_NO_MEMGUARD") != "true",
|
UseMemguard: os.Getenv("GOLDWARDEN_NO_MEMGUARD") != "true",
|
||||||
SSHAgentSocketPath: os.Getenv("GOLDWARDEN_SSH_AUTH_SOCK"),
|
SSHAgentSocketPath: os.Getenv("GOLDWARDEN_SSH_AUTH_SOCK"),
|
||||||
GoldwardenSocketPath: os.Getenv("GOLDWARDEN_SOCKET_PATH"),
|
GoldwardenSocketPath: os.Getenv("GOLDWARDEN_SOCKET_PATH"),
|
||||||
|
DaemonAuthToken: os.Getenv("GOLDWARDEN_DAEMON_AUTH_TOKEN"),
|
||||||
|
|
||||||
ConfigDirectory: configPath,
|
ConfigDirectory: configPath,
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +64,7 @@ func main() {
|
||||||
userHome, _ := os.UserHomeDir()
|
userHome, _ := os.UserHomeDir()
|
||||||
runtimeConfig.ConfigDirectory = userHome + "/.var/app/com.quexten.Goldwarden/config/goldwarden.json"
|
runtimeConfig.ConfigDirectory = userHome + "/.var/app/com.quexten.Goldwarden/config/goldwarden.json"
|
||||||
runtimeConfig.ConfigDirectory = strings.ReplaceAll(runtimeConfig.ConfigDirectory, "~", userHome)
|
runtimeConfig.ConfigDirectory = strings.ReplaceAll(runtimeConfig.ConfigDirectory, "~", userHome)
|
||||||
println("Flatpak Config directory: " + runtimeConfig.ConfigDirectory)
|
fmt.Println("Flatpak Config directory: " + runtimeConfig.ConfigDirectory)
|
||||||
runtimeConfig.SSHAgentSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/ssh-auth-sock"
|
runtimeConfig.SSHAgentSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/ssh-auth-sock"
|
||||||
runtimeConfig.GoldwardenSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock"
|
runtimeConfig.GoldwardenSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
184
ui/goldwarden.py
184
ui/goldwarden.py
|
|
@ -1,184 +0,0 @@
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
# if flatpak
|
|
||||||
if os.path.exists("/app/bin/goldwarden"):
|
|
||||||
BINARY_PATH = "/app/bin/goldwarden"
|
|
||||||
else:
|
|
||||||
res = subprocess.run(["which", "goldwarden"])
|
|
||||||
BINARY_PATH = res.stdout.decode("utf-8").strip()
|
|
||||||
|
|
||||||
def set_api_url(url):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-api-url {url}"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def set_identity_url(url):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-identity-url {url}"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def set_notification_url(url):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-notifications-url {url}"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def set_vault_url(url):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-vault-url {url}"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed err", result.stderr)
|
|
||||||
|
|
||||||
def set_url(url):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-url {url}"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed err", result.stderr)
|
|
||||||
|
|
||||||
def get_environment():
|
|
||||||
restic_cmd = f"{BINARY_PATH} config get-environment"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
result_text = result.stdout
|
|
||||||
print(result_text)
|
|
||||||
return json.loads(result_text)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def set_client_id(client_id):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-client-id \"{client_id}\""
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed err", result.stderr)
|
|
||||||
|
|
||||||
def set_client_secret(client_secret):
|
|
||||||
restic_cmd = f"{BINARY_PATH} config set-client-secret \"{client_secret}\""
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed err", result.stderr)
|
|
||||||
|
|
||||||
def login_with_password(email, password):
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault login --email {email}"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
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):
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault login --email {email} --passwordless"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def is_pin_enabled():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault pin status"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
# check if contains enabled
|
|
||||||
return "enabled" in result.stderr
|
|
||||||
|
|
||||||
def enable_pin():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault pin set"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def unlock():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault unlock"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def lock():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault lock"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def purge():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault purge"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
|
|
||||||
def get_vault_status():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault status"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
try:
|
|
||||||
return json.loads(result.stdout)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_vault_logins():
|
|
||||||
restic_cmd = f"{BINARY_PATH} logins list"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
||||||
try:
|
|
||||||
return json.loads(result.stdout)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_runtime_config():
|
|
||||||
restic_cmd = f"{BINARY_PATH} config get-runtime-config"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
return json.loads(result.stdout)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def autotype(username, password):
|
|
||||||
# environment
|
|
||||||
env = os.environ.copy()
|
|
||||||
env["PASSWORD"] = password
|
|
||||||
restic_cmd = f"{BINARY_PATH} autotype --username {username}"
|
|
||||||
result = subprocess.run(restic_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():
|
|
||||||
restic_cmd = f"{BINARY_PATH} vault status"
|
|
||||||
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
return False
|
|
||||||
daemon_not_running = ("daemon running?" in result.stderr or "daemon running" in result.stderr)
|
|
||||||
return not daemon_not_running
|
|
||||||
|
|
||||||
def run_daemon():
|
|
||||||
restic_cmd = f"{BINARY_PATH} daemonize"
|
|
||||||
# print while running
|
|
||||||
result = subprocess.Popen(restic_cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
||||||
if result.returncode != 0:
|
|
||||||
print("Failed err", result.stderr)
|
|
||||||
for line in result.stdout:
|
|
||||||
print(line.decode("utf-8"))
|
|
||||||
result.wait()
|
|
||||||
print("quitting goldwarden daemon")
|
|
||||||
return result.returncode
|
|
||||||
53
ui/main.py
53
ui/main.py
|
|
@ -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)
|
|
||||||
3
ui/src/goldwarden_ui_main.py
Normal file
3
ui/src/goldwarden_ui_main.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import linux.main as linux_main
|
||||||
|
|
||||||
|
linux_main.main()
|
||||||
59
ui/src/linux/main.py
Normal file
59
ui/src/linux/main.py
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/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 services import goldwarden
|
||||||
|
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))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
token = secrets.token_hex(32)
|
||||||
|
print("token", token)
|
||||||
|
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_objeect("com.quexten.Goldwarden.dbus", "/com/quexten/Goldwarden")
|
||||||
|
the_interface = dbus.Interface(the_object, "com.quexten.Goldwarden.Settings")
|
||||||
|
reply = the_interface.settings()
|
||||||
|
exit()
|
||||||
|
|
||||||
|
# start daemons
|
||||||
|
dbus_autofill_monitor.run_daemon() # todo: remove after migration
|
||||||
|
dbus_monitor.run_daemon(token)
|
||||||
|
|
||||||
|
if not "--hidden" in sys.argv:
|
||||||
|
subprocess.Popen(["python3", "-m", "src.ui.settings"], cwd=root_path, start_new_session=True)
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# subprocess.Popen(["python3", f'{source_path}/background.py'], start_new_session=True)
|
||||||
|
# except Exception as e:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
while True:
|
||||||
|
time.sleep(60)
|
||||||
|
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
@ -19,8 +19,13 @@ class GoldwardenDBUSService(dbus.service.Object):
|
||||||
on_autofill()
|
on_autofill()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def run_daemon():
|
def daemon():
|
||||||
DBusGMainLoop(set_as_default=True)
|
DBusGMainLoop(set_as_default=True)
|
||||||
service = GoldwardenDBUSService()
|
service = GoldwardenDBUSService()
|
||||||
from gi.repository import GLib, GObject as gobject
|
from gi.repository import GLib, GObject as gobject
|
||||||
gobject.MainLoop().run()
|
gobject.MainLoop().run()
|
||||||
|
|
||||||
|
def run_daemon():
|
||||||
|
thread = Thread(target=daemon)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
41
ui/src/linux/monitors/dbus_monitor.py
Normal file
41
ui/src/linux/monitors/dbus_monitor.py
Normal file
|
|
@ -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.ui', bus=dbus.SessionBus())
|
||||||
|
dbus.service.Object.__init__(self, bus_name, '/com/quexten/Goldwarden/ui')
|
||||||
|
|
||||||
|
@dbus.service.method('com.quexten.Goldwarden.ui.QuickAccess')
|
||||||
|
def quickaccess(self):
|
||||||
|
p = subprocess.Popen(["python3", "-m", "src.ui.quickaccess"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True)
|
||||||
|
print("writing token")
|
||||||
|
p.stdin.write(f"{daemon_token}\n".encode())
|
||||||
|
p.stdin.flush()
|
||||||
|
print("reading token")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
@dbus.service.method('com.quexten.Goldwarden.ui.Settings')
|
||||||
|
def settings(self):
|
||||||
|
subprocess.Popen(["python3", "-m", "src.ui.settings"], cwd=root_path, start_new_session=True)
|
||||||
|
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()
|
||||||
159
ui/src/services/goldwarden.py
Normal file
159
ui/src/services/goldwarden.py
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BINARY_PATHS = [
|
||||||
|
"/app/bin/goldwarden",
|
||||||
|
"/usr/bin/goldwarden",
|
||||||
|
str(Path.home()) + "/go/src/github.com/quexten/goldwarden/goldwarden"
|
||||||
|
]
|
||||||
|
|
||||||
|
authenticated_connection = None
|
||||||
|
|
||||||
|
def create_authenticated_connection(token):
|
||||||
|
global authenticated_connection
|
||||||
|
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 = 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 ""
|
||||||
|
|
||||||
|
print("sending command", cmd)
|
||||||
|
authenticated_connection.stdin.write(cmd + "\n")
|
||||||
|
authenticated_connection.stdin.flush()
|
||||||
|
result = authenticated_connection.stdout.readline()
|
||||||
|
print("result", result)
|
||||||
|
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:
|
||||||
|
print(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:
|
||||||
|
print(e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_vault_logins():
|
||||||
|
result = send_authenticated_command(f"logins list")
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
try:
|
||||||
|
return json.loads(result)
|
||||||
|
except Exception as e:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_runtime_config():
|
||||||
|
result = send_authenticated_command(f"config get-runtime-config")
|
||||||
|
print(result)
|
||||||
|
try:
|
||||||
|
return json.loads(result)
|
||||||
|
except Exception as e:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# def autotype(username, password):
|
||||||
|
# # environment
|
||||||
|
# env = os.environ.copy()
|
||||||
|
# env["PASSWORD"] = password
|
||||||
|
# restic_cmd = f"{BINARY_PATH} autotype --username {username}"
|
||||||
|
# result = subprocess.run(restic_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 run_daemon():
|
||||||
|
# restic_cmd = f"daemonize"
|
||||||
|
# # print while running
|
||||||
|
# result = subprocess.Popen(restic_cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
# if result.returncode != 0:
|
||||||
|
# print("Failed err", result.stderr)
|
||||||
|
# for line in result.stdout:
|
||||||
|
# print(line.decode("utf-8"))
|
||||||
|
# result.wait()
|
||||||
|
# print("quitting goldwarden daemon")
|
||||||
|
# return result.returncode
|
||||||
|
|
@ -4,14 +4,17 @@ gi.require_version('Adw', '1')
|
||||||
import gc
|
import gc
|
||||||
import time
|
import time
|
||||||
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
|
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
|
||||||
import goldwarden
|
from ..services import goldwarden
|
||||||
import clipboard
|
from ..linux import clipboard
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import totp
|
from ..services import totp
|
||||||
Notify.init("Goldwarden")
|
Notify.init("Goldwarden")
|
||||||
|
|
||||||
|
token = sys.stdin.readline()
|
||||||
|
goldwarden.create_authenticated_connection(token)
|
||||||
|
|
||||||
class MyApp(Adw.Application):
|
class MyApp(Adw.Application):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
@ -85,6 +88,9 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
|
|
||||||
keycont = Gtk.EventControllerKey()
|
keycont = Gtk.EventControllerKey()
|
||||||
def handle_keypress(cotroller, keyval, keycode, state, user_data):
|
def handle_keypress(cotroller, keyval, keycode, state, user_data):
|
||||||
|
# if ctrl is pressed
|
||||||
|
if state == 4:
|
||||||
|
print("ctrl")
|
||||||
if keycode == 36:
|
if keycode == 36:
|
||||||
print("enter")
|
print("enter")
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
@ -130,7 +136,8 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
self.history_list.get_style_context().add_class("boxed-list")
|
self.history_list.get_style_context().add_class("boxed-list")
|
||||||
self.box.append(self.history_list)
|
self.box.append(self.history_list)
|
||||||
self.set_default_size(700, 700)
|
self.set_default_size(700, 700)
|
||||||
self.set_title("Goldwarden")
|
# self.set_title("Goldwarden")
|
||||||
|
self.set_title(token)
|
||||||
|
|
||||||
app = MyApp(application_id="com.quexten.Goldwarden.autofill-menu")
|
app = MyApp(application_id="com.quexten.Goldwarden.autofill-menu")
|
||||||
app.run(sys.argv)
|
app.run(sys.argv)
|
||||||
|
|
@ -6,12 +6,14 @@ gi.require_version('Adw', '1')
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
from gi.repository import Gtk, Adw, GLib, Gdk
|
from gi.repository import Gtk, Adw, GLib, Gdk
|
||||||
import goldwarden
|
from ..services import goldwarden
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import subprocess
|
import subprocess
|
||||||
import components
|
from . import components
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
goldwarden.create_authenticated_connection(None)
|
||||||
|
|
||||||
class SettingsWinvdow(Gtk.ApplicationWindow):
|
class SettingsWinvdow(Gtk.ApplicationWindow):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
@ -201,6 +203,7 @@ class SettingsWinvdow(Gtk.ApplicationWindow):
|
||||||
|
|
||||||
pin_set = goldwarden.is_pin_enabled()
|
pin_set = goldwarden.is_pin_enabled()
|
||||||
status = goldwarden.get_vault_status()
|
status = goldwarden.get_vault_status()
|
||||||
|
print("status", status)
|
||||||
runtimeCfg = goldwarden.get_runtime_config()
|
runtimeCfg = goldwarden.get_runtime_config()
|
||||||
if runtimeCfg != None:
|
if runtimeCfg != None:
|
||||||
self.ssh_row.set_subtitle("Listening at "+runtimeCfg["SSHAgentSocketPath"])
|
self.ssh_row.set_subtitle("Listening at "+runtimeCfg["SSHAgentSocketPath"])
|
||||||
Loading…
Reference in a new issue