Compare commits

...

17 Commits

Author SHA1 Message Date
Bernd Schoolmann
9d5514a976
Update com.quexten.Goldwarden.metainfo.xml 2024-02-17 14:53:14 +01:00
Bernd Schoolmann
715d04c5ab
Update release.yml 2024-02-17 14:29:03 +01:00
Bernd Schoolmann
93dc64ae36
Update PKGBUILD to 0.2.12 2024-02-17 14:24:58 +01:00
Bernd Schoolmann
8b95af6458
Fix broken arch ci due to maintainer account renaming 2024-02-17 14:17:27 +01:00
Bernd Schoolmann
969ee1ff49
Update com.quexten.Goldwarden.metainfo.xml 2024-02-17 14:03:09 +01:00
Bernd Schoolmann
f99d618b33
Fix flatpak build 2024-02-17 13:44:00 +01:00
Bernd Schoolmann
f894af5fb3
Update PKGBUILD 2024-02-17 13:39:47 +01:00
Bernd Schoolmann
29bd40384b
Fix autotype and remove debug logging 2024-02-17 13:38:54 +01:00
Bernd Schoolmann
6ee67d6569
Use gtk clipboard instead of wl clipboard 2024-02-17 13:32:58 +01:00
Bernd Schoolmann
13bd29dbf9
Add browser biometrics setup window 2024-02-17 12:48:26 +01:00
Bernd Schoolmann
623fdcb719
Add flatpak biometric setup 2024-02-17 12:28:04 +01:00
Bernd Schoolmann
3b2d1fcf11
Improve biometric socket path detection 2024-02-17 12:11:30 +01:00
Bernd Schoolmann
5cc502580f
Increase read buffer to 4 MiB 2024-02-17 11:30:16 +01:00
Bernd Schoolmann
f7da373fa0
Fix crash in ui 2024-02-17 11:22:49 +01:00
Bernd Schoolmann
c15447aab3
Add ssh key and keyboard shortcut windows 2024-02-17 11:00:33 +01:00
Bernd Schoolmann
9ac1d8100a
Grant other sessions while pin session is active 2024-02-17 09:52:19 +01:00
Bernd Schoolmann
606dd176ef
Improve quickaccess keyboard navigation 2024-02-17 09:51:41 +01:00
17 changed files with 399 additions and 222 deletions

View File

@ -39,12 +39,6 @@ jobs:
with:
files: './goldwarden_linux_x86_64'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Validate ArchLinux PKGBUILD
uses: hapakaien/archlinux-package-action@v2
with:
flags: ''
namcap: true
updpkgsums: true
- name: Publish AUR package
uses: KSXGitHub/github-actions-deploy-aur@v2.7.0
with:

View File

@ -1,5 +1,5 @@
pkgname=goldwarden
pkgver=0.2.10
pkgver=0.2.12
pkgrel=1
pkgdesc='A feature-packed Bitwarden compatible desktop integration'
arch=('x86_64' 'aarch64')

View File

@ -86,19 +86,21 @@ func GetPermission(sessionType SessionType, ctx sockets.CallingContext, config *
if sessionStore.verifySession(ctx, sessionType) {
log.Info("Permission granted from cached session")
} else {
if biometrics.BiometricsWorking() {
biometricsApproval := biometrics.CheckBiometrics(biometricsApprovalType)
if !biometricsApproval {
return false, nil
}
} else {
log.Warn("Biometrics is not available, asking for pin")
pin, err := pinentry.GetPassword("Enter PIN", "Biometrics is not available. Enter your pin to authorize this action. "+message)
if err != nil {
return false, err
}
if !config.VerifyPin(pin) {
return false, nil
if !sessionStore.verifySession(ctx, Pin) {
if biometrics.BiometricsWorking() {
biometricsApproval := biometrics.CheckBiometrics(biometricsApprovalType)
if !biometricsApproval {
return false, nil
}
} else {
log.Warn("Biometrics is not available, asking for pin")
pin, err := pinentry.GetPassword("Enter PIN", "Biometrics is not available. Enter your pin to authorize this action. "+message)
if err != nil {
return false, err
}
if !config.VerifyPin(pin) {
return false, nil
}
}
}

View File

@ -108,19 +108,40 @@ func detectAndInstallBrowsers(startPath string) error {
return nil
}
binPath, err := os.Executable()
if err != nil {
return err
}
if info.IsDir() && info.Name() == "native-messaging-hosts" {
fmt.Printf("Found mozilla-like browser: %s\n", path)
manifest := strings.Replace(templateMozilla, "PATH", binPath, 1)
err = os.WriteFile(path+"/com.8bit.bitwarden.json", []byte(manifest), 0644)
os.Chown(path+"/com.8bit.bitwarden.json", 7, 7)
os.Remove(path + "/com.8bit.bitwarden.json")
os.Chown(path+"/goldwarden-proxy.sh", 7, 7)
os.Remove(path + "/goldwarden-proxy.sh")
manifest := strings.Replace(templateMozilla, "PATH", path+"/goldwarden-proxy.sh", 1)
err = os.WriteFile(path+"/com.8bit.bitwarden.json", []byte(manifest), 0444)
if err != nil {
return err
}
err = os.WriteFile(path+"/goldwarden-proxy.sh", []byte(proxyScript), 0755)
if err != nil {
return err
}
} else if info.IsDir() && info.Name() == "NativeMessagingHosts" {
fmt.Printf("Found chrome-like browser: %s\n", path)
manifest := strings.Replace(templateChrome, "PATH", binPath, 1)
err = os.WriteFile(path+"/com.8bit.bitwarden.json", []byte(manifest), 0644)
os.Chown(path+"/com.8bit.bitwarden.json", 7, 7)
os.Remove(path + "/com.8bit.bitwarden.json")
os.Chown(path+"/goldwarden-proxy.sh", 7, 7)
os.Remove(path + "/goldwarden-proxy.sh")
manifest := strings.Replace(templateChrome, "PATH", path+"/goldwarden-proxy.sh", 1)
err = os.WriteFile(path+"/com.8bit.bitwarden.json", []byte(manifest), 0444)
if err != nil {
return err
}
err = os.WriteFile(path+"/goldwarden-proxy.sh", []byte(proxyScript), 0755)
if err != nil {
return err
}
}
return err

View File

@ -21,3 +21,14 @@ const templateChrome = `{
"chrome-extension://ccnckbpmaceehanjmeomladnmlffdjgn/"
]
}`
const proxyScript = `#!/bin/bash
# Check if the "com.quexten.Goldwarden" Flatpak is installed
if flatpak list | grep -q "com.quexten.Goldwarden"; then
flatpak run --command=goldwarden com.quexten.Goldwarden "$@"
else
# If not installed, attempt to run the local version
goldwarden "$@"
fi
`

View File

@ -9,7 +9,7 @@ import (
"github.com/quexten/goldwarden/ipc/messages"
)
const READ_BUFFER = 1 * 1024 * 1024 // 1MB
const READ_BUFFER = 4 * 1024 * 1024 // 16MB
type UnixSocketClient struct {
runtimeConfig *config.RuntimeConfig

View File

@ -3,6 +3,8 @@
package cmd
import (
"bufio"
"encoding/hex"
"os"
"github.com/quexten/goldwarden/autotype"
@ -15,14 +17,13 @@ var autofillCmd = &cobra.Command{
Short: "Autotype credentials",
Long: `Autotype credentials`,
Run: func(cmd *cobra.Command, args []string) {
username, _ := cmd.Flags().GetString("username")
// get pasword from env
password := os.Getenv("PASSWORD")
autotype.TypeString(username + "\t" + password)
reader := bufio.NewReader(os.Stdin)
textHex, _ := reader.ReadString('\n')
text, _ := hex.DecodeString(textHex)
autotype.TypeString(string(text))
},
}
func init() {
rootCmd.AddCommand(autofillCmd)
autofillCmd.PersistentFlags().String("username", "", "")
}

View File

@ -29,17 +29,10 @@ finish-args:
- --system-talk-name=org.freedesktop.PolicyKit1
modules:
- ./gui/python3-requirements.json
- name: wl-clipboard
buildsystem: meson
config-opts:
- -Dfishcompletiondir=no
sources:
- type: git
url: https://github.com/bugaevc/wl-clipboard.git
tag: v2.2.1
- name: goldwarden-python-ui
buildsystem: simple
build-commands:
- mkdir -p /app/bin
- cp -R ./gui/* /app/bin
- chmod +x /app/bin/goldwarden_ui_main.py
- install -D ./gui/com.quexten.Goldwarden.desktop /app/share/applications/com.quexten.Goldwarden.desktop

View File

@ -36,6 +36,7 @@
<developer_name>Bernd Schoolmann</developer_name>
<update_contact>mail@quexten.com</update_contact>
<releases>
<release version="0.2.12" date="2024-02-17"/>
<release version="0.2.9" date="2024-01-04"/>
<release version="0.2.7" date="2023-12-30"/>
<release version="0.2.6" date="2023-12-30"/>

View File

@ -0,0 +1,53 @@
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import gc
import time
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
from threading import Thread
import sys
import os
from . import components
class MyApp(Adw.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.pinentry_window = MainWindow(application=app)
self.pinentry_window.present()
self.app = app
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# vertical box
self.box = Gtk.Box()
self.box.set_orientation(Gtk.Orientation.VERTICAL)
self.set_child(self.box)
self.stack = Gtk.Stack()
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
self.box.append(self.stack)
self.preferences_page = Adw.PreferencesPage()
self.preferences_page.set_title("General")
self.stack.add_named(self.preferences_page, "preferences_page")
self.register_browser_biometrics_group = Adw.PreferencesGroup()
self.register_browser_biometrics_group.set_title("Register Browser Biometrics")
self.register_browser_biometrics_group.set_description("Run the following command in your terminal to set up the browser biometrics integration")
self.preferences_page.add(self.register_browser_biometrics_group)
self.setup_command_row = Adw.ActionRow()
self.setup_command_row.set_subtitle("flatpak run --filesystem=home --command=goldwarden com.quexten.Goldwarden setup browserbiometrics")
self.setup_command_row.set_subtitle_selectable(True)
self.register_browser_biometrics_group.add(self.setup_command_row)
self.set_default_size(700, 400)
self.set_title("Goldwarden Browser Biometrics Setup")
app = MyApp(application_id="com.quexten.Goldwarden.browserbiometrics")
app.run(sys.argv)

View File

@ -6,16 +6,32 @@ import gc
import time
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
from ..services import goldwarden
from ..linux import clipboard
from threading import Thread
import sys
import os
from ..services import totp
Notify.init("Goldwarden")
# read line from stdin
token = sys.stdin.readline()
goldwarden.create_authenticated_connection(token)
def autotype(text):
goldwarden.autotype(text)
time.sleep(0.1)
os._exit(0)
def set_clipboard(text):
Gdk.Display.get_clipboard(Gdk.Display.get_default()).set_content(
Gdk.ContentProvider.new_for_value(text)
)
def kill():
time.sleep(0.5)
os._exit(0)
thread = Thread(target=kill)
thread.start()
class MyApp(Adw.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
@ -50,7 +66,7 @@ class MainWindow(Gtk.ApplicationWindow):
self.text_view = Adw.EntryRow()
self.text_view.set_title("Search")
# on type func
def on_type(entry):
if len(entry.get_text()) > 1:
self.results_list.show()
@ -94,12 +110,10 @@ class MainWindow(Gtk.ApplicationWindow):
keycont = Gtk.EventControllerKey()
def handle_keypress(cotroller, keyval, keycode, state, user_data):
# if ctrl is pressed
if state == 4:
print("ctrl")
ctrl_pressed = state & Gdk.ModifierType.CONTROL_MASK > 0
alt_pressed = state & Gdk.ModifierType.ALT_MASK > 0
if keycode == 9:
print("esc")
os._exit(0)
if keyval == 65364:
@ -112,43 +126,42 @@ class MainWindow(Gtk.ApplicationWindow):
return False
if keycode == 36:
print("enter")
self.hide()
def do_autotype(username, password):
time.sleep(0.5)
goldwarden.autotype(username, password)
os._exit(0)
autotypeThread = Thread(target=do_autotype, args=(self.results_list.get_selected_row().username, self.results_list.get_selected_row().password,))
autotypeThread = Thread(target=autotype, args=(f"{self.results_list.get_selected_row().username}\t{self.results_list.get_selected_row().password}",))
autotypeThread.start()
print(self.results_list.get_selected_row().get_title())
if keyval == 112:
print("copy password")
clipboard.write(self.results_list.get_selected_row().password)
Notify.Notification.new("Goldwarden", "Password Copied", "dialog-information").show()
print("pass", ctrl_pressed, alt_pressed)
if ctrl_pressed and not alt_pressed:
set_clipboard(self.results_list.get_selected_row().password)
if ctrl_pressed and alt_pressed:
self.hide()
autotypeThread = Thread(target=autotype, args=(self.results_list.get_selected_row().password,))
autotypeThread.start()
elif keyval == 117:
print("copy username")
clipboard.write(self.results_list.get_selected_row().username)
notification=Notify.Notification.new("Goldwarden", "Username Copied", "dialog-information")
notification.set_timeout(5)
notification.show()
if ctrl_pressed and not alt_pressed:
set_clipboard(self.results_list.get_selected_row().username)
if ctrl_pressed and alt_pressed:
self.hide()
autotypeThread = Thread(target=autotype, args=(self.results_list.get_selected_row().username,))
autotypeThread.start()
elif keyval == 118:
print("open web vault")
environment = goldwarden.get_environment()
if environment == None:
return
item_uri = environment["vault"] + "#/vault?itemId=" + self.results_list.get_selected_row().uuid
Gtk.show_uri(None, item_uri, Gdk.CURRENT_TIME)
if ctrl_pressed and alt_pressed:
environment = goldwarden.get_environment()
if environment == None:
return
item_uri = environment["vault"] + "#/vault?itemId=" + self.results_list.get_selected_row().uuid
Gtk.show_uri(None, item_uri, Gdk.CURRENT_TIME)
elif keyval == 108:
print("launch")
print(self.results_list.get_selected_row().uri)
Gtk.show_uri(None, self.results_list.get_selected_row().uri, Gdk.CURRENT_TIME)
if ctrl_pressed and alt_pressed:
Gtk.show_uri(None, self.results_list.get_selected_row().uri, Gdk.CURRENT_TIME)
elif keyval == 116:
print("copy totp")
totp_code = totp.totp(self.results_list.get_selected_row().totp)
clipboard.write(totp_code)
notification=Notify.Notification.new("Goldwarden", "Totp Copied", "dialog-information")
notification.set_timeout(5)
notification.show()
totp_code = totp.totp(self.resuts_list.get_selected_row().totp)
if ctrl_pressed and not alt_pressed:
set_clipboard(totp_code)
if ctrl_pressed and alt_pressed:
self.hide()
autotypeThread = Thread(target=autotype, args=(totp_code,))
autotypeThread.start()
elif keyval == 102:
# focus search
self.text_view.grab_focus()

View File

@ -5,7 +5,7 @@ gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import gc
from gi.repository import Gtk, Adw, GLib, Gdk
from gi.repository import Gtk, Adw, GLib, Gdk, Gio
from ..services import goldwarden
from threading import Thread
import subprocess
@ -16,6 +16,35 @@ root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file_
token = sys.stdin.readline()
goldwarden.create_authenticated_connection(None)
def quickaccess_button_clicked():
p = subprocess.Popen(["python3", "-m", "src.gui.quickaccess"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True)
p.stdin.write(f"{token}\n".encode())
p.stdin.flush()
def shortcuts_button_clicked():
p = subprocess.Popen(["python3", "-m", "src.gui.shortcuts"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True)
p.stdin.write(f"{token}\n".encode())
p.stdin.flush()
def ssh_button_clicked():
p = subprocess.Popen(["python3", "-m", "src.gui.ssh"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True)
p.stdin.write(f"{token}\n".encode())
p.stdin.flush()
def browserbiometrics_button_clicked():
p = subprocess.Popen(["python3", "-m", "src.gui.browserbiometrics"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True)
p.stdin.write(f"{token}\n".encode())
p.stdin.flush()
def add_action_row(parent, title, subtitle, icon=None):
row = Adw.ActionRow()
row.set_title(title)
row.set_subtitle(subtitle)
if icon != None:
row.set_icon_name(icon)
parent.add(row)
return row
class SettingsWinvdow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -50,10 +79,7 @@ class SettingsWinvdow(Gtk.ApplicationWindow):
self.autotype_button = Gtk.Button()
self.autotype_button.set_label("Quick Access")
self.autotype_button.set_margin_top(10)
def quickaccess_button_clicked():
p = subprocess.Popen(["python3", "-m", "src.gui.quickaccess"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=root_path, start_new_session=True)
p.stdin.write(f"{token}\n".encode())
p.stdin.flush()
self.autotype_button.connect("clicked", lambda button: quickaccess_button_clicked())
self.autotype_button.get_style_context().add_class("suggested-action")
self.action_preferences_group.add(self.autotype_button)
@ -98,128 +124,58 @@ class SettingsWinvdow(Gtk.ApplicationWindow):
self.wiki_button.set_margin_top(10)
self.action_preferences_group.add(self.wiki_button)
self.shortcut_preferences_group = Adw.PreferencesGroup()
self.shortcut_preferences_group.set_title("Shortcuts")
self.preferences_page.add(self.shortcut_preferences_group)
self.autofill_row = Adw.ActionRow()
self.autofill_row.set_title("Autofill Shortcut")
self.autofill_row.set_subtitle("Unavailable, please set up a shortcut in your desktop environment (README)")
self.shortcut_preferences_group.add(self.autofill_row)
self.autofill_icon = components.StatusIcon()
self.autofill_icon.set_icon("dialog-warning", "warning")
self.autofill_row.add_prefix(self.autofill_icon)
self.copy_username_shortcut_row = Adw.ActionRow()
self.copy_username_shortcut_row.set_title("Copy Username Shortcut")
self.copy_username_shortcut_row.set_subtitle("U")
self.shortcut_preferences_group.add(self.copy_username_shortcut_row)
self.copy_password_shortcut_row = Adw.ActionRow()
self.copy_password_shortcut_row.set_title("Copy Password Shortcut")
self.copy_password_shortcut_row.set_subtitle("P")
self.shortcut_preferences_group.add(self.copy_password_shortcut_row)
self.copy_totp_shortcut_row = Adw.ActionRow()
self.copy_totp_shortcut_row.set_title("Copy TOTP Shortcut")
self.copy_totp_shortcut_row.set_subtitle("T")
self.shortcut_preferences_group.add(self.copy_totp_shortcut_row)
self.launch_uri_shortcut_row = Adw.ActionRow()
self.launch_uri_shortcut_row.set_title("Launch URI Shortcut")
self.launch_uri_shortcut_row.set_subtitle("L")
self.shortcut_preferences_group.add(self.launch_uri_shortcut_row)
self.launch_web_vault_shortcut_row = Adw.ActionRow()
self.launch_web_vault_shortcut_row.set_title("Launch Web Vault Shortcut")
self.launch_web_vault_shortcut_row.set_subtitle("V")
self.shortcut_preferences_group.add(self.launch_web_vault_shortcut_row)
self.focus_search_shortcut_row = Adw.ActionRow()
self.focus_search_shortcut_row.set_title("Focus Search Shortcut")
self.focus_search_shortcut_row.set_subtitle("F")
self.shortcut_preferences_group.add(self.focus_search_shortcut_row)
self.quit_shortcut_row = Adw.ActionRow()
self.quit_shortcut_row.set_title("Quit Shortcut")
self.quit_shortcut_row.set_subtitle("Esc")
self.shortcut_preferences_group.add(self.quit_shortcut_row)
self.vault_status_preferences_group = Adw.PreferencesGroup()
self.vault_status_preferences_group.set_title("Vault Status")
self.preferences_page.add(self.vault_status_preferences_group)
self.status_row = Adw.ActionRow()
self.status_row.set_title("Vault Status")
self.status_row.set_subtitle("Locked")
self.vault_status_preferences_group.add(self.status_row)
self.status_row = add_action_row(self.vault_status_preferences_group, "Vault Status", "Locked")
self.vault_status_icon = components.StatusIcon()
self.vault_status_icon.set_icon("dialog-error", "error")
self.status_row.add_prefix(self.vault_status_icon)
self.last_sync_row = Adw.ActionRow()
self.last_sync_row.set_title("Last Sync")
self.last_sync_row.set_subtitle("Never")
self.last_sync_row.set_icon_name("emblem-synchronizing-symbolic")
self.vault_status_preferences_group.add(self.last_sync_row)
self.websocket_connected_row = Adw.ActionRow()
self.websocket_connected_row.set_title("Websocket Connected")
self.websocket_connected_row.set_subtitle("False")
self.vault_status_preferences_group.add(self.websocket_connected_row)
self.last_sync_row = add_action_row(self.vault_status_preferences_group, "Last Sync", "Never", "emblem-synchronizing-symbolic")
self.websocket_connected_row = add_action_row(self.vault_status_preferences_group, "Websocket Connected", "False")
self.websocket_connected_status_icon = components.StatusIcon()
self.websocket_connected_status_icon.set_icon("dialog-error", "error")
self.websocket_connected_row.add_prefix(self.websocket_connected_status_icon)
self.login_row = add_action_row(self.vault_status_preferences_group, "Vault Login Entries", "0", "dialog-password-symbolic")
self.notes_row = add_action_row(self.vault_status_preferences_group, "Vault Notes", "0", "emblem-documents-symbolic")
self.header = Gtk.HeaderBar()
self.set_titlebar(self.header)
action = Gio.SimpleAction.new("shortcuts", None)
action.connect("activate", lambda action, parameter: shortcuts_button_clicked())
self.add_action(action)
menu = Gio.Menu.new()
menu.append("Keyboard Shortcuts", "win.shortcuts")
self.popover = Gtk.PopoverMenu()
self.popover.set_menu_model(menu)
action = Gio.SimpleAction.new("ssh", None)
action.connect("activate", lambda action, parameter: ssh_button_clicked())
self.add_action(action)
menu.append("SSH Agent", "win.ssh")
action = Gio.SimpleAction.new("browserbiometrics", None)
action.connect("activate", lambda action, parameter: browserbiometrics_button_clicked())
self.add_action(action)
menu.append("Browser Biometrics", "win.browserbiometrics")
self.login_row = Adw.ActionRow()
self.login_row.set_title("Vault Login Entries")
self.login_row.set_subtitle("0")
self.login_row.set_icon_name("dialog-password-symbolic")
self.vault_status_preferences_group.add(self.login_row)
self.hamburger = Gtk.MenuButton()
self.hamburger.set_popover(self.popover)
self.hamburger.set_icon_name("open-menu-symbolic")
self.header.pack_start(self.hamburger)
self.notes_row = Adw.ActionRow()
self.notes_row.set_title("Vault Notes")
self.notes_row.set_subtitle("0")
self.notes_row.set_icon_name("emblem-documents-symbolic")
self.vault_status_preferences_group.add(self.notes_row)
self.preferences_group = Adw.PreferencesGroup()
self.preferences_group.set_title("Services")
self.preferences_page.add(self.preferences_group)
self.ssh_row = Adw.ActionRow()
self.ssh_row.set_title("SSH Daemon")
self.ssh_row.set_subtitle("Getting status...")
self.ssh_row.set_icon_name("emblem-default")
self.preferences_group.add(self.ssh_row)
self.goldwarden_daemon_row = Adw.ActionRow()
self.goldwarden_daemon_row.set_title("Goldwarden Daemon")
self.goldwarden_daemon_row.set_subtitle("Getting status...")
self.goldwarden_daemon_row.set_icon_name("emblem-default")
self.preferences_group.add(self.goldwarden_daemon_row)
self.login_with_device = Adw.ActionRow()
self.login_with_device.set_title("Login with device")
self.login_with_device.set_subtitle("Waiting for requests...")
self.preferences_group.add(self.login_with_device)
self.status_row = Adw.ActionRow()
self.status_row.set_title("DBUS Service")
self.status_row.set_subtitle("Listening")
self.preferences_group.add(self.status_row)
def update_labels():
pin_set = goldwarden.is_pin_enabled()
status = goldwarden.get_vault_status()
print("status", status)
runtimeCfg = goldwarden.get_runtime_config()
if runtimeCfg != None:
self.ssh_row.set_subtitle("Listening at "+runtimeCfg["SSHAgentSocketPath"])
self.goldwarden_daemon_row.set_subtitle("Listening at "+runtimeCfg["goldwardenSocketPath"])
if status != None:
if pin_set:
@ -230,15 +186,11 @@ class SettingsWinvdow(Gtk.ApplicationWindow):
self.banner.set_revealed(True)
logged_in = status["loggedIn"]
if logged_in and not status["locked"]:
self.preferences_group.set_visible(True)
self.shortcut_preferences_group.set_visible(True)
self.autotype_button.set_visible(True)
self.login_row.set_sensitive(True)
self.notes_row.set_sensitive(True)
self.websocket_connected_row.set_sensitive(True)
else:
self.preferences_group.set_visible(False)
self.shortcut_preferences_group.set_visible(False)
self.autotype_button.set_visible(False)
self.websocket_connected_row.set_sensitive(False)
self.login_row.set_sensitive(False)
@ -276,16 +228,10 @@ class SettingsWinvdow(Gtk.ApplicationWindow):
GLib.timeout_add(5000, update_labels)
GLib.timeout_add(1000, update_labels)
self.set_default_size(400, 700)
self.set_title("Goldwarden")
#add title buttons
self.title_bar = Gtk.HeaderBar()
self.set_titlebar(self.title_bar)
class MyApp(Adw.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
@ -372,6 +318,5 @@ Gtk.StyleContext.add_provider_for_display(
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
app = MyApp(application_id="com.quexten.Goldwarden.settings")
app.run(sys.argv)

80
gui/src/gui/shortcuts.py Normal file
View File

@ -0,0 +1,80 @@
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import gc
import time
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
from threading import Thread
import sys
import os
from . import components
def add_action_row(parent, title, subtitle, icon=None):
row = Adw.ActionRow()
row.set_title(title)
row.set_subtitle(subtitle)
if icon != None:
row.set_icon_name(icon)
parent.add(row)
return row
class MyApp(Adw.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.pinentry_window = MainWindow(application=app)
self.pinentry_window.present()
self.app = app
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# vertical box
self.box = Gtk.Box()
self.box.set_orientation(Gtk.Orientation.VERTICAL)
self.set_child(self.box)
self.stack = Gtk.Stack()
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
self.box.append(self.stack)
self.preferences_page = Adw.PreferencesPage()
self.preferences_page.set_title("General")
self.stack.add_named(self.preferences_page, "preferences_page")
self.global_preferences_group = Adw.PreferencesGroup()
self.global_preferences_group.set_title("Global Shortcuts")
self.preferences_page.add(self.global_preferences_group)
self.autofill_row = Adw.ActionRow()
self.autofill_row.set_title("Autofill Shortcut")
self.autofill_row.set_subtitle("Not implemented - check the wiki for manual setup")
self.global_preferences_group.add(self.autofill_row)
self.autofill_icon = components.StatusIcon()
self.autofill_icon.set_icon("dialog-warning", "warning")
self.autofill_row.add_prefix(self.autofill_icon)
self.quickaccess_preferences_group = Adw.PreferencesGroup()
self.quickaccess_preferences_group.set_title("Quick Access Shortcuts")
self.preferences_page.add(self.quickaccess_preferences_group)
add_action_row(self.quickaccess_preferences_group, "Copy Username Shortcut", "CTRL + U")
add_action_row(self.quickaccess_preferences_group, "Autotype Username Shortcut", "CTRL + ALT + U")
add_action_row(self.quickaccess_preferences_group, "Copy Password Shortcut", "CTRL + P")
add_action_row(self.quickaccess_preferences_group, "Autotype Password Shortcut", "CTRL + ALT + P")
add_action_row(self.quickaccess_preferences_group, "Copy TOTP Shortcut", "CTRL + T")
add_action_row(self.quickaccess_preferences_group, "Autotype TOTP Shortcut", "CTRL + ALT + T")
add_action_row(self.quickaccess_preferences_group, "Launch URI Shortcut", "CTRL+L")
add_action_row(self.quickaccess_preferences_group, "Launch Web Vault Shortcut", "CTRL+V")
add_action_row(self.quickaccess_preferences_group, "Focus Search Shortcut", "F")
add_action_row(self.quickaccess_preferences_group, "Quit Shortcut", "Esc")
self.set_default_size(700, 700)
self.set_title("Goldwarden Shortcuts")
app = MyApp(application_id="com.quexten.Goldwarden.shortcuts")
app.run(sys.argv)

67
gui/src/gui/ssh.py Normal file
View File

@ -0,0 +1,67 @@
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import gc
import time
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
from threading import Thread
import sys
import os
from . import components
class MyApp(Adw.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.pinentry_window = MainWindow(application=app)
self.pinentry_window.present()
self.app = app
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# vertical box
self.box = Gtk.Box()
self.box.set_orientation(Gtk.Orientation.VERTICAL)
self.set_child(self.box)
self.stack = Gtk.Stack()
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
self.box.append(self.stack)
self.preferences_page = Adw.PreferencesPage()
self.preferences_page.set_title("General")
self.stack.add_named(self.preferences_page, "preferences_page")
self.add_ssh_key_group = Adw.PreferencesGroup()
self.add_ssh_key_group.set_title("Add an SSH Key")
self.preferences_page.add(self.add_ssh_key_group)
self.add_ssh_key_row = Adw.ActionRow()
self.add_ssh_key_row.set_subtitle("flatpak run --command=goldwarden com.quexten.Goldwarden ssh add --name MY_KEY_NAME")
self.add_ssh_key_row.set_subtitle_selectable(True)
self.add_ssh_key_group.add(self.add_ssh_key_row)
self.ssh_socket_path_group = Adw.PreferencesGroup()
self.ssh_socket_path_group.set_title("SSH Socket Path")
self.ssh_socket_path_group.set_description("Add this to your your enviorment variables")
self.preferences_page.add(self.ssh_socket_path_group)
self.ssh_socket_path_row = Adw.ActionRow()
self.ssh_socket_path_row.set_subtitle("export SSH_AUTH_SOCK=/home/$USER/.var/app/com.quexten.Goldwarden/data/ssh-auth-sock")
self.ssh_socket_path_row.set_subtitle_selectable(True)
self.ssh_socket_path_group.add(self.ssh_socket_path_row)
self.git_signing_group = Adw.PreferencesGroup()
self.git_signing_group.set_title("Git Signing")
self.git_signing_group.set_description("Check the wiki for more information")
self.preferences_page.add(self.git_signing_group)
self.set_default_size(400, 700)
self.set_title("Goldwarden SSH Setup")
app = MyApp(application_id="com.quexten.Goldwarden.sshsetup")
app.run(sys.argv)

View File

@ -1,9 +0,0 @@
import subprocess
import os
def write(text):
# set path
env = os.environ.copy()
env["PATH"] = env["PATH"] + ":/app/bin"
process = subprocess.Popen(["/bin/sh", "-c", "wl-copy"], stdin=subprocess.PIPE, env=env)
process.communicate(text.encode('utf-8'))

View File

@ -131,16 +131,13 @@ def get_runtime_config():
except Exception as e:
return None
def autotype(username, password):
env = os.environ.copy()
# todo convert to stdin
env["PASSWORD"] = password
goldwarden_cmd = f"{BINARY_PATH} autotype --username {username}"
result = subprocess.run(goldwarden_cmd.split(), capture_output=True, text=True, env=env)
print(result.stderr)
print(result.stdout)
if result.returncode != 0:
raise Exception("Failed to initialize repository, err", result.stderr)
def autotype(text):
goldwarden_cmd = f"{BINARY_PATH} autotype"
process = subprocess.Popen(goldwarden_cmd.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
text_hex = text.encode("utf-8").hex()
process.stdin.write(text_hex + "\n")
process.stdin.flush()
process.wait()
def is_daemon_running():
result = send_authenticated_command(f"vault status")

22
main.go
View File

@ -41,15 +41,18 @@ func main() {
panic(err)
}
if runtimeConfig.SSHAgentSocketPath == "" {
runtimeConfig.SSHAgentSocketPath = home + "/.goldwarden-ssh-agent.sock"
if _, err := os.Stat(home + "/.ssh-agent-socket"); err == nil {
runtimeConfig.SSHAgentSocketPath = home + "/.ssh-agent-socket"
} else if _, err := os.Stat(home + "/.var/app/com.quexten.Goldwarden/data/ssh-auth-sock"); err == nil {
runtimeConfig.SSHAgentSocketPath = home + "/.var/app/com.quexten.Goldwarden/data/ssh-auth-sock"
}
}
if runtimeConfig.GoldwardenSocketPath == "" {
runtimeConfig.GoldwardenSocketPath = home + "/.goldwarden.sock"
}
if len(os.Args) > 1 && (strings.Contains(os.Args[1], "com.8bit.bitwarden.json") || strings.Contains(os.Args[1], "chrome-extension://")) {
browserbiometrics.Main(&runtimeConfig)
return
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"
}
}
_, err = os.Stat("/.flatpak-info")
@ -62,5 +65,10 @@ func main() {
runtimeConfig.GoldwardenSocketPath = userHome + "/.var/app/com.quexten.Goldwarden/data/goldwarden.sock"
}
if len(os.Args) > 1 && (strings.Contains(os.Args[1], "com.8bit.bitwarden.json") || strings.Contains(os.Args[1], "chrome-extension://")) {
browserbiometrics.Main(&runtimeConfig)
return
}
cmd.Execute(runtimeConfig)
}