From 8eb55f28082f7aacfe0155cabb79f3139b664dfd Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Sat, 20 Jan 2024 12:31:37 +0100 Subject: [PATCH] Add url auto-config and web vault config --- agent/actions/config.go | 90 ++++++++++++++++++++++++++++++++++++++ agent/config/config.go | 2 + cmd/config.go | 96 +++++++++++++++++++++++++++++++++++++++++ ipc/messages/config.go | 50 +++++++++++++++++++++ 4 files changed, 238 insertions(+) diff --git a/agent/actions/config.go b/agent/actions/config.go index 9f06fad..4479ea7 100644 --- a/agent/actions/config.go +++ b/agent/actions/config.go @@ -1,6 +1,10 @@ package actions import ( + "encoding/json" + "io" + "net/http" + "github.com/quexten/goldwarden/agent/config" "github.com/quexten/goldwarden/agent/sockets" "github.com/quexten/goldwarden/agent/vault" @@ -55,6 +59,89 @@ func handleSetNotifications(request messages.IPCMessage, cfg *config.Config, vau }) } +func handleSetVaultURL(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) { + vaultURL := messages.ParsePayload(request).(messages.SetVaultURLRequest).Value + cfg.ConfigFile.VaultUrl = vaultURL + err = cfg.WriteConfig() + if err != nil { + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: false, + Message: err.Error(), + }) + } + + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: true, + }) +} + +type ConfigResponse struct { + Version string `json:"version"` + GitHash string `json:"gitHash"` + Environment struct { + Vault string `json:"vault"` + Api string `json:"api"` + Identity string `json:"identity"` + Notifications string `json:"notifications"` + } +} + +func handleSetURLsAutomatically(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) { + autoconfigBaseURL := messages.ParsePayload(request).(messages.SetURLsAutomaticallyRequest).Value + + // make http request + resp, err := http.Get(autoconfigBaseURL + "/api/config") + if err != nil { + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: false, + Message: err.Error(), + }) + } + + // parse response + var configResponse ConfigResponse + body, err := io.ReadAll(resp.Body) + if err != nil { + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: false, + Message: err.Error(), + }) + } + err = json.Unmarshal(body, &configResponse) + if err != nil { + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: false, + Message: err.Error(), + }) + } + + cfg.ConfigFile.ApiUrl = configResponse.Environment.Api + cfg.ConfigFile.IdentityUrl = configResponse.Environment.Identity + cfg.ConfigFile.NotificationsUrl = configResponse.Environment.Notifications + cfg.ConfigFile.VaultUrl = configResponse.Environment.Vault + + err = cfg.WriteConfig() + if err != nil { + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: false, + Message: err.Error(), + }) + } + + return messages.IPCMessageFromPayload(messages.ActionResponse{ + Success: true, + }) +} + +func handleGetConfigEnvironment(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) { + return messages.IPCMessageFromPayload(messages.GetConfigEnvironmentResponse{ + ApiURL: cfg.ConfigFile.ApiUrl, + IdentityURL: cfg.ConfigFile.IdentityUrl, + NotificationsURL: cfg.ConfigFile.NotificationsUrl, + VaultURL: cfg.ConfigFile.VaultUrl, + }) +} + func handleSetClientID(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) { clientID := messages.ParsePayload(request).(messages.SetClientIDRequest).Value cfg.SetClientID(clientID) @@ -99,6 +186,9 @@ func init() { AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetIdentityURLRequest{}), handleSetIdentity) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetApiURLRequest{}), handleSetApiURL) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetNotificationsURLRequest{}), handleSetNotifications) + AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetVaultURLRequest{}), handleSetVaultURL) + AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetURLsAutomaticallyRequest{}), handleSetURLsAutomatically) + AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetConfigEnvironmentRequest{}), handleGetConfigEnvironment) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetRuntimeConfigRequest{}), handleGetRuntimeConfig) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetClientIDRequest{}), handleSetClientID) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetClientSecretRequest{}), handleSetClientSecret) diff --git a/agent/config/config.go b/agent/config/config.go index 79c855b..88791e6 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -55,6 +55,7 @@ type ConfigFile struct { IdentityUrl string ApiUrl string NotificationsUrl string + VaultUrl string EncryptedClientID string EncryptedClientSecret string DeviceUUID string @@ -91,6 +92,7 @@ func DefaultConfig(useMemguard bool) Config { IdentityUrl: "https://vault.bitwarden.com/identity", ApiUrl: "https://vault.bitwarden.com/api", NotificationsUrl: "https://notifications.bitwarden.com", + VaultUrl: "https://vault.bitwarden.com", EncryptedClientID: "", EncryptedClientSecret: "", DeviceUUID: deviceUUID.String(), diff --git a/cmd/config.go b/cmd/config.go index 851e8e2..01812b0 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -107,6 +107,99 @@ var setNotificationsURLCmd = &cobra.Command{ }, } +var setVaultURLCmd = &cobra.Command{ + Use: "set-vault-url", + Short: "Set the vault url", + Long: `Set the vault url.`, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 { + return + } + + url := args[0] + request := messages.SetVaultURLRequest{} + request.Value = url + + result, err := commandClient.SendToAgent(request) + if err != nil { + handleSendToAgentError(err) + return + } + + switch result.(type) { + case messages.ActionResponse: + if result.(messages.ActionResponse).Success { + println("Done") + } else { + println("Setting vault url failed: " + result.(messages.ActionResponse).Message) + } + default: + println("Wrong IPC response type") + } + + }, +} + +var setURLsAutomaticallyCmd = &cobra.Command{ + Use: "set-server", + Short: "Set the urls automatically", + Long: `Set the api/identity/vault/notification urls automaticall from a base url.`, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 { + return + } + + value := args[0] + request := messages.SetURLsAutomaticallyRequest{} + request.Value = value + + result, err := commandClient.SendToAgent(request) + if err != nil { + handleSendToAgentError(err) + return + } + + switch result.(type) { + case messages.ActionResponse: + if result.(messages.ActionResponse).Success { + println("Done") + } else { + println("Setting urls automatically failed: " + result.(messages.ActionResponse).Message) + } + default: + println("Wrong IPC response type") + } + + }, +} + +var getEnvironmentCmd = &cobra.Command{ + Use: "get-environment", + Short: "Get the environment", + Long: `Get the environment.`, + Run: func(cmd *cobra.Command, args []string) { + request := messages.GetConfigEnvironmentRequest{} + + result, err := commandClient.SendToAgent(request) + if err != nil { + handleSendToAgentError(err) + return + } + + 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("}") + default: + println("Wrong IPC response type") + } + }, +} + var setApiClientIDCmd = &cobra.Command{ Use: "set-client-id", Short: "Set the client id", @@ -218,6 +311,9 @@ func init() { configCmd.AddCommand(setApiUrlCmd) configCmd.AddCommand(setIdentityURLCmd) configCmd.AddCommand(setNotificationsURLCmd) + configCmd.AddCommand(setVaultURLCmd) + configCmd.AddCommand(setURLsAutomaticallyCmd) + configCmd.AddCommand(getEnvironmentCmd) configCmd.AddCommand(getRuntimeConfigCmd) configCmd.AddCommand(setApiClientIDCmd) configCmd.AddCommand(setApiSecretCmd) diff --git a/ipc/messages/config.go b/ipc/messages/config.go index 107d818..f4a1ab6 100644 --- a/ipc/messages/config.go +++ b/ipc/messages/config.go @@ -14,6 +14,24 @@ type SetNotificationsURLRequest struct { Value string } +type SetVaultURLRequest struct { + Value string +} + +type SetURLsAutomaticallyRequest struct { + Value string +} + +type GetConfigEnvironmentRequest struct { +} + +type GetConfigEnvironmentResponse struct { + ApiURL string + IdentityURL string + NotificationsURL string + VaultURL string +} + type SetClientIDRequest struct { Value string } @@ -93,4 +111,36 @@ func init() { } return req, nil }, SetClientSecretRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req SetVaultURLRequest + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, SetVaultURLRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req SetURLsAutomaticallyRequest + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, SetURLsAutomaticallyRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req GetConfigEnvironmentRequest + return req, nil + }, GetConfigEnvironmentRequest{}) + + registerPayloadParser(func(payload []byte) (interface{}, error) { + var req GetConfigEnvironmentResponse + err := json.Unmarshal(payload, &req) + if err != nil { + panic("Unmarshal: " + err.Error()) + } + return req, nil + }, GetConfigEnvironmentResponse{}) }