From aea57958326360a1dc15509c02397594da20538e Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sat, 23 Aug 2025 20:43:04 +1000 Subject: lock: add fprint support (#429) * lock: add fprint support * lock: better fprint detection * lock: cap error retries * nix: fix fprint pam for nix * lock: reset fprint tries * lock: minor pam fixes Delay fprint error retries Reset fprint error retries on lock * lock: loading indicator passwd state Instead of fprint state cause no way of detecting that * dashboard: better visualiser * lock: better fprint availability check * lock: better in/out anim Animating layout sizes is a bad idea :woe: Use scale instead * lock: add better error/fail messages * lock: less fprint icon states Already shown by message * lock: fix fprint reset * lock: include passwd pam * lock: flash message on change * lock: fix message anim Also wrap message instead of eliding * lock: better messages for no fprint --- modules/lock/Pam.qml | 127 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 4 deletions(-) (limited to 'modules/lock/Pam.qml') diff --git a/modules/lock/Pam.qml b/modules/lock/Pam.qml index 2675405..0186c2f 100644 --- a/modules/lock/Pam.qml +++ b/modules/lock/Pam.qml @@ -1,4 +1,6 @@ +import qs.config import Quickshell +import Quickshell.Io import Quickshell.Wayland import Quickshell.Services.Pam import QtQuick @@ -9,12 +11,16 @@ Scope { required property WlSessionLock lock readonly property alias passwd: passwd - readonly property bool active: passwd.active + readonly property alias fprint: fprint + property string lockMessage property string state + property string fprintState property string buffer + signal flashMsg + function handleKey(event: KeyEvent): void { - if (passwd.active) + if (passwd.active || state === "max") return; if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { @@ -34,6 +40,16 @@ Scope { PamContext { id: passwd + config: "passwd" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onMessageChanged: { + if (message.startsWith("The account is locked")) + root.lockMessage = message; + else if (root.lockMessage && message.endsWith(" left to unlock)")) + root.lockMessage += "\n" + message; + } + onResponseRequiredChanged: { if (!responseRequired) return; @@ -53,22 +69,125 @@ Scope { else if (res === PamResult.Failed) root.state = "fail"; + root.flashMsg(); stateReset.restart(); } } + PamContext { + id: fprint + + property bool available + property int tries + property int errorTries + + function checkAvail(): void { + if (!available || !Config.lock.enableFprint || !root.lock.secure) { + abort(); + return; + } + + tries = 0; + errorTries = 0; + start(); + } + + config: "fprint" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onCompleted: res => { + if (!available) + return; + + if (res === PamResult.Success) + return root.lock.unlock(); + + if (res === PamResult.Error) { + root.fprintState = "error"; + errorTries++; + if (errorTries < 5) { + abort(); + errorRetry.restart(); + } + } else if (res === PamResult.MaxTries) { + // Isn't actually the real max tries as pam only reports completed + // when max tries is reached. + tries++; + if (tries < Config.lock.maxFprintTries) { + // Restart if not actually real max tries + root.fprintState = "fail"; + start(); + } else { + root.fprintState = "max"; + abort(); + } + } + + root.flashMsg(); + fprintStateReset.start(); + } + } + + Process { + id: availProc + + command: ["sh", "-c", "fprintd-list $USER"] + onExited: code => { + fprint.available = code === 0; + fprint.checkAvail(); + } + } + + Timer { + id: errorRetry + + interval: 800 + onTriggered: fprint.start() + } + Timer { id: stateReset interval: 4000 - onTriggered: root.state = "" + onTriggered: { + if (root.state !== "max") + root.state = ""; + } + } + + Timer { + id: fprintStateReset + + interval: 4000 + onTriggered: { + root.fprintState = ""; + fprint.errorTries = 0; + } } Connections { target: root.lock + function onSecureChanged(): void { + if (root.lock.secure) { + availProc.running = true; + root.buffer = ""; + root.state = ""; + root.fprintState = ""; + root.lockMessage = ""; + } + } + function onUnlock(): void { - root.buffer = ""; + fprint.abort(); + } + } + + Connections { + target: Config.lock + + function onEnableFprintChanged(): void { + fprint.checkAvail(); } } } -- cgit v1.2.3-freya