1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-02 03:28:28 -04:00

feat(auth): expand shared PAM support for custom policies

- Add support for DMS and System managed factor policies
- Add validated dedicated security-key PAM / U2F Key sources
- Restore U2F OR/AND flows

Related: #2874
Port 1.5
This commit is contained in:
purian23
2026-07-16 09:24:12 -04:00
parent 7c24e85c19
commit 48e36ae146
10 changed files with 544 additions and 105 deletions
+43 -22
View File
@@ -71,7 +71,7 @@ Scope {
}
function proceedAfterPrimaryAuth(): void {
if (SettingsData.enableU2f && SettingsData.u2fMode === "and" && u2f.available) {
if (!root.u2fSuppressedByPrimaryPam && SettingsData.enableU2f && SettingsData.u2fMode === "and" && u2f.available) {
u2f.startForSecondFactor();
} else {
completeUnlock();
@@ -91,8 +91,9 @@ Scope {
}
readonly property bool customPamActive: SettingsData.lockPamPath !== "" && customPamWatcher.loaded
readonly property bool fprintSuppressedByCustomPam: customPamActive && SettingsData.lockPamInlineFprint
readonly property bool u2fSuppressedByCustomPam: customPamActive && SettingsData.lockPamInlineU2f
readonly property bool fprintSuppressedByPrimaryPam: SettingsData.lockPamExternallyManaged || (customPamActive && SettingsData.lockPamInlineFprint)
readonly property bool u2fSuppressedByPrimaryPam: SettingsData.lockPamExternallyManaged || (customPamActive && SettingsData.lockPamInlineU2f)
readonly property bool customU2fPamActive: SettingsData.lockU2fPamPath !== "" && customU2fPamWatcher.loaded
FileView {
id: customPamWatcher
@@ -109,16 +110,16 @@ Scope {
}
FileView {
id: nixosMarker
id: u2fConfigWatcher
path: "/etc/NIXOS"
path: "/etc/pam.d/dankshell-u2f"
printErrors: false
}
FileView {
id: u2fConfigWatcher
id: customU2fPamWatcher
path: "/etc/pam.d/dankshell-u2f"
path: SettingsData.lockU2fPamPath !== "" ? SettingsData.lockU2fPamPath : ""
printErrors: false
}
@@ -145,26 +146,23 @@ Scope {
}
function ensureUserPamConfig(): void {
if (root.runningFromNixStore || resolveUserPam.running)
if (SettingsData.lockPamExternallyManaged || resolveUserPam.running)
return;
resolveUserPam.running = true;
}
Component.onCompleted: ensureUserPamConfig()
// Detects Nix-installed DMS on non-NixOS systems
readonly property bool runningFromNixStore: Quickshell.shellDir.startsWith("/nix/store/")
PamContext {
id: passwd
config: {
if (root.customPamActive)
return SettingsData.lockPamPath.slice(SettingsData.lockPamPath.lastIndexOf("/") + 1);
if (SettingsData.lockPamExternallyManaged)
return "login";
if (dankshellConfigWatcher.loaded)
return "dankshell";
if (nixosMarker.loaded || root.runningFromNixStore)
return "login";
if (userPamWatcher.loaded)
return "dankshell";
return "login";
@@ -174,9 +172,9 @@ Scope {
const idx = SettingsData.lockPamPath.lastIndexOf("/");
return idx > 0 ? SettingsData.lockPamPath.slice(0, idx) : "/";
}
if (dankshellConfigWatcher.loaded)
if (SettingsData.lockPamExternallyManaged)
return "/etc/pam.d";
if (nixosMarker.loaded || root.runningFromNixStore)
if (dankshellConfigWatcher.loaded)
return "/etc/pam.d";
if (userPamWatcher.loaded)
return root.userPamDir;
@@ -265,7 +263,7 @@ Scope {
property int errorTries
function checkAvail(): void {
if (!available || !SettingsData.enableFprint || !root.lockSecured || root.fprintSuppressedByCustomPam) {
if (!available || !SettingsData.enableFprint || !root.lockSecured || root.fprintSuppressedByPrimaryPam) {
abort();
return;
}
@@ -325,7 +323,7 @@ Scope {
property bool available: SettingsData.lockU2fReady
function checkAvail(): void {
if (!available || !SettingsData.enableU2f || !root.lockSecured || root.u2fSuppressedByCustomPam) {
if (!available || !SettingsData.enableU2f || !root.lockSecured || root.u2fSuppressedByPrimaryPam) {
abort();
return;
}
@@ -335,7 +333,7 @@ Scope {
}
function startForSecondFactor(): void {
if (!available || !SettingsData.enableU2f || root.u2fSuppressedByCustomPam) {
if (!available || !SettingsData.enableU2f || root.u2fSuppressedByPrimaryPam) {
root.completeUnlock();
return;
}
@@ -348,7 +346,7 @@ Scope {
}
function startForAlternativeAuth(): void {
if (!available || !SettingsData.enableU2f || root.u2fSuppressedByCustomPam || SettingsData.u2fMode !== "or" || root.unlockInProgress || passwd.active || active)
if (!available || !SettingsData.enableU2f || root.u2fSuppressedByPrimaryPam || SettingsData.u2fMode !== "or" || root.unlockInProgress || passwd.active || active)
return;
abort();
root.u2fPending = true;
@@ -358,8 +356,18 @@ Scope {
start();
}
config: u2fConfigWatcher.loaded ? "dankshell-u2f" : "u2f"
configDirectory: u2fConfigWatcher.loaded ? "/etc/pam.d" : Quickshell.shellDir + "/assets/pam"
config: {
if (root.customU2fPamActive)
return SettingsData.lockU2fPamPath.slice(SettingsData.lockU2fPamPath.lastIndexOf("/") + 1);
return u2fConfigWatcher.loaded ? "dankshell-u2f" : "u2f";
}
configDirectory: {
if (root.customU2fPamActive) {
const idx = SettingsData.lockU2fPamPath.lastIndexOf("/");
return idx > 0 ? SettingsData.lockU2fPamPath.slice(0, idx) : "/";
}
return u2fConfigWatcher.loaded ? "/etc/pam.d" : Quickshell.shellDir + "/assets/pam";
}
onMessageChanged: {
if (message.toLowerCase().includes("touch"))
@@ -478,7 +486,7 @@ Scope {
root.attemptInfoMessages = [];
root.lockoutAnnouncedThisAttempt = false;
root.resetAuthFlows();
if (!dankshellConfigWatcher.loaded && !nixosMarker.loaded && !userPamWatcher.loaded)
if (!SettingsData.lockPamExternallyManaged && !dankshellConfigWatcher.loaded && !userPamWatcher.loaded)
ensureUserPamConfig();
fprint.checkAvail();
u2f.checkAvail();
@@ -516,6 +524,19 @@ Scope {
u2f.checkAvail();
}
function onLockPamExternallyManagedChanged(): void {
root.resetAuthFlows();
if (!SettingsData.lockPamExternallyManaged)
root.ensureUserPamConfig();
fprint.checkAvail();
u2f.checkAvail();
}
function onLockU2fPamPathChanged(): void {
u2f.abort();
u2f.checkAvail();
}
function onU2fModeChanged(): void {
if (root.lockSecured) {
u2f.abort();