mirror of
https://github.com/quexten/goldwarden.git
synced 2024-10-27 03:33:14 +03:00
Compare commits
17 Commits
592ff48148
...
9d5514a976
Author | SHA1 | Date | |
---|---|---|---|
|
9d5514a976 | ||
|
715d04c5ab | ||
|
93dc64ae36 | ||
|
8b95af6458 | ||
|
969ee1ff49 | ||
|
f99d618b33 | ||
|
f894af5fb3 | ||
|
29bd40384b | ||
|
6ee67d6569 | ||
|
13bd29dbf9 | ||
|
623fdcb719 | ||
|
3b2d1fcf11 | ||
|
5cc502580f | ||
|
f7da373fa0 | ||
|
c15447aab3 | ||
|
9ac1d8100a | ||
|
606dd176ef |
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@ -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:
|
||||
|
2
PKGBUILD
2
PKGBUILD
@ -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')
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
`
|
||||
|
@ -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
|
||||
|
@ -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", "", "")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"/>
|
||||
|
53
gui/src/gui/browserbiometrics.py
Normal file
53
gui/src/gui/browserbiometrics.py
Normal 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)
|
@ -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()
|
||||
|
@ -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
80
gui/src/gui/shortcuts.py
Normal 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
67
gui/src/gui/ssh.py
Normal 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)
|
@ -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'))
|
@ -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
22
main.go
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user