mirror of
https://github.com/quexten/goldwarden.git
synced 2024-10-05 15:07:43 +03:00
Compare commits
10 Commits
9ae9401542
...
1c9bf6101b
Author | SHA1 | Date | |
---|---|---|---|
|
1c9bf6101b | ||
|
9a0ffded83 | ||
|
97a485712e | ||
|
79bfc43ab8 | ||
|
d32147bdf8 | ||
|
53271c3331 | ||
|
5af6771460 | ||
|
2651a36d3c | ||
|
a41c91ca6b | ||
|
275ba9a3d2 |
@ -16,12 +16,24 @@ import (
|
||||
func handleAddSSH(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||
req := messages.ParsePayload(msg).(messages.CreateSSHKeyRequest)
|
||||
|
||||
cipher, publicKey := ssh.NewSSHKeyCipher(req.Name, vault.Keyring)
|
||||
cipher, publicKey, err := ssh.NewSSHKeyCipher(req.Name, vault.Keyring)
|
||||
if err != nil {
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := cfg.GetToken()
|
||||
@ -56,7 +68,49 @@ func handleListSSH(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vau
|
||||
return
|
||||
}
|
||||
|
||||
func handleImportSSH(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||
req := messages.ParsePayload(msg).(messages.ImportSSHKeyRequest)
|
||||
|
||||
cipher, _, err := ssh.SSHKeyCipherFromKey(req.Name, req.Key, vault.Keyring)
|
||||
if err != nil {
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: true,
|
||||
})
|
||||
if err != nil {
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := cfg.GetToken()
|
||||
if err != nil {
|
||||
actionsLog.Warn(err.Error())
|
||||
}
|
||||
ctx := context.WithValue(context.TODO(), bitwarden.AuthToken{}, token.AccessToken)
|
||||
postedCipher, err := bitwarden.PostCipher(ctx, cipher, cfg)
|
||||
if err == nil {
|
||||
vault.AddOrUpdateSecureNote(postedCipher)
|
||||
} else {
|
||||
actionsLog.Warn("Error posting ssh key cipher: " + err.Error())
|
||||
}
|
||||
|
||||
response, err = messages.IPCMessageFromPayload(messages.ImportSSHKeyResponse{
|
||||
Success: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.CreateSSHKeyRequest{}), ensureEverything(systemauth.SSHKey, handleAddSSH))
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetSSHKeysRequest{}), ensureIsNotLocked(ensureIsLoggedIn(handleListSSH)))
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.ImportSSHKeyRequest{}), ensureEverything(systemauth.SSHKey, handleImportSSH))
|
||||
}
|
||||
|
@ -255,12 +255,11 @@ func parseMessageTypeFromMessagePack(messagePack []byte) (int8, string, bool) {
|
||||
return 0, "", false
|
||||
}
|
||||
if len(value) < 5 {
|
||||
websocketLog.Warn("Invalid message received, length too short")
|
||||
return 0, "", false
|
||||
}
|
||||
value, success := value[4].([]interface{})
|
||||
if len(value) < 1 || !success {
|
||||
websocketLog.Warn("Invalid message received, length too short")
|
||||
websocketLog.Warn("Invalid message received, value length less than 1")
|
||||
return 0, "", false
|
||||
}
|
||||
value1, success := value[0].(map[string]interface{})
|
||||
|
@ -12,8 +12,55 @@ import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func NewSSHKeyCipher(name string, keyring *crypto.Keyring) (models.Cipher, string) {
|
||||
// todo refactor to share code
|
||||
func SSHKeyCipherFromKey(name string, privateKey string, keyring *crypto.Keyring) (models.Cipher, string, error) {
|
||||
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return models.Cipher{}, "", err
|
||||
}
|
||||
|
||||
pubKey := signer.PublicKey()
|
||||
encryptedName, _ := crypto.EncryptWith([]byte(name), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPublicKeyKey, _ := crypto.EncryptWith([]byte("public-key"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPublicKeyValue, _ := crypto.EncryptWith([]byte(string(ssh.MarshalAuthorizedKey(pubKey))), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedCustomTypeKey, _ := crypto.EncryptWith([]byte("custom-type"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedCustomTypeValue, _ := crypto.EncryptWith([]byte("ssh-key"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPrivateKeyKey, _ := crypto.EncryptWith([]byte("private-key"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPrivateKeyValue, _ := crypto.EncryptWith([]byte(privateKey), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
|
||||
cipher := models.Cipher{
|
||||
Type: models.CipherNote,
|
||||
Name: encryptedName,
|
||||
Notes: &encryptedPublicKeyValue,
|
||||
ID: nil,
|
||||
Favorite: false,
|
||||
OrganizationID: nil,
|
||||
SecureNote: &models.SecureNoteCipher{
|
||||
Type: 0,
|
||||
},
|
||||
Fields: []models.Field{
|
||||
{
|
||||
Type: 0,
|
||||
Name: encryptedCustomTypeKey,
|
||||
Value: encryptedCustomTypeValue,
|
||||
},
|
||||
{
|
||||
Type: 0,
|
||||
Name: encryptedPublicKeyKey,
|
||||
Value: encryptedPublicKeyValue,
|
||||
},
|
||||
{
|
||||
Type: 1,
|
||||
Name: encryptedPrivateKeyKey,
|
||||
Value: encryptedPrivateKeyValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return cipher, string(ssh.MarshalAuthorizedKey(pubKey)), nil
|
||||
}
|
||||
|
||||
func NewSSHKeyCipher(name string, keyring *crypto.Keyring) (models.Cipher, string, error) {
|
||||
var reader io.Reader = rand.Reader
|
||||
pub, priv, err := ed25519.GenerateKey(reader)
|
||||
|
||||
@ -72,5 +119,5 @@ func NewSSHKeyCipher(name string, keyring *crypto.Keyring) (models.Cipher, strin
|
||||
},
|
||||
}
|
||||
|
||||
return cipher, string(ssh.MarshalAuthorizedKey(publicKey))
|
||||
return cipher, string(ssh.MarshalAuthorizedKey(publicKey)), nil
|
||||
}
|
||||
|
@ -1,16 +1,22 @@
|
||||
//go:build freebsd || linux
|
||||
//go:build freebsd || linux || darwin
|
||||
|
||||
package pinentry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
|
||||
"github.com/twpayne/go-pinentry"
|
||||
)
|
||||
|
||||
func getPassword(title string, description string) (string, error) {
|
||||
binaryClientOption := pinentry.WithBinaryNameFromGnuPGAgentConf()
|
||||
if runtime.GOOS == "darwin" {
|
||||
binaryClientOption = pinentry.WithBinaryName("pinentry-mac")
|
||||
}
|
||||
|
||||
client, err := pinentry.NewClient(
|
||||
pinentry.WithBinaryNameFromGnuPGAgentConf(),
|
||||
binaryClientOption,
|
||||
pinentry.WithGPGTTY(),
|
||||
pinentry.WithTitle(title),
|
||||
pinentry.WithDesc(description),
|
||||
|
@ -1,4 +1,4 @@
|
||||
//go:build windows || darwin
|
||||
//go:build windows
|
||||
|
||||
package pinentry
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@ -92,6 +93,59 @@ var listSSHCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var importSSHCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Imports an SSH key into your vault",
|
||||
Long: `Imports an SSH key into your vault.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
filename := args[0]
|
||||
fmt.Println("Importing SSH key from " + filename)
|
||||
|
||||
name, _ := cmd.Flags().GetString("name")
|
||||
if name == "" {
|
||||
name = "Imported SSH Key"
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
fmt.Println("Error: File does not exist")
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
fmt.Println("Error: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(file)
|
||||
key := buf.String()
|
||||
|
||||
result, err := commandClient.SendToAgent(messages.ImportSSHKeyRequest{
|
||||
Key: key,
|
||||
Name: name,
|
||||
})
|
||||
if err != nil {
|
||||
handleSendToAgentError(err)
|
||||
return
|
||||
}
|
||||
|
||||
switch result.(type) {
|
||||
case messages.ImportSSHKeyResponse:
|
||||
response := result.(messages.ImportSSHKeyResponse)
|
||||
if response.Success {
|
||||
fmt.Println("Success")
|
||||
} else {
|
||||
fmt.Println("Error: " + response.ErrorMsg)
|
||||
}
|
||||
return
|
||||
case messages.ActionResponse:
|
||||
fmt.Println("Error: " + result.(messages.ActionResponse).Message)
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(sshCmd)
|
||||
sshCmd.AddCommand(sshAddCmd)
|
||||
@ -99,4 +153,6 @@ func init() {
|
||||
_ = sshAddCmd.MarkFlagRequired("name")
|
||||
sshAddCmd.PersistentFlags().Bool("clipboard", false, "Copy the public key to the clipboard")
|
||||
sshCmd.AddCommand(listSSHCmd)
|
||||
importSSHCmd.PersistentFlags().String("name", "", "")
|
||||
sshCmd.AddCommand(importSSHCmd)
|
||||
}
|
||||
|
@ -17,6 +17,16 @@ type GetSSHKeysResponse struct {
|
||||
Keys []string
|
||||
}
|
||||
|
||||
type ImportSSHKeyRequest struct {
|
||||
Key string
|
||||
Name string
|
||||
}
|
||||
|
||||
type ImportSSHKeyResponse struct {
|
||||
Success bool
|
||||
ErrorMsg string
|
||||
}
|
||||
|
||||
func init() {
|
||||
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||
var req CreateSSHKeyRequest
|
||||
@ -53,4 +63,22 @@ func init() {
|
||||
}
|
||||
return req, nil
|
||||
}, GetSSHKeysResponse{})
|
||||
|
||||
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||
var req ImportSSHKeyRequest
|
||||
err := json.Unmarshal(payload, &req)
|
||||
if err != nil {
|
||||
panic("Unmarshal: " + err.Error())
|
||||
}
|
||||
return req, nil
|
||||
}, ImportSSHKeyRequest{})
|
||||
|
||||
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||
var req ImportSSHKeyResponse
|
||||
err := json.Unmarshal(payload, &req)
|
||||
if err != nil {
|
||||
panic("Unmarshal: " + err.Error())
|
||||
}
|
||||
return req, nil
|
||||
}, ImportSSHKeyResponse{})
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import src.linux.main as linux_main
|
||||
|
||||
linux_main.main()
|
||||
import platform
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
import src.macos.main as macos_main
|
||||
macos_main.main()
|
||||
elif platform.system() == 'Linux':
|
||||
import src.linux.main as linux_main
|
||||
linux_main.main()
|
||||
else:
|
||||
print("Unsupported OS " + platform.system() + "... exiting...")
|
@ -1,10 +1,10 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
gi.require_version('Notify', '0.7')
|
||||
# gi.require_version('Notify', '0.7')
|
||||
import gc
|
||||
import time
|
||||
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
|
||||
from gi.repository import Gtk, Adw, GLib, Gdk
|
||||
from ..services import goldwarden
|
||||
from ..services.autotype import autotype
|
||||
from threading import Thread
|
||||
@ -12,7 +12,6 @@ from .resource_loader import load_template
|
||||
import sys
|
||||
import os
|
||||
from ..services import totp
|
||||
Notify.init("Goldwarden")
|
||||
|
||||
class GoldwardenQuickAccessApp(Adw.Application):
|
||||
def __init__(self, **kwargs):
|
||||
@ -115,8 +114,8 @@ class GoldwardenQuickAccessApp(Adw.Application):
|
||||
|
||||
def run_autotype(self, text):
|
||||
def perform_autotype(text):
|
||||
self.window.hide()
|
||||
time.sleep(0.1)
|
||||
GLib.idle_add(self.window.hide)
|
||||
time.sleep(2)
|
||||
autotype.autotype(text)
|
||||
time.sleep(0.1)
|
||||
os._exit(0)
|
||||
@ -148,7 +147,7 @@ class GoldwardenQuickAccessApp(Adw.Application):
|
||||
self.filtered_logins = self.filtered_logins[0:7]
|
||||
|
||||
def render_list(self):
|
||||
if len(self.filtered_logins) > 1:
|
||||
if len(self.filtered_logins) > 0:
|
||||
self.results_list.set_visible(True)
|
||||
while self.results_list.get_first_child() != None:
|
||||
self.results_list.remove(self.results_list.get_first_child())
|
||||
|
@ -101,8 +101,7 @@ class GoldwardenSettingsApp(Adw.Application):
|
||||
if status == None:
|
||||
is_daemon_running = goldwarden.is_daemon_running()
|
||||
if not is_daemon_running:
|
||||
self.status_row.set_subtitle("Daemon not running")
|
||||
self.vault_status_icon.set_icon("dialog-error", "error")
|
||||
print("Daemon not running")
|
||||
return
|
||||
|
||||
logged_in = status["loggedIn"]
|
||||
|
30
gui/src/macos/main.py
Normal file
30
gui/src/macos/main.py
Normal file
@ -0,0 +1,30 @@
|
||||
import sys
|
||||
import subprocess
|
||||
import os
|
||||
import secrets
|
||||
from src.services import goldwarden
|
||||
from src.services import pinentry
|
||||
import time
|
||||
|
||||
root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir))
|
||||
|
||||
def main():
|
||||
token = secrets.token_hex(32)
|
||||
if not os.environ.get("GOLDWARDEN_DAEMON_AUTH_TOKEN") == None:
|
||||
token = os.environ["GOLDWARDEN_DAEMON_AUTH_TOKEN"]
|
||||
print("Starting Goldwarden GUI")
|
||||
goldwarden.run_daemon_background(token)
|
||||
time.sleep(1)
|
||||
#pinentry.daemonize()
|
||||
if not "--hidden" in sys.argv:
|
||||
p = subprocess.Popen(["python3", "-m", "src.gui.settings"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=root_path, start_new_session=True)
|
||||
p.stdin.write(f"{token}\n".encode())
|
||||
p.stdin.flush()
|
||||
# print stdout
|
||||
while True:
|
||||
line = p.stderr.readline()
|
||||
if not line:
|
||||
break
|
||||
print(line.decode().strip())
|
||||
while True:
|
||||
time.sleep(60)
|
@ -1,5 +1,5 @@
|
||||
from ..goldwarden import autotype
|
||||
|
||||
def libportal_autotype(text):
|
||||
def autotype_libportal(text):
|
||||
print("autotypeing with libportal")
|
||||
goldwarden.autotype(text)
|
@ -2,4 +2,7 @@ import pyautogui
|
||||
|
||||
def autotype_pyautogui(text):
|
||||
print("autotypeing with pyautogui")
|
||||
pyautogui.write(text, interval=0.02)
|
||||
pyautogui.write(text, interval=0.02)
|
||||
|
||||
if __name__ == "__main__":
|
||||
autotype_pyautogui("hello world")
|
Loading…
Reference in New Issue
Block a user