1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-12 08:42:13 -04:00

feat(Auth): Unify shared PAM sync across greeter & lockscreen

- Add a neutral `dms auth sync` command and reuse the shared auth flow from:
- Settings auth toggle auto-apply
- `dms greeter sync`
- `dms greeter install`
- greeter auth cleanup paths

- Rework lockscreen PAM so DMS builds /etc/pam.d/dankshell from the system login stack, but removes fingerprint and U2F from that password path. Keep /etc/pam.d/dankshell-u2f separate.

- Preserve custom PAM files in place to avoid adding duplicate greeter auth when the distro already provides it, and keep NixOS on the non-writing path.
This commit is contained in:
purian23
2026-03-27 12:52:08 -04:00
parent 521a3fa6e8
commit e7ee26ce74
17 changed files with 1968 additions and 514 deletions

View File

@@ -4,6 +4,8 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services
Singleton {
id: root
@@ -52,6 +54,14 @@ Singleton {
readonly property var forcedFprintAvailable: envFlag("DMS_FORCE_FPRINT_AVAILABLE")
readonly property var forcedU2fAvailable: envFlag("DMS_FORCE_U2F_AVAILABLE")
property bool authApplyRunning: false
property bool authApplyQueued: false
property bool authApplyRerunRequested: false
property bool authApplyTerminalFallbackFromPrecheck: false
property string authApplyStdout: ""
property string authApplyStderr: ""
property string authApplySudoProbeStderr: ""
property string authApplyTerminalFallbackStderr: ""
function detectQtTools() {
qtToolsDetectionProcess.running = true;
@@ -92,6 +102,50 @@ Singleton {
pluginSettingsCheckProcess.running = true;
}
function scheduleAuthApply() {
if (!settingsRoot || settingsRoot.isGreeterMode)
return;
authApplyQueued = true;
if (authApplyRunning) {
authApplyRerunRequested = true;
return;
}
authApplyDebounce.restart();
}
function beginAuthApply() {
if (!authApplyQueued || authApplyRunning || !settingsRoot || settingsRoot.isGreeterMode)
return;
authApplyQueued = false;
authApplyRerunRequested = false;
authApplyStdout = "";
authApplyStderr = "";
authApplySudoProbeStderr = "";
authApplyTerminalFallbackStderr = "";
authApplyTerminalFallbackFromPrecheck = false;
authApplyRunning = true;
authApplySudoProbeProcess.running = true;
}
function launchAuthApplyTerminalFallback(fromPrecheck, details) {
authApplyTerminalFallbackFromPrecheck = fromPrecheck;
if (details && details !== "")
ToastService.showInfo(I18n.tr("Authentication changes need sudo. Opening terminal so you can use password or fingerprint."), details, "", "auth-sync");
authApplyTerminalFallbackStderr = "";
authApplyTerminalFallbackProcess.running = true;
}
function finishAuthApply() {
const shouldRerun = authApplyQueued || authApplyRerunRequested;
authApplyRunning = false;
authApplyRerunRequested = false;
if (shouldRerun)
authApplyDebounce.restart();
}
function stripPamComment(line) {
if (!line)
return "";
@@ -417,6 +471,91 @@ Singleton {
}
}
Timer {
id: authApplyDebounce
interval: 300
repeat: false
onTriggered: root.beginAuthApply()
}
property var authApplyProcess: Process {
command: ["dms", "auth", "sync", "--yes"]
running: false
stdout: StdioCollector {
onStreamFinished: root.authApplyStdout = text || ""
}
stderr: StdioCollector {
onStreamFinished: root.authApplyStderr = text || ""
}
onExited: exitCode => {
const out = (root.authApplyStdout || "").trim();
const err = (root.authApplyStderr || "").trim();
if (exitCode === 0) {
let details = out;
if (err !== "")
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
ToastService.showInfo(I18n.tr("Authentication changes applied."), details, "", "auth-sync");
root.detectAuthCapabilities();
root.finishAuthApply();
return;
}
let details = "";
if (out !== "")
details = out;
if (err !== "")
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
ToastService.showWarning(I18n.tr("Background authentication sync failed. Trying terminal mode."), details, "", "auth-sync");
root.launchAuthApplyTerminalFallback(false, "");
}
}
property var authApplySudoProbeProcess: Process {
command: ["sudo", "-n", "true"]
running: false
stderr: StdioCollector {
onStreamFinished: root.authApplySudoProbeStderr = text || ""
}
onExited: exitCode => {
const err = (root.authApplySudoProbeStderr || "").trim();
if (exitCode === 0) {
ToastService.showInfo(I18n.tr("Applying authentication changes…"), "", "", "auth-sync");
root.authApplyProcess.running = true;
return;
}
root.launchAuthApplyTerminalFallback(true, err);
}
}
property var authApplyTerminalFallbackProcess: Process {
command: ["dms", "auth", "sync", "--terminal", "--yes"]
running: false
stderr: StdioCollector {
onStreamFinished: root.authApplyTerminalFallbackStderr = text || ""
}
onExited: exitCode => {
if (exitCode === 0) {
const message = root.authApplyTerminalFallbackFromPrecheck
? I18n.tr("Terminal opened. Complete authentication setup there; it will close automatically when done.")
: I18n.tr("Terminal fallback opened. Complete authentication setup there; it will close automatically when done.");
ToastService.showInfo(message, "", "", "auth-sync");
} else {
let details = (root.authApplyTerminalFallbackStderr || "").trim();
ToastService.showError(I18n.tr("Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.") + " (exit " + exitCode + ")", details, "", "auth-sync");
}
root.finishAuthApply();
}
}
FileView {
id: greetdPamWatcher
path: "/etc/pam.d/greetd"

View File

@@ -169,8 +169,8 @@ var SPEC = {
lockDateFormat: { def: "" },
greeterRememberLastSession: { def: true },
greeterRememberLastUser: { def: true },
greeterEnableFprint: { def: false },
greeterEnableU2f: { def: false },
greeterEnableFprint: { def: false, onChange: "scheduleAuthApply" },
greeterEnableU2f: { def: false, onChange: "scheduleAuthApply" },
greeterWallpaperPath: { def: "" },
greeterUse24HourClock: { def: true },
greeterShowSeconds: { def: false },
@@ -353,7 +353,7 @@ var SPEC = {
lockScreenShowMediaPlayer: { def: true },
lockScreenPowerOffMonitorsOnLock: { def: false },
lockAtStartup: { def: false },
enableFprint: { def: false },
enableFprint: { def: false, onChange: "scheduleAuthApply" },
maxFprintTries: { def: 15 },
fprintdAvailable: { def: false, persist: false },
lockFingerprintCanEnable: { def: false, persist: false },
@@ -363,7 +363,7 @@ var SPEC = {
greeterFingerprintReady: { def: false, persist: false },
greeterFingerprintReason: { def: "probe_failed", persist: false },
greeterFingerprintSource: { def: "none", persist: false },
enableU2f: { def: false },
enableU2f: { def: false, onChange: "scheduleAuthApply" },
u2fMode: { def: "or" },
u2fAvailable: { def: false, persist: false },
lockU2fCanEnable: { def: false, persist: false },