Add more logging

This commit is contained in:
Bernd Schoolmann 2023-12-22 10:44:49 +01:00
parent 82d576d546
commit 3a1e47ff67
No known key found for this signature in database
9 changed files with 113 additions and 22 deletions

View File

@ -15,28 +15,33 @@ import (
) )
func handleGetBiometricsKey(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) { func handleGetBiometricsKey(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
actionsLog.Info("Browser Biometrics: Key requested, verifying biometrics...")
if !(systemauth.VerifyPinSession(*ctx) || biometrics.CheckBiometrics(biometrics.BrowserBiometrics)) { if !(systemauth.VerifyPinSession(*ctx) || biometrics.CheckBiometrics(biometrics.BrowserBiometrics)) {
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{ response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
Success: false, Success: false,
Message: "not approved", Message: "not approved",
}) })
actionsLog.Info("Browser Biometrics: Biometrics not approved %v", err)
if err != nil { if err != nil {
return messages.IPCMessage{}, err return messages.IPCMessage{}, err
} }
return response, nil return response, nil
} }
actionsLog.Info("Browser Biometrics: Biometrics verified, asking for approval...")
if approved, err := pinentry.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access your vault encryption key for browser biometric unlock.", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved { if approved, err := pinentry.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access your vault encryption key for browser biometric unlock.", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{ response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
Success: false, Success: false,
Message: "not approved", Message: "not approved",
}) })
actionsLog.Info("Browser Biometrics: Biometrics not approved %v", err)
if err != nil { if err != nil {
return messages.IPCMessage{}, err return messages.IPCMessage{}, err
} }
return response, nil return response, nil
} }
actionsLog.Info("Browser Biometrics: Approved, getting key...")
masterKey, err := cfg.GetMasterKey() masterKey, err := cfg.GetMasterKey()
if err != nil { if err != nil {
return messages.IPCMessage{}, err return messages.IPCMessage{}, err
@ -45,6 +50,7 @@ func handleGetBiometricsKey(request messages.IPCMessage, cfg *config.Config, vau
response, err = messages.IPCMessageFromPayload(messages.GetBiometricsKeyResponse{ response, err = messages.IPCMessageFromPayload(messages.GetBiometricsKeyResponse{
Key: masterKeyB64, Key: masterKeyB64,
}) })
actionsLog.Info("Browser Biometrics: Sending key...")
return response, err return response, err
} }

View File

@ -185,10 +185,20 @@ func handlePinStatus(request messages.IPCMessage, cfg *config.Config, vault *vau
return return
} }
func handleVaultStatus(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext *sockets.CallingContext) (response messages.IPCMessage, err error) {
var vaultStatus messages.VaultStatusResponse = messages.VaultStatusResponse{}
vaultStatus.Locked = cfg.IsLocked()
vaultStatus.NumberOfLogins = len(vault.GetLogins())
vaultStatus.NumberOfNotes = len(vault.GetNotes())
response, err = messages.IPCMessageFromPayload(vaultStatus)
return
}
func init() { func init() {
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.UnlockVaultRequest{}), handleUnlockVault) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.UnlockVaultRequest{}), handleUnlockVault)
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.LockVaultRequest{}), handleLockVault) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.LockVaultRequest{}), handleLockVault)
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.WipeVaultRequest{}), handleWipeVault) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.WipeVaultRequest{}), handleWipeVault)
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.UpdateVaultPINRequest{}), ensureBiometricsAuthorized(systemauth.AccessVault, handleUpdateVaultPin)) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.UpdateVaultPINRequest{}), ensureBiometricsAuthorized(systemauth.AccessVault, handleUpdateVaultPin))
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetVaultPINRequest{}), handlePinStatus) AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetVaultPINRequest{}), handlePinStatus)
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.VaultStatusRequest{}), handleVaultStatus)
} }

View File

@ -2,8 +2,12 @@ package crypto
import ( import (
"errors" "errors"
"github.com/quexten/goldwarden/logging"
) )
var keyringLog = logging.GetLogger("Goldwarden", "Keyring")
type Keyring struct { type Keyring struct {
AccountKey SymmetricEncryptionKey AccountKey SymmetricEncryptionKey
AsymmetricEncyryptionKey AsymmetricEncryptionKey AsymmetricEncyryptionKey AsymmetricEncryptionKey
@ -12,12 +16,14 @@ type Keyring struct {
} }
func NewMemoryKeyring(accountKey *MemorySymmetricEncryptionKey) Keyring { func NewMemoryKeyring(accountKey *MemorySymmetricEncryptionKey) Keyring {
keyringLog.Info("Creating new memory keyring")
return Keyring{ return Keyring{
AccountKey: accountKey, AccountKey: accountKey,
} }
} }
func NewMemguardKeyring(accountKey *MemguardSymmetricEncryptionKey) Keyring { func NewMemguardKeyring(accountKey *MemguardSymmetricEncryptionKey) Keyring {
keyringLog.Info("Creating new memguard keyring")
return Keyring{ return Keyring{
AccountKey: accountKey, AccountKey: accountKey,
} }
@ -28,6 +34,7 @@ func (keyring Keyring) IsLocked() bool {
} }
func (keyring *Keyring) Lock() { func (keyring *Keyring) Lock() {
keyringLog.Info("Locking keyring")
keyring.AccountKey = nil keyring.AccountKey = nil
keyring.AsymmetricEncyryptionKey = MemoryAsymmetricEncryptionKey{} keyring.AsymmetricEncyryptionKey = MemoryAsymmetricEncryptionKey{}
keyring.OrganizationKeys = nil keyring.OrganizationKeys = nil

View File

@ -30,35 +30,39 @@ func Sync(ctx context.Context, config *config.Config) (models.SyncData, error) {
func DoFullSync(ctx context.Context, vault *vault.Vault, config *config.Config, userSymmetricKey *crypto.SymmetricEncryptionKey, allowCache bool) error { func DoFullSync(ctx context.Context, vault *vault.Vault, config *config.Config, userSymmetricKey *crypto.SymmetricEncryptionKey, allowCache bool) error {
log.Info("Performing full sync...") log.Info("Performing full sync...")
sync, err := Sync(ctx, config) sync, err := Sync(ctx, config)
if err != nil { if err != nil {
log.Error("Could not sync: %v", err)
if allowCache { if allowCache {
home, _ := os.UserHomeDir() home, _ := os.UserHomeDir()
sync, err = ReadVault(home + path) sync, err = ReadVault(home + path)
} else { } else {
return err return err
} }
} else {
log.Info("Sync successful, initializing keyring and vault...")
} }
var orgKeys map[string]string = make(map[string]string) var orgKeys map[string]string = make(map[string]string)
log.Info("Initializing %d org keys...", len(sync.Profile.Organizations))
for _, org := range sync.Profile.Organizations { for _, org := range sync.Profile.Organizations {
orgId := org.Id.String() orgId := org.Id.String()
orgKeys[orgId] = org.Key orgKeys[orgId] = org.Key
} }
if userSymmetricKey != nil { if userSymmetricKey != nil {
log.Info("Initializing keyring from user symmetric key...")
crypto.InitKeyringFromUserSymmetricKey(vault.Keyring, *userSymmetricKey, sync.Profile.PrivateKey, orgKeys) crypto.InitKeyringFromUserSymmetricKey(vault.Keyring, *userSymmetricKey, sync.Profile.PrivateKey, orgKeys)
} }
log.Info("Clearing vault...")
vault.Clear() vault.Clear()
log.Info("Adding %d ciphers to vault...", len(sync.Ciphers))
for _, cipher := range sync.Ciphers { for _, cipher := range sync.Ciphers {
switch cipher.Type { switch cipher.Type {
case models.CipherLogin: case models.CipherLogin:
vault.AddOrUpdateLogin(cipher) vault.AddOrUpdateLogin(cipher)
break
case models.CipherNote: case models.CipherNote:
vault.AddOrUpdateSecureNote(cipher) vault.AddOrUpdateSecureNote(cipher)
break
} }
} }

View File

@ -3,7 +3,6 @@ package bitwarden
import ( import (
"bytes" "bytes"
"context" "context"
"fmt"
"net/url" "net/url"
"os" "os"
"os/signal" "os/signal"
@ -49,7 +48,7 @@ const (
) )
const ( const (
WEBSOCKET_SLEEP_DURATION_SECONDS = 5 WEBSOCKET_SLEEP_DURATION_SECONDS = 60
) )
func RunWebsocketDaemon(ctx context.Context, vault *vault.Vault, cfg *config.Config) { func RunWebsocketDaemon(ctx context.Context, vault *vault.Vault, cfg *config.Config) {
@ -95,12 +94,15 @@ func connectToWebsocket(ctx context.Context, vault *vault.Vault, cfg *config.Con
go func() { go func() {
defer close(done) defer close(done)
for { for {
mt, message, err := c.ReadMessage() _, message, err := c.ReadMessage()
fmt.Println(mt)
if err != nil { if err != nil {
websocketLog.Error("Error reading websocket message %s", err) websocketLog.Error("Error reading websocket message %s", err)
return return
} }
if len(message) < 3 {
//ignore empty messages
continue
}
if messageType, cipherid, success := websocketMessageType(message); success { if messageType, cipherid, success := websocketMessageType(message); success {
var mt1 = NotificationMessageType(messageType) var mt1 = NotificationMessageType(messageType)

View File

@ -2,8 +2,7 @@
package processsecurity package processsecurity
import "golang.org/x/sys/unix"
func DisableDumpable() error { func DisableDumpable() error {
return unix.Prctl(unix.PR_SET_DUMPABLE, 0, 0, 0, 0) // return unix.Prctl(unix.PR_SET_DUMPABLE, 0, 0, 0, 0)
return nil
} }

View File

@ -7,10 +7,12 @@ import (
"github.com/quexten/goldwarden/agent/bitwarden/crypto" "github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/bitwarden/models" "github.com/quexten/goldwarden/agent/bitwarden/models"
"github.com/rs/zerolog/log" "github.com/quexten/goldwarden/logging"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
var vaultLog = logging.GetLogger("Goldwarden", "Vault")
type Vault struct { type Vault struct {
Keyring *crypto.Keyring Keyring *crypto.Keyring
logins map[string]models.Cipher logins map[string]models.Cipher
@ -94,7 +96,7 @@ func (vault *Vault) isEnv(cipher models.Cipher) (string, bool) {
key, err := cipher.GetKeyForCipher(*vault.Keyring) key, err := cipher.GetKeyForCipher(*vault.Keyring)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to get key for cipher " + cipher.ID.String()) vaultLog.Error("Failed to get key for cipher "+cipher.ID.String(), err.Error())
return "", false return "", false
} }
@ -132,7 +134,7 @@ func (vault *Vault) isSSHKey(cipher models.Cipher) bool {
key, err := cipher.GetKeyForCipher(*vault.Keyring) key, err := cipher.GetKeyForCipher(*vault.Keyring)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to get key for cipher " + cipher.ID.String()) vaultLog.Error("Failed to get key for cipher "+cipher.ID.String(), err.Error())
return false return false
} }
@ -140,8 +142,12 @@ func (vault *Vault) isSSHKey(cipher models.Cipher) bool {
fieldName, err := crypto.DecryptWith(field.Name, key) fieldName, err := crypto.DecryptWith(field.Name, key)
if err != nil { if err != nil {
cipherID := cipher.ID.String() cipherID := cipher.ID.String()
if cipher.OrganizationID != nil {
orgID := cipher.OrganizationID.String() orgID := cipher.OrganizationID.String()
log.Warn().Err(err).Msg("Failed to decrypt field name with on cipher " + cipherID + " in organization " + orgID) vaultLog.Error("Failed to decrypt field name with on cipher "+cipherID+" in organization "+orgID, err.Error())
} else {
vaultLog.Error("Failed to decrypt field name with on cipher "+cipherID, err.Error())
}
continue continue
} }
fieldValue, err := crypto.DecryptWith(field.Value, key) fieldValue, err := crypto.DecryptWith(field.Value, key)
@ -229,7 +235,7 @@ func (vault *Vault) GetEnvCredentialForExecutable(executableName string) (map[st
if id, ok := vault.envCredentials[executableName]; ok { if id, ok := vault.envCredentials[executableName]; ok {
key, err := vault.secureNotes[id].GetKeyForCipher(*vault.Keyring) key, err := vault.secureNotes[id].GetKeyForCipher(*vault.Keyring)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to get key for cipher " + id) vaultLog.Error("Failed to get key for cipher " + id)
return make(map[string]string), false return make(map[string]string), false
} }
@ -302,7 +308,7 @@ func (vault *Vault) GetLoginByFilter(uuid string, orgId string, name string, use
key, err := cipher.GetKeyForCipher(*vault.Keyring) key, err := cipher.GetKeyForCipher(*vault.Keyring)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to get key for cipher " + cipher.ID.String()) vaultLog.Error("Failed to get key for cipher " + cipher.ID.String())
continue continue
} }
if name != "" { if name != "" {
@ -312,7 +318,7 @@ func (vault *Vault) GetLoginByFilter(uuid string, orgId string, name string, use
decryptedName, err := crypto.DecryptWith(cipher.Name, key) decryptedName, err := crypto.DecryptWith(cipher.Name, key)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to decrypt name for cipher " + cipher.ID.String()) vaultLog.Error("Failed to decrypt name for cipher " + cipher.ID.String())
continue continue
} }
if name != "" && string(decryptedName) != name { if name != "" && string(decryptedName) != name {
@ -327,7 +333,7 @@ func (vault *Vault) GetLoginByFilter(uuid string, orgId string, name string, use
decryptedUsername, err := crypto.DecryptWith(cipher.Login.Username, key) decryptedUsername, err := crypto.DecryptWith(cipher.Login.Username, key)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to decrypt username for cipher " + cipher.ID.String()) vaultLog.Error("Failed to decrypt username for cipher " + cipher.ID.String())
continue continue
} }
if username != "" && string(decryptedUsername) != username { if username != "" && string(decryptedUsername) != username {
@ -338,7 +344,7 @@ func (vault *Vault) GetLoginByFilter(uuid string, orgId string, name string, use
return cipher, nil return cipher, nil
} }
return models.Cipher{}, errors.New("Cipher not found") return models.Cipher{}, errors.New("cipher not found")
} }
func (vault *Vault) GetNoteByFilter(uuid string, orgId string, name string) (models.Cipher, error) { func (vault *Vault) GetNoteByFilter(uuid string, orgId string, name string) (models.Cipher, error) {
@ -355,12 +361,12 @@ func (vault *Vault) GetNoteByFilter(uuid string, orgId string, name string) (mod
key, err := cipher.GetKeyForCipher(*vault.Keyring) key, err := cipher.GetKeyForCipher(*vault.Keyring)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to get key for cipher " + cipher.ID.String()) vaultLog.Error("Failed to get key for cipher "+cipher.ID.String(), err.Error())
continue continue
} }
decryptedName, err := crypto.DecryptWith(cipher.Name, key) decryptedName, err := crypto.DecryptWith(cipher.Name, key)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to decrypt name for cipher " + cipher.ID.String()) vaultLog.Error("Failed to decrypt name for cipher "+cipher.ID.String(), err.Error())
continue continue
} }
if name != "" && string(decryptedName) != name { if name != "" && string(decryptedName) != name {

View File

@ -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"
) )
@ -89,9 +91,35 @@ var purgeCmd = &cobra.Command{
}, },
} }
var statusCmd = &cobra.Command{
Use: "status",
Short: "Shows the vault status",
Long: `Shows the vault status.`,
Run: func(cmd *cobra.Command, args []string) {
request := messages.VaultStatusRequest{}
result, err := commandClient.SendToAgent(request)
if err != nil {
handleSendToAgentError(err)
return
}
switch result.(type) {
case messages.VaultStatusResponse:
status := result.(messages.VaultStatusResponse)
fmt.Println("Locked: ", status.Locked)
fmt.Println("Number of logins: ", status.NumberOfLogins)
fmt.Println("Number of notes: ", status.NumberOfNotes)
default:
println("Wrong response type")
}
},
}
func init() { func init() {
rootCmd.AddCommand(vaultCmd) rootCmd.AddCommand(vaultCmd)
vaultCmd.AddCommand(unlockCmd) vaultCmd.AddCommand(unlockCmd)
vaultCmd.AddCommand(lockCmd) vaultCmd.AddCommand(lockCmd)
vaultCmd.AddCommand(purgeCmd) vaultCmd.AddCommand(purgeCmd)
vaultCmd.AddCommand(statusCmd)
} }

View File

@ -17,6 +17,17 @@ type WipeVaultRequest struct {
type GetVaultPINRequest struct { type GetVaultPINRequest struct {
} }
type VaultStatusRequest struct {
}
type VaultStatusResponse struct {
Locked bool
NumberOfLogins int
NumberOfNotes int
// todo websocket status
// todo last synced
}
func init() { func init() {
registerPayloadParser(func(payload []byte) (interface{}, error) { registerPayloadParser(func(payload []byte) (interface{}, error) {
var req LockVaultRequest var req LockVaultRequest
@ -62,4 +73,22 @@ func init() {
} }
return req, nil return req, nil
}, GetVaultPINRequest{}) }, GetVaultPINRequest{})
registerPayloadParser(func(payload []byte) (interface{}, error) {
var req VaultStatusRequest
err := json.Unmarshal(payload, &req)
if err != nil {
panic("Unmarshal: " + err.Error())
}
return req, nil
}, VaultStatusRequest{})
registerPayloadParser(func(payload []byte) (interface{}, error) {
var req VaultStatusResponse
err := json.Unmarshal(payload, &req)
if err != nil {
panic("Unmarshal: " + err.Error())
}
return req, nil
}, VaultStatusResponse{})
} }