2023-07-17 05:02:29 +02:00
|
|
|
package browserbiometrics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"encoding/json"
|
2024-03-15 15:59:35 +01:00
|
|
|
"fmt"
|
2023-07-17 05:02:29 +02:00
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
|
2023-12-30 18:53:01 +01:00
|
|
|
"github.com/quexten/goldwarden/agent/config"
|
2023-07-17 05:02:29 +02:00
|
|
|
"github.com/quexten/goldwarden/browserbiometrics/logging"
|
|
|
|
"github.com/quexten/goldwarden/client"
|
2023-09-20 03:05:44 +02:00
|
|
|
"github.com/quexten/goldwarden/ipc/messages"
|
2023-07-17 05:02:29 +02:00
|
|
|
)
|
|
|
|
|
2023-12-30 18:53:01 +01:00
|
|
|
var runtimeConfig *config.RuntimeConfig
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
func readLoop(rtCfg *config.RuntimeConfig) error {
|
2023-12-30 18:53:01 +01:00
|
|
|
runtimeConfig = rtCfg
|
2023-07-17 05:02:29 +02:00
|
|
|
v := bufio.NewReader(os.Stdin)
|
|
|
|
s := bufio.NewReaderSize(v, bufferSize)
|
|
|
|
|
|
|
|
lengthBytes := make([]byte, 4)
|
|
|
|
lengthNum := int(0)
|
|
|
|
|
2023-12-22 15:29:58 +01:00
|
|
|
logging.Debugf("Sending connected message")
|
2024-03-15 15:59:35 +01:00
|
|
|
err := send(SendMessage{
|
2023-07-17 05:02:29 +02:00
|
|
|
Command: "connected",
|
|
|
|
AppID: appID,
|
|
|
|
})
|
2024-03-15 15:59:35 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
|
2023-12-22 15:29:58 +01:00
|
|
|
logging.Debugf("Starting read loop")
|
2023-07-17 05:02:29 +02:00
|
|
|
for b, err := s.Read(lengthBytes); b > 0 && err == nil; b, err = s.Read(lengthBytes) {
|
2024-03-15 15:59:35 +01:00
|
|
|
lengthNum, err = readMessageLength(lengthBytes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
|
|
|
|
content := make([]byte, lengthNum)
|
|
|
|
_, err := s.Read(content)
|
|
|
|
if err != nil && err != io.EOF {
|
2024-03-15 15:59:35 +01:00
|
|
|
return err
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
err = parseMessage(content)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
return nil
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
func parseMessage(msg []byte) error {
|
2023-07-17 05:02:29 +02:00
|
|
|
logging.Debugf("Received message: " + string(msg))
|
|
|
|
|
|
|
|
var genericMessage GenericRecvMessage
|
|
|
|
err := json.Unmarshal(msg, &genericMessage)
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return fmt.Errorf("unable to unmarshal json to struct: %w", err)
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
|
2023-07-17 05:02:29 +02:00
|
|
|
if _, ok := (genericMessage.Message.(map[string]interface{})["command"]); ok {
|
|
|
|
logging.Debugf("Message is unencrypted")
|
|
|
|
|
|
|
|
var unmsg UnencryptedRecvMessage
|
|
|
|
err := json.Unmarshal(msg, &unmsg)
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return fmt.Errorf("unable to unmarshal json to struct: %w", err)
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
err = handleUnencryptedMessage(unmsg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
} else {
|
|
|
|
logging.Debugf("Message is encrypted")
|
|
|
|
|
|
|
|
var encmsg EncryptedRecvMessage
|
|
|
|
err := json.Unmarshal(msg, &encmsg)
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return fmt.Errorf("unable to unmarshal json to struct: %w", err)
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
decryptedMessage, err := decryptStringSymmetric(transportKey, encmsg.Message.IV, encmsg.Message.Data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
var payloadMsg PayloadMessage
|
|
|
|
err = json.Unmarshal([]byte(decryptedMessage), &payloadMsg)
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return fmt.Errorf("unable to unmarshal json to struct: %w", err)
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
err = handlePayloadMessage(payloadMsg, genericMessage.AppID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
|
|
|
|
return nil
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
func handleUnencryptedMessage(msg UnencryptedRecvMessage) error {
|
2023-07-17 05:02:29 +02:00
|
|
|
logging.Debugf("Received unencrypted message: %+v", msg.Message)
|
|
|
|
logging.Debugf(" with command: %s", msg.Message.Command)
|
|
|
|
|
|
|
|
switch msg.Message.Command {
|
|
|
|
case "setupEncryption":
|
|
|
|
sharedSecret, err := rsaEncrypt(msg.Message.PublicKey, transportKey)
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return err
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
err = send(SendMessage{
|
2023-07-17 05:02:29 +02:00
|
|
|
Command: "setupEncryption",
|
|
|
|
AppID: msg.AppID,
|
|
|
|
SharedSecret: sharedSecret,
|
|
|
|
})
|
2024-03-15 15:59:35 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
|
|
|
|
return nil
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
|
|
|
|
func handlePayloadMessage(msg PayloadMessage, appID string) error {
|
2023-07-17 05:02:29 +02:00
|
|
|
logging.Debugf("Received unencrypted message: %+v", msg)
|
|
|
|
|
|
|
|
switch msg.Command {
|
|
|
|
case "biometricUnlock":
|
|
|
|
logging.Debugf("Biometric unlock requested")
|
|
|
|
// logging.Debugf("Biometrics authorized: %t", isAuthorized)
|
2024-02-18 06:08:37 +01:00
|
|
|
|
|
|
|
home, err := os.UserHomeDir()
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return err
|
2024-02-18 06:08:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if runtimeConfig.GoldwardenSocketPath == "" {
|
|
|
|
if _, err := os.Stat(home + "/.goldwarden.sock"); err == nil {
|
|
|
|
runtimeConfig.GoldwardenSocketPath = home + "/.goldwarden.sock"
|
|
|
|
} else if _, err := os.Stat(home + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock"); err == nil {
|
|
|
|
runtimeConfig.GoldwardenSocketPath = home + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock"
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = os.Stat("/.flatpak-info"); err == nil {
|
|
|
|
runtimeConfig.GoldwardenSocketPath = home + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-19 08:24:26 +01:00
|
|
|
logging.Debugf("Connecting to agent at path %s", runtimeConfig.GoldwardenSocketPath)
|
2024-02-18 06:08:37 +01:00
|
|
|
|
2023-12-30 18:53:01 +01:00
|
|
|
result, err := client.NewUnixSocketClient(runtimeConfig).SendToAgent(messages.GetBiometricsKeyRequest{})
|
2023-07-17 05:02:29 +02:00
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return fmt.Errorf("Unable to send message to agent: %w", err)
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
switch result := result.(type) {
|
|
|
|
case messages.GetBiometricsKeyResponse:
|
|
|
|
var key = result.Key
|
2023-07-17 05:02:29 +02:00
|
|
|
var payloadMsg ReceiveMessage = ReceiveMessage{
|
|
|
|
Command: "biometricUnlock",
|
|
|
|
Response: "unlocked",
|
|
|
|
Timestamp: msg.Timestamp,
|
|
|
|
KeyB64: key,
|
|
|
|
}
|
|
|
|
payloadStr, err := json.Marshal(payloadMsg)
|
|
|
|
if err != nil {
|
2024-03-15 15:59:35 +01:00
|
|
|
return err
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
logging.Debugf("Payload: %s", payloadStr)
|
|
|
|
|
2024-03-15 15:59:35 +01:00
|
|
|
encStr, err := encryptStringSymmetric(transportKey, payloadStr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = send(SendMessage{
|
2023-07-17 05:02:29 +02:00
|
|
|
AppID: appID,
|
|
|
|
Message: encStr,
|
|
|
|
})
|
2024-03-15 15:59:35 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|
|
|
|
}
|
2024-03-15 15:59:35 +01:00
|
|
|
|
|
|
|
return nil
|
2023-07-17 05:02:29 +02:00
|
|
|
}
|