Automated update
This commit is contained in:
120
qutebrowser/qute_pass_manager.py
Normal file
120
qutebrowser/qute_pass_manager.py
Normal file
@@ -0,0 +1,120 @@
|
||||
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 <current_url>")
|
||||
sys.exit(1)
|
||||
|
||||
url = sys.argv[1]
|
||||
autofill_password(url)
|
||||
|
||||
Reference in New Issue
Block a user