mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
171 lines
4.6 KiB
QML
171 lines
4.6 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import Quickshell.Services.Pam
|
|
import qs.Commons
|
|
import qs.Services.System
|
|
|
|
Scope {
|
|
id: root
|
|
signal unlocked
|
|
signal failed
|
|
|
|
property string currentText: ""
|
|
property bool waitingForPassword: false
|
|
property bool unlockInProgress: false
|
|
property bool showFailure: false
|
|
property bool showInfo: false
|
|
property string errorMessage: ""
|
|
property string infoMessage: ""
|
|
|
|
readonly property string pamConfigDirectory: "/etc/pam.d"
|
|
property string pamConfig: Quickshell.env("NOCTALIA_PAM_SERVICE") || "login"
|
|
property bool pamReady: false
|
|
|
|
Component.onCompleted: {
|
|
if (Quickshell.env("NOCTALIA_PAM_SERVICE")) {
|
|
Logger.i("LockContext", "NOCTALIA_PAM_SERVICE is set, using system PAM config: /etc/pam.d/" + pamConfig);
|
|
pamReady = true;
|
|
} else {
|
|
Logger.i("LockContext", "Probing for best PAM service...");
|
|
detectPamServiceProc.running = true;
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: detectPamServiceProc
|
|
command: ["sh", "-c", "
|
|
if [ -f /etc/pam.d/login ]; then echo 'login'; exit 0; fi;
|
|
if [ -f /etc/pam.d/system-auth ]; then echo 'system-auth'; exit 0; fi;
|
|
if [ -f /etc/pam.d/common-auth ]; then echo 'common-auth'; exit 0; fi;
|
|
echo 'login';
|
|
"]
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const service = String(text || "").trim();
|
|
if (service.length > 0) {
|
|
root.pamConfig = service;
|
|
Logger.i("LockContext", "Detected PAM service: " + service);
|
|
} else {
|
|
Logger.w("LockContext", "Failed to detect PAM service, defaulting to login");
|
|
}
|
|
root.pamReady = true;
|
|
}
|
|
}
|
|
stderr: StdioCollector {}
|
|
}
|
|
|
|
onPamReadyChanged: {
|
|
if (pamReady) {
|
|
if (Settings.data.general.autoStartAuth && currentText === "") {
|
|
pam.start();
|
|
}
|
|
}
|
|
}
|
|
|
|
onShowInfoChanged: {
|
|
if (showInfo) {
|
|
showFailure = false;
|
|
}
|
|
}
|
|
|
|
onShowFailureChanged: {
|
|
if (showFailure) {
|
|
showInfo = false;
|
|
}
|
|
}
|
|
|
|
onCurrentTextChanged: {
|
|
if (currentText !== "") {
|
|
showInfo = false;
|
|
showFailure = false;
|
|
if (!waitingForPassword) {
|
|
pam.abort();
|
|
}
|
|
if (Settings.data.general.allowPasswordWithFprintd) {
|
|
occupyFingerprintSensorProc.running = true;
|
|
}
|
|
} else {
|
|
occupyFingerprintSensorProc.running = false;
|
|
if (pamReady && Settings.data.general.autoStartAuth) {
|
|
pam.start();
|
|
}
|
|
}
|
|
}
|
|
|
|
function tryUnlock() {
|
|
if (!pamReady) {
|
|
Logger.w("LockContext", "PAM not ready yet, ignoring unlock attempt");
|
|
return;
|
|
}
|
|
|
|
if (waitingForPassword) {
|
|
pam.respond(currentText);
|
|
unlockInProgress = true;
|
|
waitingForPassword = false;
|
|
showInfo = false;
|
|
return;
|
|
}
|
|
|
|
Logger.i("LockContext", "Starting PAM authentication for user:", pam.user);
|
|
pam.start();
|
|
}
|
|
|
|
Process {
|
|
id: occupyFingerprintSensorProc
|
|
command: ["fprintd-verify"]
|
|
}
|
|
|
|
PamContext {
|
|
id: pam
|
|
configDirectory: root.pamConfigDirectory
|
|
config: root.pamConfig
|
|
user: HostService.username
|
|
|
|
onPamMessage: {
|
|
Logger.i("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:", responseRequired);
|
|
|
|
if (this.responseRequired) {
|
|
Logger.i("LockContext", "Responding to PAM with password");
|
|
if (root.currentText !== "") {
|
|
this.respond(root.currentText);
|
|
unlockInProgress = true;
|
|
} else {
|
|
root.waitingForPassword = true;
|
|
infoMessage = I18n.tr("lock-screen.password");
|
|
showInfo = true;
|
|
}
|
|
} else if (messageIsError) {
|
|
errorMessage = message;
|
|
showFailure = true;
|
|
} else {
|
|
infoMessage = message;
|
|
showInfo = true;
|
|
}
|
|
}
|
|
|
|
onCompleted: result => {
|
|
Logger.i("LockContext", "PAM completed with result:", result);
|
|
if (result === PamResult.Success) {
|
|
Logger.i("LockContext", "Authentication successful");
|
|
root.unlocked();
|
|
} else {
|
|
Logger.i("LockContext", "Authentication failed");
|
|
root.currentText = "";
|
|
errorMessage = I18n.tr("authentication.failed");
|
|
showFailure = true;
|
|
root.failed();
|
|
}
|
|
root.unlockInProgress = false;
|
|
}
|
|
|
|
onError: {
|
|
Logger.i("LockContext", "PAM error:", error, "message:", message);
|
|
errorMessage = message || "Authentication error";
|
|
showFailure = true;
|
|
root.unlockInProgress = false;
|
|
root.failed();
|
|
}
|
|
}
|
|
}
|