Refactor platform abstractions

This commit is contained in:
Bernd Schoolmann 2023-09-12 02:54:46 +02:00
parent 5490eb2cb1
commit a566d71223
No known key found for this signature in database
24 changed files with 94 additions and 39 deletions

View File

@ -6,14 +6,14 @@ import (
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/ipc"
)
func handleGetBiometricsKey(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx sockets.CallingContext) (response interface{}, err error) {
if approved, err := systemauth.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 = ipc.IPCMessageFromPayload(ipc.ActionResponse{
Success: false,
Message: "not approved",

View File

@ -5,8 +5,8 @@ import (
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/ipc"
)
@ -14,7 +14,7 @@ import (
func handleGetCliCredentials(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx sockets.CallingContext) (response interface{}, err error) {
req := request.ParsedPayload().(ipc.GetCLICredentialsRequest)
if approved, err := systemauth.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access credentials for %s", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName, req.ApplicationName)); err != nil || !approved {
if approved, err := pinentry.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access credentials for %s", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName, req.ApplicationName)); err != nil || !approved {
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
Success: false,
Message: "not approved",

View File

@ -10,8 +10,8 @@ import (
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/ipc"
)
@ -83,7 +83,7 @@ func handleGetLoginCipher(request ipc.IPCMessage, cfg *config.Config, vault *vau
}
}
if approved, err := systemauth.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access credentials for user %s on entry %s", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName, decryptedLogin.Username, decryptedLogin.Name)); err != nil || !approved {
if approved, err := pinentry.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access credentials for user %s on entry %s", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName, decryptedLogin.Username, decryptedLogin.Name)); err != nil || !approved {
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
Success: false,
Message: "not approved",
@ -101,7 +101,7 @@ func handleGetLoginCipher(request ipc.IPCMessage, cfg *config.Config, vault *vau
}
func handleListLoginsRequest(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx sockets.CallingContext) (response interface{}, err error) {
if approved, err := systemauth.GetApproval("Approve List Credentials", fmt.Sprintf("%s on %s>%s>%s is trying to list credentials (name & username)", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
if approved, err := pinentry.GetApproval("Approve List Credentials", fmt.Sprintf("%s on %s>%s>%s is trying to list credentials (name & username)", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
Success: false,
Message: "not approved",

View File

@ -8,8 +8,8 @@ import (
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/ipc"
)
@ -140,7 +140,7 @@ func handleWipeVault(request ipc.IPCMessage, cfg *config.Config, vault *vault.Va
}
func handleUpdateVaultPin(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext sockets.CallingContext) (response interface{}, err error) {
pin, err := systemauth.GetPassword("Pin Change", "Enter your desired pin")
pin, err := pinentry.GetPassword("Pin Change", "Enter your desired pin")
if err != nil {
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
Success: false,

View File

@ -18,7 +18,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/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/logging"
"golang.org/x/crypto/pbkdf2"
@ -76,7 +76,7 @@ func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Conf
var masterKey crypto.MasterKey
var hashedPassword string
password, err := systemauth.GetPassword("Bitwarden Password", "Enter your Bitwarden password")
password, err := pinentry.GetPassword("Bitwarden Password", "Enter your Bitwarden password")
if err != nil {
return LoginResponseToken{}, crypto.MasterKey{}, "", err
}

View File

@ -11,7 +11,7 @@ import (
"github.com/keys-pub/go-libfido2"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
)
const isFido2Enabled = true
@ -61,7 +61,7 @@ func Fido2TwoFactor(challengeB64 string, credentials []string, config *config.Co
clientDataHash := sha256.Sum256([]byte(clientDataJson))
clientDataJson = base64.URLEncoding.EncodeToString([]byte(clientDataJson))
pin, err := systemauth.GetPassword("Fido2 PIN", "Enter your token's PIN")
pin, err := pinentry.GetPassword("Fido2 PIN", "Enter your token's PIN")
if err != nil {
twofactorLog.Fatal(err.Error())
}

View File

@ -6,7 +6,7 @@ import (
"strconv"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/logging"
)
@ -33,11 +33,11 @@ func PerformSecondFactor(resp *TwoFactorResponse, cfg *config.Config) (TwoFactor
}
}
if _, isInMap := resp.TwoFactorProviders2[Authenticator]; isInMap {
token, err := systemauth.GetPassword("Authenticator Second Factor", "Enter your two-factor auth code")
token, err := pinentry.GetPassword("Authenticator Second Factor", "Enter your two-factor auth code")
return Authenticator, []byte(token), err
}
if _, isInMap := resp.TwoFactorProviders2[Email]; isInMap {
token, err := systemauth.GetPassword("Email Second Factor", "Enter your two-factor auth code")
token, err := pinentry.GetPassword("Email Second Factor", "Enter your two-factor auth code")
return Email, []byte(token), err
}

View File

@ -13,8 +13,8 @@ import (
"github.com/gorilla/websocket"
"github.com/quexten/goldwarden/agent/bitwarden/models"
"github.com/quexten/goldwarden/agent/config"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/logging"
"github.com/vmihailenco/msgpack/v5"
@ -179,7 +179,7 @@ func connectToWebsocket(ctx context.Context, vault *vault.Vault, cfg *config.Con
}
websocketLog.Info("AuthRequest details " + authRequest.RequestIpAddress + " " + authRequest.RequestDeviceType)
if approved, err := systemauth.GetApproval("Paswordless Login Request", "Do you want to allow "+authRequest.RequestIpAddress+" ("+authRequest.RequestDeviceType+") to login to your account?"); err != nil || !approved {
if approved, err := pinentry.GetApproval("Paswordless Login Request", "Do you want to allow "+authRequest.RequestIpAddress+" ("+authRequest.RequestDeviceType+") to login to your account?"); err != nil || !approved {
websocketLog.Info("AuthRequest denied")
break
}

View File

@ -13,7 +13,7 @@ import (
"github.com/awnumar/memguard"
"github.com/google/uuid"
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/tink-crypto/tink-go/v2/aead/subtle"
"golang.org/x/crypto/argon2"
@ -395,7 +395,7 @@ func ReadConfig(rtCfg RuntimeConfig) (Config, error) {
}
func (cfg *Config) TryUnlock(vault *vault.Vault) error {
pin, err := systemauth.GetPassword("Unlock Goldwarden", "Enter the vault PIN")
pin, err := pinentry.GetPassword("Unlock Goldwarden", "Enter the vault PIN")
if err != nil {
return err
}

View File

@ -27,6 +27,7 @@ func GetCallingContext(connection net.Conn) CallingContext {
if err != nil {
panic(err)
}
parentProcess, err := gops.FindProcess(ppid)
if err != nil {
panic(err)

View File

@ -9,8 +9,8 @@ import (
"os"
"github.com/quexten/goldwarden/agent/sockets"
"github.com/quexten/goldwarden/agent/systemauth"
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/agent/vault"
"github.com/quexten/goldwarden/logging"
"golang.org/x/crypto/ssh"
@ -95,7 +95,7 @@ func (vaultAgent vaultAgent) Sign(key ssh.PublicKey, data []byte) (*ssh.Signatur
message := fmt.Sprintf("%s on %s>%s>%s is requesting signage with key %s", vaultAgent.context.UserName, vaultAgent.context.GrandParentProcessName, vaultAgent.context.ParentProcessName, vaultAgent.context.ProcessName, sshKey.Name)
if approved, err := systemauth.GetApproval("SSH Key Signing Request", message); err != nil || !approved {
if approved, err := pinentry.GetApproval("SSH Key Signing Request", message); err != nil || !approved {
log.Info("Sign Request for key: %s denied", sshKey.Name)
return nil, errors.New("Approval not given")
}

View File

@ -2,17 +2,21 @@
package biometrics
import (
touchid "github.com/lox/go-touchid"
)
func CheckBiometrics(approvalType Approval) bool {
ok, err := touchid.Authenticate(approvalType.String())
if err != nil {
log.Fatal(err)
log.Error(err)
}
if ok {
log.Printf("Authenticated")
log.Info("Authenticated")
return true
} else {
log.Fatal("Failed to authenticate")
log.Error("Failed to authenticate")
return false
}
}

View File

@ -0,0 +1,8 @@
//go:build windows
package biometrics
func CheckBiometrics(approvalType Approval) bool {
log.Info("Biometrics undefined on windows... skipping")
return true
}

View File

@ -1,4 +1,6 @@
package systemauth
//go:build linux || freebsd
package pinentry
import (
"errors"

View File

@ -1,4 +1,4 @@
package systemauth
package pinentry
import (
"os"
@ -6,8 +6,7 @@ import (
"github.com/quexten/goldwarden/logging"
)
var log = logging.GetLogger("Goldwarden", "Systemauth")
var log = logging.GetLogger("Goldwarden", "Pinentry")
var systemAuthDisabled = false
func init() {

View File

@ -0,0 +1,13 @@
//go:build !linux && !freebsd
package pinentry
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) {
log.Info("Asking for approval is not implemented on this platform")
return true, errors.New("Not implemented")
}

View File

@ -6,7 +6,7 @@ import (
"errors"
"github.com/atotto/clipboard"
"github.com/quexten/goldwarden/autofill/uinput"
"github.com/quexten/goldwarden/autofill/autotype"
"github.com/quexten/goldwarden/client"
"github.com/quexten/goldwarden/ipc"
)
@ -72,14 +72,14 @@ func Run(layout string, useCopyPaste bool, client client.Client) {
if useCopyPaste {
clipboard.WriteAll(string(login.Username))
uinput.Paste(layout)
uinput.TypeString(string(uinput.KeyTab), layout)
autotype.Paste(layout)
autotype.TypeString("\t", layout)
clipboard.WriteAll(login.Password)
uinput.Paste(layout)
autotype.Paste(layout)
} else {
uinput.TypeString(string(login.Username), layout)
uinput.TypeString(string(uinput.KeyTab), layout)
uinput.TypeString(string(login.Password), layout)
autotype.TypeString(string(login.Username), layout)
autotype.TypeString("\t", layout)
autotype.TypeString(string(login.Password), layout)
}
clipboard.WriteAll(login.TwoFactorCode)

View File

@ -0,0 +1,13 @@
//go:build linux
package autotype
import "github.com/quexten/goldwarden/autofill/autotype/uinput"
func TypeString(text string, layout string) error {
return uinput.TypeString(text, layout)
}
func Paste(layout string) error {
return uinput.Paste(layout)
}

View File

@ -0,0 +1,7 @@
//go:build !linux
package autotype
func TypeString(text string, layout string) error {
return errors.New("Not implemented")
}

6
go.mod
View File

@ -19,9 +19,9 @@ require (
github.com/tink-crypto/tink-go/v2 v2.0.0
github.com/twpayne/go-pinentry v0.2.0
github.com/vmihailenco/msgpack/v5 v5.3.5
golang.org/x/crypto v0.11.0
golang.org/x/crypto v0.13.0
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
golang.org/x/sys v0.10.0
golang.org/x/sys v0.12.0
)
require (
@ -38,7 +38,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 // indirect
golang.org/x/image v0.5.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/text v0.13.0 // indirect
)
require (

8
go.sum
View File

@ -105,12 +105,15 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 h1:ryT6Nf0R83ZgD8WnFFdfI8wCeyqgdXWN4+CkFVNPAT0=
@ -141,15 +144,20 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=