mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
129 lines
3.7 KiB
QML
129 lines
3.7 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Services.Pam
|
|
import qs.Commons
|
|
import qs.Services.System
|
|
|
|
Scope {
|
|
id: root
|
|
signal unlocked
|
|
signal failed
|
|
|
|
property string currentText: ""
|
|
property bool unlockInProgress: false
|
|
property bool showFailure: false
|
|
property string errorMessage: ""
|
|
property string infoMessage: ""
|
|
property bool pamAvailable: typeof PamContext !== "undefined"
|
|
|
|
// Determine PAM config based on OS
|
|
// On NixOS: use /etc/pam.d/login
|
|
// Otherwise: use generated config in configDir
|
|
readonly property string pamConfigDirectory: {
|
|
if (HostService.isReady && HostService.isNixOS) {
|
|
return "/etc/pam.d";
|
|
}
|
|
return Settings.configDir + "pam";
|
|
}
|
|
readonly property string pamConfig: {
|
|
if (HostService.isReady && HostService.isNixOS) {
|
|
return "login";
|
|
}
|
|
return "password.conf";
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
if (HostService.isReady) {
|
|
if (HostService.isNixOS) {
|
|
Logger.i("LockContext", "NixOS detected, using system PAM config: /etc/pam.d/login");
|
|
} else {
|
|
Logger.i("LockContext", "Using generated PAM config:", pamConfigDirectory + "/" + pamConfig);
|
|
}
|
|
} else {
|
|
// Wait for HostService to be ready
|
|
HostService.isReadyChanged.connect(function () {
|
|
if (HostService.isNixOS) {
|
|
Logger.i("LockContext", "NixOS detected, using system PAM config: /etc/pam.d/login");
|
|
} else {
|
|
Logger.i("LockContext", "Using generated PAM config:", pamConfigDirectory + "/" + pamConfig);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
onCurrentTextChanged: {
|
|
if (currentText !== "") {
|
|
showFailure = false;
|
|
errorMessage = "";
|
|
}
|
|
}
|
|
|
|
function tryUnlock() {
|
|
if (!pamAvailable) {
|
|
errorMessage = "PAM not available";
|
|
showFailure = true;
|
|
return;
|
|
}
|
|
|
|
if (root.unlockInProgress) {
|
|
Logger.i("LockContext", "Unlock already in progress, ignoring duplicate attempt");
|
|
return;
|
|
}
|
|
|
|
root.unlockInProgress = true;
|
|
errorMessage = "";
|
|
showFailure = false;
|
|
|
|
Logger.i("LockContext", "Starting PAM authentication for user:", pam.user);
|
|
pam.start();
|
|
}
|
|
|
|
PamContext {
|
|
id: pam
|
|
// Use custom PAM config to ensure predictable password-only authentication
|
|
// On NixOS: uses /etc/pam.d/login
|
|
// Otherwise: uses config created in Settings.qml and stored in configDir/pam/
|
|
configDirectory: root.pamConfigDirectory
|
|
config: root.pamConfig
|
|
user: HostService.username
|
|
|
|
onPamMessage: {
|
|
Logger.i("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:", responseRequired);
|
|
|
|
if (messageIsError) {
|
|
errorMessage = message;
|
|
} else {
|
|
infoMessage = message;
|
|
}
|
|
|
|
if (this.responseRequired) {
|
|
Logger.i("LockContext", "Responding to PAM with password");
|
|
this.respond(root.currentText);
|
|
}
|
|
}
|
|
|
|
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("lock-screen.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();
|
|
}
|
|
}
|
|
}
|