import subprocess import os import json import pyperclip from qutebrowser.api import interceptor import urwid import sys PASS_STORE = os.path.expanduser("~/.password-store") IGNORE_DOMAINS = ["localhost", "127.0.0.1"] def get_pass_entries(): """Returns a list of all password entries in the store.""" result = subprocess.run(["pass", "ls"], capture_output=True, text=True) if result.returncode != 0: return [] return [line.strip().replace(" ", "") for line in result.stdout.split("\n") if line] def find_matching_entry(url): """Finds the closest matching pass entry for a given URL.""" domain = url.split("/")[2] if "://" in url else url if domain in IGNORE_DOMAINS: return None entries = get_pass_entries() for entry in entries: if domain in entry.lower(): return entry return None def get_password(entry): """Retrieves the password from pass.""" result = subprocess.run(["pass", entry], capture_output=True, text=True) if result.returncode != 0: return None lines = result.stdout.strip().split("\n") username = None password = lines[0] # First line is password if len(lines) > 1: for line in lines[1:]: if line.startswith("username:"): username = line.split(":", 1)[1].strip() return username, password def show_tui(entries): """Shows a TUI menu for manual password selection.""" def on_select(button, choice): global selected_entry selected_entry = choice raise urwid.ExitMainLoop() body = [urwid.Text("Select a password entry:"), urwid.Divider()] for entry in entries: button = urwid.Button(entry) urwid.connect_signal(button, 'click', on_select, entry) body.append(urwid.AttrMap(button, None, focus_map='reversed')) main_widget = urwid.ListBox(urwid.SimpleFocusListWalker(body)) urwid.MainLoop(main_widget).run() return selected_entry def autofill_password(url): """Handles autofilling the password in qutebrowser.""" entry = find_matching_entry(url) if not entry: entries = get_pass_entries() entry = show_tui(entries) if entry: username, password = get_password(entry) if not password: print("Error: No password found.") return js_script = """ (function() { let inputs = document.querySelectorAll('input[type="password"]'); if (inputs.length === 0) { alert('No password field found!'); return; } let passwordField = inputs[0]; let form = passwordField.closest('form'); let userField = form.querySelector('input[type="text"], input[type="email"]'); if (!userField) { alert('No username field found!'); return; } userField.value = "%s"; passwordField.value = "%s"; })(); """ % (username or "", password) with open("/tmp/qute_autofill.js", "w") as f: f.write(js_script) subprocess.run(["qutebrowser", ":jseval file:///tmp/qute_autofill.js"]) else: print("No entry selected.") if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python qute_pass_manager.py ") sys.exit(1) url = sys.argv[1] autofill_password(url)