summaryrefslogtreecommitdiff
path: root/modules/lock/Pam.qml
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-08-23 20:43:04 +1000
committerGitHub <noreply@github.com>2025-08-23 20:43:04 +1000
commitaea57958326360a1dc15509c02397594da20538e (patch)
treed3a4626e7246f93ae420f500a8b189ee0342b074 /modules/lock/Pam.qml
parentbar: add idle inhibitor (#459) (diff)
downloadcaelestia-shell-aea57958326360a1dc15509c02397594da20538e.tar.gz
caelestia-shell-aea57958326360a1dc15509c02397594da20538e.tar.bz2
caelestia-shell-aea57958326360a1dc15509c02397594da20538e.zip
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
Diffstat (limited to 'modules/lock/Pam.qml')
-rw-r--r--modules/lock/Pam.qml127
1 files changed, 123 insertions, 4 deletions
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();
}
}
}