Files
nixos-config/modules/user/lucid/Vaultwarden.qml
T
2026-11-13 00:06:31 +03:00

130 lines
3.4 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
pragma Singleton
Singleton {
id: root
property var entries: []
property bool loading: false
property string error: ""
property string targetAddress: ""
property string pendingPassword: ""
property var passwordProcess: null
signal passwordReady(string password, string targetAddress)
function refresh() {
if (listReader.running)
return;
root.loading = true;
root.error = "";
listReader.command = ["rbw", "list", "--fields", "id,name,user,folder"];
listReader.running = true;
}
function getPassword(id, target) {
if (root.passwordProcess)
return;
root.targetAddress = target || "";
root.error = "";
root.passwordProcess = passwordProcessComponent.createObject(root, { entryId: id });
if (!root.passwordProcess) {
root.error = "Could not start rbw.";
return;
}
root.passwordProcess.running = true;
}
function typePassword(password, target) {
root.pendingPassword = password;
root.targetAddress = target || "";
typeDelay.restart();
}
Process {
id: listReader
command: []
stdout: StdioCollector {
id: listOutput
}
onExited: (code) => {
root.loading = false;
if (code !== 0) {
root.error = "Could not read the vault. Unlock it with rbw, then retry.";
root.entries = [];
return;
}
root.entries = listOutput.text.split(/\r?\n/).filter((line) => line !== "").map((line) => {
const fields = line.split("\t");
return {
id: fields[0] || "",
name: fields[1] || "Untitled",
user: fields[2] || "",
folder: fields[3] || ""
};
}).filter((entry) => entry.id !== "");
root.error = "";
}
}
Component {
id: passwordProcessComponent
Process {
id: passwordJob
property string entryId: ""
command: ["rbw", "get", entryId]
stdout: StdioCollector {
id: passwordOutput
}
onExited: (code) => {
if (root.passwordProcess === passwordJob)
root.passwordProcess = null;
if (code !== 0) {
root.error = "Could not read that password.";
} else {
root.passwordReady(passwordOutput.text.replace(/\r?\n$/, ""), root.targetAddress);
}
passwordJob.destroy();
}
}
}
Process {
id: typer
command: ["wtype", "-"]
stdinEnabled: true
onStarted: {
write(root.pendingPassword);
stdinEnabled = false;
root.pendingPassword = "";
root.targetAddress = "";
}
}
Timer {
id: typeDelay
interval: 260
onTriggered: {
if (root.targetAddress !== "")
Hyprland.dispatch("focuswindow address:" + root.targetAddress);
typer.running = false;
typer.stdinEnabled = true;
typer.running = true;
}
}
}