Add notification support to the goldwarden daemon

This commit is contained in:
Bernd Schoolmann 2023-12-28 12:58:02 +01:00
parent 8263094c03
commit 5c7de72da7
No known key found for this signature in database
7 changed files with 101 additions and 1 deletions

View File

@ -17,6 +17,7 @@ import (
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/bitwarden/twofactor"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/notify"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/logging"
@ -68,6 +69,7 @@ func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Conf
if err := authenticatedHTTPPost(ctx, cfg.ConfigFile.ApiUrl+"/accounts/prelogin", &preLogin, preLoginRequest{
Email: email,
}); err != nil {
notify.Notify("Goldwarden", fmt.Sprintf("Could not pre-login: %v", err), "", func() {})
return LoginResponseToken{}, crypto.MasterKey{}, "", fmt.Errorf("could not pre-login: %v", err)
}
@ -77,11 +79,13 @@ func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Conf
password, err := pinentry.GetPassword("Bitwarden Password", "Enter your Bitwarden password")
if err != nil {
notify.Notify("Goldwarden", fmt.Sprintf("Could not get password: %v", err), "", func() {})
return LoginResponseToken{}, crypto.MasterKey{}, "", err
}
masterKey, err = crypto.DeriveMasterKey([]byte(strings.Clone(password)), email, crypto.KDFConfig{Type: crypto.KDFType(preLogin.KDF), Iterations: uint32(preLogin.KDFIterations), Memory: uint32(preLogin.KDFMemory), Parallelism: uint32(preLogin.KDFParallelism)})
if err != nil {
notify.Notify("Goldwarden", fmt.Sprintf("Could not derive master key: %v", err), "", func() {})
return LoginResponseToken{}, crypto.MasterKey{}, "", err
}
@ -104,12 +108,14 @@ func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Conf
if ok && bytes.Contains(errsc.body, []byte("TwoFactor")) {
loginResponseToken, err = Perform2FA(values, errsc, cfg, ctx)
if err != nil {
notify.Notify("Goldwarden", fmt.Sprintf("Could not login via two-factor: %v", err), "", func() {})
return LoginResponseToken{}, crypto.MasterKey{}, "", err
}
} else if err != nil && strings.Contains(err.Error(), "Captcha required.") {
notify.Notify("Goldwarden", fmt.Sprintf("Captcha required"), "", func() {})
return LoginResponseToken{}, crypto.MasterKey{}, "", fmt.Errorf("captcha required, please login via the web interface")
} else if err != nil {
notify.Notify("Goldwarden", fmt.Sprintf("Could not login via password: %v", err), "", func() {})
return LoginResponseToken{}, crypto.MasterKey{}, "", fmt.Errorf("could not login via password: %v", err)
}

View File

@ -10,6 +10,7 @@ import (
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/bitwarden/models"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/notify"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/logging"
)
@ -34,6 +35,7 @@ func DoFullSync(ctx context.Context, vault *vault.Vault, config *config.Config,
sync, err := Sync(ctx, config)
if err != nil {
log.Error("Could not sync: %v", err)
notify.Notify("Goldwarden", "Could not sync", "", func() {})
if allowCache {
home, _ := os.UserHomeDir()
sync, err = ReadVault(home + path)

View File

@ -13,6 +13,7 @@ import (
"github.com/google/uuid"
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/notify"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/tink-crypto/tink-go/v2/aead/subtle"
@ -146,6 +147,7 @@ func (c *Config) Lock() {
return
}
(*c.key).Wipe()
notify.Notify("Goldwarden", "Vault Locked", "", func() {})
}
func (c *Config) Purge() {

69
agent/notify/dbus.go Normal file
View File

@ -0,0 +1,69 @@
//go:build linux || freebsd
package notify
import (
"github.com/godbus/dbus/v5"
)
var closeListenerMap = make(map[uint32]func())
func Notify(title string, body string, actionName string, onclose func()) error {
bus, err := dbus.SessionBus()
if err != nil {
return err
}
obj := bus.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
actions := []string{}
if actionName != "" {
actions = append(actions, actionName)
}
call := obj.Call("org.freedesktop.Notifications.Notify", 0, "goldwarden", uint32(0), "", title, body, actions, map[string]dbus.Variant{}, int32(60000))
if call.Err != nil {
return call.Err
}
if len(call.Body) < 1 {
return nil
}
id := call.Body[0].(uint32)
closeListenerMap[id] = onclose
return nil
}
func ListenForNotifications() error {
bus, err := dbus.SessionBus()
if err != nil {
return err
}
err = bus.AddMatchSignal(dbus.WithMatchInterface("org.freedesktop.Notifications"))
if err != nil {
return err
}
signals := make(chan *dbus.Signal, 10)
bus.Signal(signals)
for {
select {
case message := <-signals:
if message.Name == "org.freedesktop.Notifications.NotificationClosed" {
if len(message.Body) < 1 {
continue
}
id, ok := message.Body[0].(uint32)
if !ok {
continue
}
if id == 0 {
continue
}
if closeListener, ok := closeListenerMap[id]; ok {
delete(closeListenerMap, id)
closeListener()
}
}
}
}
return nil
}

View File

@ -0,0 +1,12 @@
//go:build windows || darwin
package notify
func Notify(title string, body string) error {
// no notifications on windows or darwin
return nil
}
func ListenForNotifications() error {
return nil
}

View File

@ -9,6 +9,7 @@ import (
"os"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/notify"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
@ -113,6 +114,7 @@ func (vaultAgent vaultAgent) Sign(key ssh.PublicKey, data []byte) (*ssh.Signatur
var rand = rand.Reader
log.Info("Sign Request for key: %s %s accepted", ssh.FingerprintSHA256(key), sshKey.Name)
notify.Notify("Goldwarden", fmt.Sprintf("SSH Key Signing Request Approved for %s", sshKey.Name), "", func() {})
return signer.Sign(rand, data)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/quexten/goldwarden/agent/bitwarden"
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/notify"
"github.com/quexten/goldwarden/agent/processsecurity"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/ssh"
@ -181,6 +182,12 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error {
log.Warn("Could not monitor idle: %s", err.Error())
}
}()
go func() {
err = notify.ListenForNotifications()
if err != nil {
log.Warn("Could not listen for notifications: %s", err.Error())
}
}()
go func() {
if !runtimeConfig.WebsocketDisabled {