mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-06 13:38:28 -04:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74896fb87c | |||
| f1f528b2cb | |||
| 9853e1431b | |||
| e7b8196a4a | |||
| 85ebb402cb |
@@ -200,7 +200,9 @@ in
|
|||||||
];
|
];
|
||||||
# DMS currently relies on /etc/pam.d/login for lock screen password auth on NixOS.
|
# DMS currently relies on /etc/pam.d/login for lock screen password auth on NixOS.
|
||||||
# Declare security.pam.services.dankshell only if you want to override that runtime fallback.
|
# Declare security.pam.services.dankshell only if you want to override that runtime fallback.
|
||||||
# U2F and fingerprint are handled separately by DMS — do not add pam_u2f or pam_fprintd here.
|
# Do not add pam_u2f or pam_fprintd here for security-key unlock, enable
|
||||||
|
# programs.dank-material-shell.lockscreen.securityKey.enable, which declares the
|
||||||
|
# dedicated dankshell-u2f service DMS drives on its own.
|
||||||
# security.pam.services.dankshell = {
|
# security.pam.services.dankshell = {
|
||||||
# # Example: add faillock
|
# # Example: add faillock
|
||||||
# faillock.enable = true;
|
# faillock.enable = true;
|
||||||
|
|||||||
@@ -23,6 +23,15 @@ in
|
|||||||
description = "Systemd target to bind to.";
|
description = "Systemd target to bind to.";
|
||||||
default = "graphical-session.target";
|
default = "graphical-session.target";
|
||||||
};
|
};
|
||||||
|
options.programs.dank-material-shell.lockscreen.securityKey = {
|
||||||
|
enable = lib.mkEnableOption "FIDO2/U2F security key unlock for the DMS lock screen via a dedicated dankshell-u2f PAM service";
|
||||||
|
package = lib.mkPackageOption pkgs "pam_u2f" { };
|
||||||
|
moduleArgs = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "cue" ];
|
||||||
|
description = "Arguments passed to pam_u2f.so in the dankshell-u2f PAM service.";
|
||||||
|
};
|
||||||
|
};
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
||||||
description = "DankMaterialShell";
|
description = "DankMaterialShell";
|
||||||
@@ -46,6 +55,18 @@ in
|
|||||||
inherit value;
|
inherit value;
|
||||||
}) common.plugins;
|
}) common.plugins;
|
||||||
|
|
||||||
|
# DMS's bundled U2F fallback stack references pam_u2f.so by name, which NixOS's
|
||||||
|
# libpam cannot resolve; the dedicated service below uses the absolute store path
|
||||||
|
# and is picked up automatically by the lock screen when present.
|
||||||
|
security.pam.services."dankshell-u2f" = lib.mkIf cfg.lockscreen.securityKey.enable {
|
||||||
|
text = ''
|
||||||
|
auth required ${cfg.lockscreen.securityKey.package}/lib/security/pam_u2f.so ${lib.concatStringsSep " " cfg.lockscreen.securityKey.moduleArgs}
|
||||||
|
account required pam_permit.so
|
||||||
|
password required pam_deny.so
|
||||||
|
session required pam_permit.so
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
services.power-profiles-daemon.enable = lib.mkDefault true;
|
services.power-profiles-daemon.enable = lib.mkDefault true;
|
||||||
services.accounts-daemon.enable = lib.mkDefault true;
|
services.accounts-daemon.enable = lib.mkDefault true;
|
||||||
services.geoclue2.enable = lib.mkDefault true;
|
services.geoclue2.enable = lib.mkDefault true;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pkgs.testers.runNixOSTest {
|
|||||||
programs.dank-material-shell = {
|
programs.dank-material-shell = {
|
||||||
enable = true;
|
enable = true;
|
||||||
systemd.enable = true;
|
systemd.enable = true;
|
||||||
|
lockscreen.securityKey.enable = true;
|
||||||
plugins = {
|
plugins = {
|
||||||
TestPlugin = {
|
TestPlugin = {
|
||||||
src = pkgs.emptyDirectory;
|
src = pkgs.emptyDirectory;
|
||||||
@@ -39,6 +40,7 @@ pkgs.testers.runNixOSTest {
|
|||||||
machine.succeed("su -- danklinux -c 'dms --help >/dev/null'")
|
machine.succeed("su -- danklinux -c 'dms --help >/dev/null'")
|
||||||
machine.succeed("test -d /etc/xdg/quickshell/dms-plugins")
|
machine.succeed("test -d /etc/xdg/quickshell/dms-plugins")
|
||||||
machine.succeed("test -f /run/current-system/sw/lib/systemd/user/dms.service")
|
machine.succeed("test -f /run/current-system/sw/lib/systemd/user/dms.service")
|
||||||
|
machine.succeed("grep -q 'lib/security/pam_u2f.so cue' /etc/pam.d/dankshell-u2f")
|
||||||
|
|
||||||
payload = json.loads(machine.succeed("su -- danklinux -c 'dms doctor --json'"))
|
payload = json.loads(machine.succeed("su -- danklinux -c 'dms doctor --json'"))
|
||||||
t.assertIn("summary", payload)
|
t.assertIn("summary", payload)
|
||||||
|
|||||||
@@ -604,7 +604,7 @@ Singleton {
|
|||||||
let details = out;
|
let details = out;
|
||||||
if (err !== "")
|
if (err !== "")
|
||||||
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
|
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
|
||||||
ToastService.showInfo(I18n.tr("Authentication changes applied"), details, "", "auth-sync");
|
ToastService.showInfo(I18n.tr("Authentication changes applied."), details, "", "auth-sync");
|
||||||
root.detectAuthCapabilities();
|
root.detectAuthCapabilities();
|
||||||
root.finishAuthApply();
|
root.finishAuthApply();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Item {
|
|||||||
readonly property real _barInsetPaddingAuto: _barIsVertical ? Theme.spacingXS : _edgeBaseMargin
|
readonly property real _barInsetPaddingAuto: _barIsVertical ? Theme.spacingXS : _edgeBaseMargin
|
||||||
readonly property real _barInsetPadding: _barInsetPaddingRaw < 0 ? _barInsetPaddingAuto : _barInsetPaddingRaw
|
readonly property real _barInsetPadding: _barInsetPaddingRaw < 0 ? _barInsetPaddingAuto : _barInsetPaddingRaw
|
||||||
// Connected-frame Bar Inset Padding: absolute free-end inset (auto < 0 = frameThickness, 0 = edge-to-edge).
|
// Connected-frame Bar Inset Padding: absolute free-end inset (auto < 0 = frameThickness, 0 = edge-to-edge).
|
||||||
// Any amount beyond the frameThickness baseline is also added at the bar-clearance ends (all ends).
|
// FrameExclusions already moves a free bar end inward by frameThickness so use frame inset to mangage the gap
|
||||||
readonly property real _frameInsetResolved: SettingsData.frameBarInsetPadding < 0 ? SettingsData.frameThickness : SettingsData.frameBarInsetPadding
|
readonly property real _frameInsetResolved: SettingsData.frameBarInsetPadding < 0 ? SettingsData.frameThickness : SettingsData.frameBarInsetPadding
|
||||||
readonly property real _frameInsetExtra: Math.max(0, _frameInsetResolved - SettingsData.frameThickness)
|
readonly property real _frameInsetExtra: Math.max(0, _frameInsetResolved - SettingsData.frameThickness)
|
||||||
|
|
||||||
@@ -47,28 +47,28 @@ Item {
|
|||||||
if (_barIsVertical)
|
if (_barIsVertical)
|
||||||
return _edgeBaseMargin;
|
return _edgeBaseMargin;
|
||||||
if (_usesFrameBarChrome)
|
if (_usesFrameBarChrome)
|
||||||
return hasAdjacentLeftBarLive ? (_edgeBaseMargin + SettingsData.frameBarSize + _frameInsetExtra) : Math.max(0, _frameInsetResolved);
|
return hasAdjacentLeftBarLive ? (_edgeBaseMargin + SettingsData.frameBarSize + _frameInsetExtra) : _frameInsetExtra;
|
||||||
return Math.max(0, _barInsetPadding);
|
return Math.max(0, _barInsetPadding);
|
||||||
}
|
}
|
||||||
readonly property real _rightMargin: {
|
readonly property real _rightMargin: {
|
||||||
if (_barIsVertical)
|
if (_barIsVertical)
|
||||||
return _edgeBaseMargin;
|
return _edgeBaseMargin;
|
||||||
if (_usesFrameBarChrome)
|
if (_usesFrameBarChrome)
|
||||||
return hasAdjacentRightBarLive ? (_edgeBaseMargin + SettingsData.frameBarSize + _frameInsetExtra) : Math.max(0, _frameInsetResolved);
|
return hasAdjacentRightBarLive ? (_edgeBaseMargin + SettingsData.frameBarSize + _frameInsetExtra) : _frameInsetExtra;
|
||||||
return Math.max(0, _barInsetPadding);
|
return Math.max(0, _barInsetPadding);
|
||||||
}
|
}
|
||||||
readonly property real _topMargin: {
|
readonly property real _topMargin: {
|
||||||
if (!_barIsVertical)
|
if (!_barIsVertical)
|
||||||
return 0;
|
return 0;
|
||||||
if (_usesFrameBarChrome)
|
if (_usesFrameBarChrome)
|
||||||
return hasAdjacentTopBarLive ? (outlineThickness + SettingsData.frameThickness + _frameInsetExtra) : Math.max(0, _frameInsetResolved);
|
return hasAdjacentTopBarLive ? (outlineThickness + SettingsData.frameThickness + _frameInsetExtra) : _frameInsetExtra;
|
||||||
return Math.max(0, _barInsetPadding);
|
return Math.max(0, _barInsetPadding);
|
||||||
}
|
}
|
||||||
readonly property real _bottomMargin: {
|
readonly property real _bottomMargin: {
|
||||||
if (!_barIsVertical)
|
if (!_barIsVertical)
|
||||||
return 0;
|
return 0;
|
||||||
if (_usesFrameBarChrome)
|
if (_usesFrameBarChrome)
|
||||||
return hasAdjacentBottomBarLive ? (outlineThickness + SettingsData.frameThickness + _frameInsetExtra) : Math.max(0, _frameInsetResolved);
|
return hasAdjacentBottomBarLive ? (outlineThickness + SettingsData.frameThickness + _frameInsetExtra) : _frameInsetExtra;
|
||||||
return Math.max(0, _barInsetPadding);
|
return Math.max(0, _barInsetPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,39 +19,39 @@ Item {
|
|||||||
|
|
||||||
function greeterFingerprintDescription() {
|
function greeterFingerprintDescription() {
|
||||||
if (SettingsData.greeterPamExternallyManaged)
|
if (SettingsData.greeterPamExternallyManaged)
|
||||||
return I18n.tr("Managed by the primary PAM source", "factor managed by PAM source status");
|
return I18n.tr("Managed by the primary PAM source.", "factor managed by PAM source status");
|
||||||
if (SettingsData.greeterFingerprintSource === "pam")
|
if (SettingsData.greeterFingerprintSource === "pam")
|
||||||
return I18n.tr("PAM already provides fingerprint auth. Enable this to show it at login.", "greeter fingerprint login setting");
|
return I18n.tr("PAM already provides fingerprint auth. Enable this to show it at login.", "greeter fingerprint login setting");
|
||||||
|
|
||||||
switch (SettingsData.greeterFingerprintReason) {
|
switch (SettingsData.greeterFingerprintReason) {
|
||||||
case "ready":
|
case "ready":
|
||||||
return I18n.tr("Authentication changes apply automatically", "greeter auth setting description");
|
return I18n.tr("Authentication changes apply automatically.", "greeter auth setting description");
|
||||||
case "missing_enrollment":
|
case "missing_enrollment":
|
||||||
return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.", "greeter fingerprint login setting");
|
return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.", "greeter fingerprint login setting");
|
||||||
case "missing_reader":
|
case "missing_reader":
|
||||||
return I18n.tr("No fingerprint reader detected", "fingerprint setting status");
|
return I18n.tr("No fingerprint reader detected.", "fingerprint setting status");
|
||||||
case "missing_pam_support":
|
case "missing_pam_support":
|
||||||
return I18n.tr("Not available — install fprintd and pam_fprintd, or configure greetd PAM.", "greeter fingerprint login setting");
|
return I18n.tr("Not available — install fprintd and pam_fprintd, or configure greetd PAM.", "greeter fingerprint login setting");
|
||||||
default:
|
default:
|
||||||
return I18n.tr("Fingerprint availability could not be confirmed", "fingerprint setting status");
|
return I18n.tr("Fingerprint availability could not be confirmed.", "fingerprint setting status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function greeterU2fDescription() {
|
function greeterU2fDescription() {
|
||||||
if (SettingsData.greeterPamExternallyManaged)
|
if (SettingsData.greeterPamExternallyManaged)
|
||||||
return I18n.tr("Managed by the primary PAM source", "factor managed by PAM source status");
|
return I18n.tr("Managed by the primary PAM source.", "factor managed by PAM source status");
|
||||||
if (SettingsData.greeterU2fSource === "pam")
|
if (SettingsData.greeterU2fSource === "pam")
|
||||||
return I18n.tr("PAM already provides security-key auth. Enable this to show it at login.", "greeter security key login setting");
|
return I18n.tr("PAM already provides security-key auth. Enable this to show it at login.", "greeter security key login setting");
|
||||||
|
|
||||||
switch (SettingsData.greeterU2fReason) {
|
switch (SettingsData.greeterU2fReason) {
|
||||||
case "ready":
|
case "ready":
|
||||||
return I18n.tr("Authentication changes apply automatically", "greeter auth setting description");
|
return I18n.tr("Authentication changes apply automatically.", "greeter auth setting description");
|
||||||
case "missing_key_registration":
|
case "missing_key_registration":
|
||||||
return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", "security key setting status");
|
return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", "security key setting status");
|
||||||
case "missing_pam_support":
|
case "missing_pam_support":
|
||||||
return I18n.tr("Not available — install or configure pam_u2f, or configure greetd PAM.", "greeter security key login setting");
|
return I18n.tr("Not available — install or configure pam_u2f, or configure greetd PAM.", "greeter security key login setting");
|
||||||
default:
|
default:
|
||||||
return I18n.tr("Security-key availability could not be confirmed", "security key setting status");
|
return I18n.tr("Security-key availability could not be confirmed.", "security key setting status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +400,7 @@ Item {
|
|||||||
settingKey: "greeterStatus"
|
settingKey: "greeterStatus"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Sync applies your theme and settings to the login screen. Shared users should run dms greeter sync --profile instead of a primary user sync.")
|
text: I18n.tr("Sync applies your theme and settings to the login screen. Other users should run dms greeter sync --profile instead of a full sync. Authentication changes apply automatically.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -474,7 +474,7 @@ Item {
|
|||||||
settingKey: "greeterAuth"
|
settingKey: "greeterAuth"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Enable fingerprint or security key for DMS Greeter")
|
text: I18n.tr("Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -486,7 +486,7 @@ Item {
|
|||||||
settingKey: "greeterPamExternallyManaged"
|
settingKey: "greeterPamExternallyManaged"
|
||||||
tags: ["greeter", "pam", "managed", "external", "greetd", "auth"]
|
tags: ["greeter", "pam", "managed", "external", "greetd", "auth"]
|
||||||
text: I18n.tr("Use system PAM authentication", "system PAM policy toggle")
|
text: I18n.tr("Use system PAM authentication", "system PAM policy toggle")
|
||||||
description: I18n.tr("DMS removes its managed block from /etc/pam.d/greetd and stops write services", "greeter system PAM toggle description")
|
description: I18n.tr("DMS removes its managed block from /etc/pam.d/greetd and stops writing to it", "greeter system PAM toggle description")
|
||||||
checked: SettingsData.greeterPamExternallyManaged
|
checked: SettingsData.greeterPamExternallyManaged
|
||||||
onToggled: checked => SettingsData.set("greeterPamExternallyManaged", checked)
|
onToggled: checked => SettingsData.set("greeterPamExternallyManaged", checked)
|
||||||
}
|
}
|
||||||
@@ -553,7 +553,7 @@ Item {
|
|||||||
settingKey: "greeterLockDateFormat"
|
settingKey: "greeterLockDateFormat"
|
||||||
tags: ["greeter", "date", "format"]
|
tags: ["greeter", "date", "format"]
|
||||||
text: I18n.tr("Date Format")
|
text: I18n.tr("Date Format")
|
||||||
description: I18n.tr("Format the date on the login screen")
|
description: I18n.tr("Greeter only — format for the date on the login screen")
|
||||||
options: root._lockDateFormatPresets.map(p => p.label)
|
options: root._lockDateFormatPresets.map(p => p.label)
|
||||||
currentValue: {
|
currentValue: {
|
||||||
var current = (SettingsData.greeterLockDateFormat !== undefined && SettingsData.greeterLockDateFormat !== "") ? SettingsData.greeterLockDateFormat : SettingsData.lockDateFormat || "";
|
var current = (SettingsData.greeterLockDateFormat !== undefined && SettingsData.greeterLockDateFormat !== "") ? SettingsData.greeterLockDateFormat : SettingsData.lockDateFormat || "";
|
||||||
@@ -577,7 +577,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Use a custom image for the login screen, or leave empty to use desktop wallpaper")
|
text: I18n.tr("Use a custom image for the login screen, or leave empty to use your desktop wallpaper.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -605,7 +605,7 @@ Item {
|
|||||||
settingKey: "greeterBehavior"
|
settingKey: "greeterBehavior"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Convenience options for the login screen")
|
text: I18n.tr("Convenience options for the login screen. Sync to apply.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -649,7 +649,7 @@ Item {
|
|||||||
settingKey: "greeterDeps"
|
settingKey: "greeterDeps"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Requires greetd, dms-greeter, and your user in the greeter group (plus fprintd/pam_fprintd for fingerprint, pam_u2f for security keys).")
|
text: I18n.tr("Requires greetd, dms-greeter, and your user in the greeter group (plus fprintd/pam_fprintd for fingerprint, pam_u2f for security keys). Auth changes apply automatically and may open a terminal for sudo.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -658,7 +658,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Installation and PAM setup are documented in the ") + "<a href=\"https://danklinux.com/docs/dankgreeter/installation\" style=\"text-decoration:none; color:" + Theme.primary + ";\">DankGreeter docs.</a> "
|
text: I18n.tr("Installation and PAM setup: see the ") + "<a href=\"https://danklinux.com/docs/dankgreeter/installation\" style=\"text-decoration:none; color:" + Theme.primary + ";\">DankGreeter docs</a> " + I18n.tr("or run ") + "'dms greeter install'."
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
|
|||||||
@@ -96,28 +96,28 @@ Item {
|
|||||||
function lockFingerprintDescription() {
|
function lockFingerprintDescription() {
|
||||||
switch (SettingsData.lockFingerprintReason) {
|
switch (SettingsData.lockFingerprintReason) {
|
||||||
case "ready":
|
case "ready":
|
||||||
return I18n.tr("Use fingerprint authentication for the lock screen", "lock screen fingerprint setting");
|
return I18n.tr("Use fingerprint authentication for the lock screen.", "lock screen fingerprint setting");
|
||||||
case "missing_enrollment":
|
case "missing_enrollment":
|
||||||
return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.", "lock screen fingerprint setting");
|
return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.", "lock screen fingerprint setting");
|
||||||
case "missing_reader":
|
case "missing_reader":
|
||||||
return I18n.tr("No fingerprint reader detected", "fingerprint setting status");
|
return I18n.tr("No fingerprint reader detected.", "fingerprint setting status");
|
||||||
case "missing_pam_support":
|
case "missing_pam_support":
|
||||||
return I18n.tr("Not available - install fprintd and pam_fprintd", "lock screen fingerprint setting");
|
return I18n.tr("Not available — install fprintd and pam_fprintd.", "lock screen fingerprint setting");
|
||||||
default:
|
default:
|
||||||
return I18n.tr("Fingerprint availability could not be confirmed", "fingerprint setting status");
|
return I18n.tr("Fingerprint availability could not be confirmed.", "fingerprint setting status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function lockU2fDescription() {
|
function lockU2fDescription() {
|
||||||
switch (SettingsData.lockU2fReason) {
|
switch (SettingsData.lockU2fReason) {
|
||||||
case "ready":
|
case "ready":
|
||||||
return I18n.tr("Use a security key for lock screen authentication", "lock screen U2F security key setting");
|
return I18n.tr("Use a security key for lock screen authentication.", "lock screen U2F security key setting");
|
||||||
case "missing_key_registration":
|
case "missing_key_registration":
|
||||||
return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", "security key setting status");
|
return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.", "security key setting status");
|
||||||
case "missing_pam_support":
|
case "missing_pam_support":
|
||||||
return I18n.tr("Not available - install or configure pam_u2f", "lock screen security key setting");
|
return I18n.tr("Not available — install or configure pam_u2f.", "lock screen security key setting");
|
||||||
default:
|
default:
|
||||||
return I18n.tr("Security-key availability could not be confirmed", "security key setting status");
|
return I18n.tr("Security-key availability could not be confirmed.", "security key setting status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ Item {
|
|||||||
const warns = Array.isArray(data.warnings) ? data.warnings : [];
|
const warns = Array.isArray(data.warnings) ? data.warnings : [];
|
||||||
root.authValidateOk = true;
|
root.authValidateOk = true;
|
||||||
root.authValidateWarn = warns.length > 0;
|
root.authValidateWarn = warns.length > 0;
|
||||||
root.authValidateMessage = [I18n.tr("Authentication changes applied"), ...warns].join("\n");
|
root.authValidateMessage = [I18n.tr("Authentication changes applied."), ...warns].join("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ Item {
|
|||||||
const warns = Array.isArray(data.warnings) ? data.warnings : [];
|
const warns = Array.isArray(data.warnings) ? data.warnings : [];
|
||||||
root.u2fValidateOk = true;
|
root.u2fValidateOk = true;
|
||||||
root.u2fValidateWarn = warns.length > 0;
|
root.u2fValidateWarn = warns.length > 0;
|
||||||
root.u2fValidateMessage = [I18n.tr("Authentication changes applied"), ...warns].join("\n");
|
root.u2fValidateMessage = [I18n.tr("Authentication changes applied."), ...warns].join("\n");
|
||||||
root.refreshAuthDetection();
|
root.refreshAuthDetection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,7 +400,7 @@ Item {
|
|||||||
settingKey: "lockAuthSource"
|
settingKey: "lockAuthSource"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Authentication changes apply automatically")
|
text: I18n.tr("Authentication changes apply automatically.")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -484,7 +484,7 @@ Item {
|
|||||||
settingKey: "enableFprint"
|
settingKey: "enableFprint"
|
||||||
tags: ["lock", "screen", "fingerprint", "authentication", "biometric", "fprint"]
|
tags: ["lock", "screen", "fingerprint", "authentication", "biometric", "fprint"]
|
||||||
text: I18n.tr("Enable fingerprint authentication")
|
text: I18n.tr("Enable fingerprint authentication")
|
||||||
description: root.lockFprintControlledByPrimary ? I18n.tr("Managed by the primary PAM source", "factor managed by PAM source status") : root.lockFingerprintDescription()
|
description: root.lockFprintControlledByPrimary ? I18n.tr("Managed by the primary PAM source.", "factor managed by PAM source status") : root.lockFingerprintDescription()
|
||||||
descriptionColor: root.lockFprintControlledByPrimary || SettingsData.lockFingerprintReason === "ready" ? Theme.surfaceVariantText : Theme.warning
|
descriptionColor: root.lockFprintControlledByPrimary || SettingsData.lockFingerprintReason === "ready" ? Theme.surfaceVariantText : Theme.warning
|
||||||
checked: SettingsData.enableFprint || root.primaryPamHasFprint
|
checked: SettingsData.enableFprint || root.primaryPamHasFprint
|
||||||
enabled: root.lockFprintToggleAvailable && !root.lockFprintControlledByPrimary
|
enabled: root.lockFprintToggleAvailable && !root.lockFprintControlledByPrimary
|
||||||
@@ -495,7 +495,7 @@ Item {
|
|||||||
settingKey: "enableU2f"
|
settingKey: "enableU2f"
|
||||||
tags: ["lock", "screen", "u2f", "yubikey", "security", "key", "fido", "authentication", "hardware"]
|
tags: ["lock", "screen", "u2f", "yubikey", "security", "key", "fido", "authentication", "hardware"]
|
||||||
text: I18n.tr("Enable security key authentication", "Enable FIDO2/U2F hardware security key for lock screen")
|
text: I18n.tr("Enable security key authentication", "Enable FIDO2/U2F hardware security key for lock screen")
|
||||||
description: root.lockU2fControlledByPrimary ? I18n.tr("Managed by the primary PAM source", "factor managed by PAM source status") : root.lockU2fDescription()
|
description: root.lockU2fControlledByPrimary ? I18n.tr("Managed by the primary PAM source.", "factor managed by PAM source status") : root.lockU2fDescription()
|
||||||
descriptionColor: root.lockU2fControlledByPrimary || SettingsData.lockU2fReason === "ready" ? Theme.surfaceVariantText : Theme.warning
|
descriptionColor: root.lockU2fControlledByPrimary || SettingsData.lockU2fReason === "ready" ? Theme.surfaceVariantText : Theme.warning
|
||||||
checked: SettingsData.enableU2f || root.primaryPamHasU2f
|
checked: SettingsData.enableU2f || root.primaryPamHasU2f
|
||||||
enabled: root.lockU2fToggleAvailable && !root.lockU2fControlledByPrimary
|
enabled: root.lockU2fToggleAvailable && !root.lockU2fControlledByPrimary
|
||||||
|
|||||||
@@ -557,20 +557,19 @@ Item {
|
|||||||
return sectionId === "left" ? leftSection : sectionId === "center" ? centerSection : sectionId === "right" ? rightSection : null;
|
return sectionId === "left" ? leftSection : sectionId === "center" ? centerSection : sectionId === "right" ? rightSection : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id-based reorder; rebuilds from authoritative objects so every prop (incl. hideWhenIdle) survives
|
// Id-based reorder; rebuilds from authoritative objects so every prop (incl. hideWhenIdle) survives.
|
||||||
|
// Consumes one entry per occurrence so duplicate ids (e.g. two spacers) don't collapse, and
|
||||||
|
// appends unconsumed entries so nothing is silently dropped from the config array.
|
||||||
function reorderSection(sectionId, orderedIds) {
|
function reorderSection(sectionId, orderedIds) {
|
||||||
var current = getWidgetsForSection(sectionId);
|
var remaining = getWidgetsForSection(sectionId).slice();
|
||||||
var byId = {};
|
|
||||||
current.forEach(w => {
|
|
||||||
var id = (typeof w === "string" ? w : w.id);
|
|
||||||
byId[id] = w;
|
|
||||||
});
|
|
||||||
var reordered = [];
|
var reordered = [];
|
||||||
orderedIds.forEach(id => {
|
orderedIds.forEach(id => {
|
||||||
if (byId[id] !== undefined)
|
var idx = remaining.findIndex(w => (typeof w === "string" ? w : w.id) === id);
|
||||||
reordered.push(byId[id]);
|
if (idx < 0)
|
||||||
|
return;
|
||||||
|
reordered.push(remaining.splice(idx, 1)[0]);
|
||||||
});
|
});
|
||||||
setWidgetsForSection(sectionId, reordered);
|
setWidgetsForSection(sectionId, reordered.concat(remaining));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move a widget across sections (or within); committed as one atomic bar-config save
|
// Move a widget across sections (or within); committed as one atomic bar-config save
|
||||||
@@ -979,8 +978,16 @@ Item {
|
|||||||
var isString = typeof widget === "string";
|
var isString = typeof widget === "string";
|
||||||
var widgetId = isString ? widget : widget.id;
|
var widgetId = isString ? widget : widget.id;
|
||||||
var widgetDef = baseWidgetDefinitions.find(w => w.id === widgetId);
|
var widgetDef = baseWidgetDefinitions.find(w => w.id === widgetId);
|
||||||
if (!widgetDef)
|
if (!widgetDef) {
|
||||||
return;
|
// Skipping entries would desync row indices from the config array (issue #2844)
|
||||||
|
widgetDef = {
|
||||||
|
"id": widgetId,
|
||||||
|
"text": widgetId || I18n.tr("Unknown"),
|
||||||
|
"description": "",
|
||||||
|
"icon": "extension",
|
||||||
|
"warning": I18n.tr("Unavailable")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var item = Object.assign({}, widgetDef);
|
var item = Object.assign({}, widgetDef);
|
||||||
item.enabled = isString ? true : widget.enabled;
|
item.enabled = isString ? true : widget.enabled;
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
v1.5.1
|
v1.5.2
|
||||||
|
|||||||
@@ -4828,7 +4828,7 @@
|
|||||||
"security",
|
"security",
|
||||||
"source"
|
"source"
|
||||||
],
|
],
|
||||||
"description": "Managed by the primary PAM source"
|
"description": "Managed by the primary PAM source."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "loginctlLockIntegration",
|
"section": "loginctlLockIntegration",
|
||||||
@@ -4875,7 +4875,7 @@
|
|||||||
"u2f",
|
"u2f",
|
||||||
"yubikey"
|
"yubikey"
|
||||||
],
|
],
|
||||||
"description": "Managed by the primary PAM source"
|
"description": "Managed by the primary PAM source."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "lockLayout",
|
"section": "lockLayout",
|
||||||
@@ -7941,12 +7941,11 @@
|
|||||||
"managed",
|
"managed",
|
||||||
"pam",
|
"pam",
|
||||||
"removes",
|
"removes",
|
||||||
"services",
|
|
||||||
"stops",
|
"stops",
|
||||||
"write"
|
"writing"
|
||||||
],
|
],
|
||||||
"icon": "fingerprint",
|
"icon": "fingerprint",
|
||||||
"description": "DMS removes its managed block from /etc/pam.d/greetd and stops write services"
|
"description": "DMS removes its managed block from /etc/pam.d/greetd and stops writing to it"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "greeterAutoLogin",
|
"section": "greeterAutoLogin",
|
||||||
@@ -8014,7 +8013,7 @@
|
|||||||
"login",
|
"login",
|
||||||
"screen"
|
"screen"
|
||||||
],
|
],
|
||||||
"description": "Format the date on the login screen"
|
"description": "Greeter only — format for the date on the login screen"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "greeterDeps",
|
"section": "greeterDeps",
|
||||||
@@ -8160,12 +8159,11 @@
|
|||||||
"managed",
|
"managed",
|
||||||
"pam",
|
"pam",
|
||||||
"removes",
|
"removes",
|
||||||
"services",
|
|
||||||
"stops",
|
"stops",
|
||||||
"system",
|
"system",
|
||||||
"write"
|
"writing"
|
||||||
],
|
],
|
||||||
"description": "DMS removes its managed block from /etc/pam.d/greetd and stops write services"
|
"description": "DMS removes its managed block from /etc/pam.d/greetd and stops writing to it"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "muxType",
|
"section": "muxType",
|
||||||
|
|||||||
Reference in New Issue
Block a user