mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
fix(lock/greeter): sync auth files with master
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.Greetd
|
||||
import qs.Common
|
||||
import qs.Modules.Greetd
|
||||
|
||||
Scope {
|
||||
|
||||
@@ -225,7 +225,13 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.errorCount > 0 ? I18n.tr("%1 issue(s) found", "greeter doctor page error count").arg(root.errorCount) : I18n.tr("All checks passed", "greeter doctor page success")
|
||||
text: {
|
||||
if (root.errorCount === 0)
|
||||
return I18n.tr("All checks passed", "greeter doctor page success");
|
||||
return root.errorCount === 1
|
||||
? I18n.tr("%1 issue found", "greeter doctor page error count").arg(root.errorCount)
|
||||
: I18n.tr("%1 issues found", "greeter doctor page error count").arg(root.errorCount);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
@@ -230,19 +230,19 @@ Item {
|
||||
|
||||
function currentAuthMessage() {
|
||||
if (GreeterState.pamState === "error")
|
||||
return "Authentication error - try again";
|
||||
return I18n.tr("Authentication error - try again");
|
||||
if (GreeterState.pamState === "max")
|
||||
return "Too many failed attempts - account may be locked";
|
||||
return I18n.tr("Too many failed attempts - account may be locked");
|
||||
if (GreeterState.pamState === "fail") {
|
||||
if (passwordAttemptLimitHint > 0) {
|
||||
const attempt = Math.max(1, Math.min(passwordFailureCount, passwordAttemptLimitHint));
|
||||
const remaining = Math.max(passwordAttemptLimitHint - attempt, 0);
|
||||
if (remaining > 0) {
|
||||
return "Incorrect password - attempt " + attempt + " of " + passwordAttemptLimitHint + " (lockout may follow)";
|
||||
return I18n.tr("Incorrect password - attempt %1 of %2 (lockout may follow)").arg(attempt).arg(passwordAttemptLimitHint);
|
||||
}
|
||||
return "Incorrect password - next failures may trigger account lockout";
|
||||
return I18n.tr("Incorrect password - next failures may trigger account lockout");
|
||||
}
|
||||
return "Incorrect password";
|
||||
return I18n.tr("Incorrect password");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -767,7 +767,7 @@ Item {
|
||||
|
||||
property string fullTimeStr: {
|
||||
const format = GreetdSettings.getEffectiveTimeFormat();
|
||||
return systemClock.date.toLocaleTimeString(Qt.locale(), format);
|
||||
return systemClock.date.toLocaleTimeString(I18n.locale(), format);
|
||||
}
|
||||
property var timeParts: fullTimeStr.split(':')
|
||||
property string hours: timeParts[0] || ""
|
||||
@@ -876,7 +876,7 @@ Item {
|
||||
anchors.top: clockContainer.bottom
|
||||
anchors.topMargin: 4
|
||||
text: {
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), GreetdSettings.getEffectiveLockDateFormat());
|
||||
return systemClock.date.toLocaleDateString(I18n.locale(), GreetdSettings.getEffectiveLockDateFormat());
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeXLarge
|
||||
color: "white"
|
||||
@@ -1012,15 +1012,15 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: {
|
||||
if (GreeterState.unlocking) {
|
||||
return "Logging in...";
|
||||
return I18n.tr("Logging in...");
|
||||
}
|
||||
if (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse) {
|
||||
return "Authenticating...";
|
||||
return I18n.tr("Authenticating...");
|
||||
}
|
||||
if (GreeterState.showPasswordInput) {
|
||||
return "Password...";
|
||||
return I18n.tr("Password...");
|
||||
}
|
||||
return "Username...";
|
||||
return I18n.tr("Username...");
|
||||
}
|
||||
color: (GreeterState.unlocking || (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse)) ? Theme.primary : Theme.outline
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
|
||||
@@ -6,7 +6,7 @@ A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the
|
||||
|
||||
- **Multi user**: Login with any system user
|
||||
- **dms sync**: Sync settings with dms for consistent styling between shell and greeter
|
||||
- **Multiple compositors**: Supports niri, Hyprland, Sway, or mangowc.
|
||||
- **Multiple compositors**: The `dms-greeter` wrapper supports niri, Hyprland, sway, scroll, miracle-wm, labwc, and mangowc.
|
||||
- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/greetd`
|
||||
- **Session Memory**: Remembers last selected session and user
|
||||
- Can be disabled via `settings.json` keys: `greeterRememberLastSession` and `greeterRememberLastUser`
|
||||
@@ -152,8 +152,8 @@ sudo chmod +x /usr/local/bin/dms-greeter
|
||||
5. Create greeter cache directory with proper permissions:
|
||||
```bash
|
||||
sudo mkdir -p /var/cache/dms-greeter
|
||||
sudo chown greeter:greeter /var/cache/dms-greeter
|
||||
sudo chmod 750 /var/cache/dms-greeter
|
||||
sudo chown <greeter-user>:<greeter-group> /var/cache/dms-greeter
|
||||
sudo chmod 2770 /var/cache/dms-greeter
|
||||
```
|
||||
|
||||
6. Edit or create `/etc/greetd/config.toml`:
|
||||
@@ -163,7 +163,7 @@ vt = 1
|
||||
|
||||
[default_session]
|
||||
user = "greeter"
|
||||
# Change compositor to sway, hyprland, or mangowc if preferred
|
||||
# Change compositor to another wrapper-supported compositor if preferred
|
||||
command = "/usr/local/bin/dms-greeter --command niri"
|
||||
```
|
||||
|
||||
@@ -238,9 +238,12 @@ DMS_RUN_GREETER=1 qs -p /path/to/dms
|
||||
|
||||
#### Compositor
|
||||
|
||||
You can configure compositor specific settings such as outputs/displays the same as you would in niri or Hyprland.
|
||||
For current wrapper-based installs, the `dms-greeter` wrapper supports niri, hyprland, sway, scroll, miracle-wm, labwc, and mangowc.
|
||||
|
||||
Simply edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` to change compositor settings for the greeter
|
||||
Only niri currently has a generated greeter config path managed by `dms greeter sync`.
|
||||
|
||||
- niri: `dms greeter sync` writes the generated greeter config to `/etc/greetd/niri/config.kdl`. Add local manual tweaks in `/etc/greetd/niri_overrides.kdl`.
|
||||
- Other wrapper-supported compositors use the wrapper-generated config by default. If you need a custom compositor config, add `-C /path/to/config` to the `dms-greeter` command in `/etc/greetd/config.toml`.
|
||||
|
||||
#### Personalization
|
||||
|
||||
@@ -271,4 +274,4 @@ sudo ln -sf ~/.cache/DankMaterialShell/dms-colors.json /var/cache/dms-greeter/co
|
||||
|
||||
**Advanced:** You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable or the `--cache-dir` flag when using `dms-greeter`. The default is `/var/cache/dms-greeter`.
|
||||
|
||||
The cache directory should be owned by `greeter:greeter` with `770` permissions.
|
||||
The cache directory should be owned by `<greeter-user>:<greeter-group>` with `2770` permissions. If the greeter user is not available yet, DMS falls back to `root:<greeter-group>`.
|
||||
|
||||
@@ -214,18 +214,6 @@ export XDG_STATE_HOME="$CACHE_DIR/.local/state"
|
||||
export XDG_DATA_HOME="$CACHE_DIR/.local/share"
|
||||
export XDG_CACHE_HOME="$CACHE_DIR/.cache"
|
||||
|
||||
# Propagate correct XDG dirs into the systemd user session so socket-activated
|
||||
# services (e.g. wireplumber) don't inherit HOME=/ from /etc/passwd.
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl --user set-environment \
|
||||
HOME="$CACHE_DIR" \
|
||||
XDG_STATE_HOME="$CACHE_DIR/.local/state" \
|
||||
XDG_DATA_HOME="$CACHE_DIR/.local/share" \
|
||||
XDG_CACHE_HOME="$CACHE_DIR/.cache" 2>/dev/null || true
|
||||
if systemctl --user is-active --quiet wireplumber.service 2>/dev/null; then
|
||||
systemctl --user restart wireplumber.service 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Keep greeter VT clean by default; callers can override via env or --debug.
|
||||
if [[ -z "${RUST_LOG:-}" ]]; then
|
||||
|
||||
@@ -365,9 +365,9 @@ Item {
|
||||
visible: SettingsData.lockScreenShowDate
|
||||
text: {
|
||||
if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) {
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat);
|
||||
return systemClock.date.toLocaleDateString(I18n.locale(), SettingsData.lockDateFormat);
|
||||
}
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), Locale.LongFormat);
|
||||
return systemClock.date.toLocaleDateString(I18n.locale(), Locale.LongFormat);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeXLarge
|
||||
color: "white"
|
||||
@@ -719,14 +719,24 @@ Item {
|
||||
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
if (pam.u2fPending)
|
||||
return "passkey";
|
||||
if (pam.fprint.tries >= SettingsData.maxFprintTries)
|
||||
return "fingerprint_off";
|
||||
if (pam.fprint.active)
|
||||
return "fingerprint";
|
||||
if (pam.u2f.active)
|
||||
return "passkey";
|
||||
return "lock";
|
||||
}
|
||||
size: 20
|
||||
color: pam.fprint.tries >= SettingsData.maxFprintTries ? Theme.error : (passwordField.activeFocus ? Theme.primary : Theme.surfaceVariantText)
|
||||
color: {
|
||||
if (pam.fprint.tries >= SettingsData.maxFprintTries)
|
||||
return Theme.error;
|
||||
if (pam.u2fState !== "")
|
||||
return Theme.tertiary;
|
||||
return passwordField.activeFocus ? Theme.primary : Theme.surfaceVariantText;
|
||||
}
|
||||
opacity: pam.passwd.active ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -792,6 +802,11 @@ Item {
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
if (pam.u2fPending) {
|
||||
pam.cancelU2fPending();
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
@@ -856,6 +871,11 @@ Item {
|
||||
if (root.unlocking) {
|
||||
return "Unlocking...";
|
||||
}
|
||||
if (pam.u2fPending) {
|
||||
if (pam.u2fState === "insert")
|
||||
return "Insert your security key...";
|
||||
return "Touch your security key...";
|
||||
}
|
||||
if (pam.passwd.active) {
|
||||
return "Authenticating...";
|
||||
}
|
||||
@@ -930,7 +950,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: "keyboard"
|
||||
buttonSize: 32
|
||||
visible: !demoMode && !pam.passwd.active && !root.unlocking
|
||||
visible: !demoMode && !pam.passwd.active && !root.unlocking && !pam.u2fPending
|
||||
enabled: visible
|
||||
onClicked: {
|
||||
if (keyboardController.isKeyboardActive) {
|
||||
@@ -1031,7 +1051,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: "keyboard_return"
|
||||
buttonSize: 36
|
||||
visible: (demoMode || (!pam.passwd.active && !root.unlocking))
|
||||
visible: (demoMode || (!pam.passwd.active && !root.unlocking && !pam.u2fPending))
|
||||
enabled: !demoMode
|
||||
onClicked: {
|
||||
if (!demoMode && !root.unlocking && !pam.u2fPending) {
|
||||
@@ -1637,6 +1657,14 @@ Item {
|
||||
root.passwordBuffer = "";
|
||||
}
|
||||
}
|
||||
onU2fPendingChanged: {
|
||||
if (u2fPending) {
|
||||
passwordField.text = "";
|
||||
root.passwordBuffer = "";
|
||||
if (keyboardController.isKeyboardActive)
|
||||
keyboardController.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -14,9 +14,12 @@ Scope {
|
||||
|
||||
readonly property alias passwd: passwd
|
||||
readonly property alias fprint: fprint
|
||||
readonly property alias u2f: u2f
|
||||
property string lockMessage
|
||||
property string state
|
||||
property string fprintState
|
||||
property string u2fState
|
||||
property bool u2fPending: false
|
||||
property string buffer
|
||||
|
||||
signal flashMsg
|
||||
@@ -127,9 +130,8 @@ Scope {
|
||||
onCompleted: res => {
|
||||
if (res === PamResult.Success) {
|
||||
if (!root.unlockInProgress) {
|
||||
root.unlockInProgress = true;
|
||||
fprint.abort();
|
||||
root.unlockRequested();
|
||||
root.proceedAfterPrimaryAuth();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -192,9 +194,8 @@ Scope {
|
||||
|
||||
if (res === PamResult.Success) {
|
||||
if (!root.unlockInProgress) {
|
||||
root.unlockInProgress = true;
|
||||
passwd.abort();
|
||||
root.unlockRequested();
|
||||
root.proceedAfterPrimaryAuth();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -356,6 +357,8 @@ Scope {
|
||||
SettingsData.refreshAuthAvailability();
|
||||
root.state = "";
|
||||
root.fprintState = "";
|
||||
root.u2fState = "";
|
||||
root.u2fPending = false;
|
||||
root.lockMessage = "";
|
||||
root.resetAuthFlows();
|
||||
fprint.checkAvail();
|
||||
|
||||
3
quickshell/assets/pam/u2f
Normal file
3
quickshell/assets/pam/u2f
Normal file
@@ -0,0 +1,3 @@
|
||||
#%PAM-1.0
|
||||
|
||||
auth required pam_u2f.so cue nouserok timeout=10
|
||||
Reference in New Issue
Block a user