lock screen: ext-session-lock-v1 with PAM auth and logind integration
This commit is contained in:
parent
1f3cb60934
commit
4f59bc4ce4
10 changed files with 522 additions and 3 deletions
105
modules/lock/LockAuth.qml
Normal file
105
modules/lock/LockAuth.qml
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Pam
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
required property WlSessionLock lock
|
||||
|
||||
// Auth state: "", "busy", "fail", "error", "max"
|
||||
property string state: ""
|
||||
property string message: ""
|
||||
property string buffer: ""
|
||||
|
||||
signal authFailed
|
||||
|
||||
function handleKey(event) {
|
||||
if (_passwd.active || state === "max")
|
||||
return;
|
||||
|
||||
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||
if (buffer.length > 0)
|
||||
_passwd.start();
|
||||
} else if (event.key === Qt.Key_Backspace) {
|
||||
if (event.modifiers & Qt.ControlModifier)
|
||||
buffer = "";
|
||||
else
|
||||
buffer = buffer.slice(0, -1);
|
||||
} else if (event.key === Qt.Key_Escape) {
|
||||
buffer = "";
|
||||
} else if (event.text && event.text.length === 1) {
|
||||
const c = event.text;
|
||||
// Accept printable ASCII
|
||||
if (c.charCodeAt(0) >= 32 && c.charCodeAt(0) < 127)
|
||||
buffer += c;
|
||||
}
|
||||
}
|
||||
|
||||
property PamContext _passwd: PamContext {
|
||||
config: "nova-shell"
|
||||
configDirectory: Quickshell.shellDir + "/assets/pam.d"
|
||||
|
||||
onActiveChanged: {
|
||||
if (active)
|
||||
root.state = "busy";
|
||||
}
|
||||
|
||||
onResponseRequiredChanged: {
|
||||
if (!responseRequired)
|
||||
return;
|
||||
respond(root.buffer);
|
||||
root.buffer = "";
|
||||
}
|
||||
|
||||
onCompleted: res => {
|
||||
if (res === PamResult.Success) {
|
||||
root.state = "";
|
||||
root.message = "";
|
||||
root.lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (res === PamResult.Error) {
|
||||
root.state = "error";
|
||||
root.message = "Authentication error";
|
||||
} else if (res === PamResult.MaxTries) {
|
||||
root.state = "max";
|
||||
root.message = "Too many attempts";
|
||||
} else if (res === PamResult.Failed) {
|
||||
root.state = "fail";
|
||||
root.message = "Wrong password";
|
||||
}
|
||||
|
||||
root.authFailed();
|
||||
_stateReset.restart();
|
||||
}
|
||||
|
||||
onMessageChanged: {
|
||||
if (message.startsWith("The account is locked"))
|
||||
root.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
property Timer _stateReset: Timer {
|
||||
interval: 3000
|
||||
onTriggered: {
|
||||
if (root.state !== "max")
|
||||
root.state = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Reset state when lock becomes secure (freshly locked)
|
||||
property Connections _lockConn: Connections {
|
||||
target: root.lock
|
||||
|
||||
function onSecureChanged() {
|
||||
if (root.lock.secure) {
|
||||
root.buffer = "";
|
||||
root.state = "";
|
||||
root.message = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue