mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-15 18:22:08 -04:00
fix(lock/greeter): sync auth files with master
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.Greetd
|
|
||||||
import qs.Common
|
|
||||||
import qs.Modules.Greetd
|
import qs.Modules.Greetd
|
||||||
|
|
||||||
Scope {
|
Scope {
|
||||||
|
|||||||
@@ -225,7 +225,13 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
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
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText
|
color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,19 +230,19 @@ Item {
|
|||||||
|
|
||||||
function currentAuthMessage() {
|
function currentAuthMessage() {
|
||||||
if (GreeterState.pamState === "error")
|
if (GreeterState.pamState === "error")
|
||||||
return "Authentication error - try again";
|
return I18n.tr("Authentication error - try again");
|
||||||
if (GreeterState.pamState === "max")
|
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 (GreeterState.pamState === "fail") {
|
||||||
if (passwordAttemptLimitHint > 0) {
|
if (passwordAttemptLimitHint > 0) {
|
||||||
const attempt = Math.max(1, Math.min(passwordFailureCount, passwordAttemptLimitHint));
|
const attempt = Math.max(1, Math.min(passwordFailureCount, passwordAttemptLimitHint));
|
||||||
const remaining = Math.max(passwordAttemptLimitHint - attempt, 0);
|
const remaining = Math.max(passwordAttemptLimitHint - attempt, 0);
|
||||||
if (remaining > 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 "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -767,7 +767,7 @@ Item {
|
|||||||
|
|
||||||
property string fullTimeStr: {
|
property string fullTimeStr: {
|
||||||
const format = GreetdSettings.getEffectiveTimeFormat();
|
const format = GreetdSettings.getEffectiveTimeFormat();
|
||||||
return systemClock.date.toLocaleTimeString(Qt.locale(), format);
|
return systemClock.date.toLocaleTimeString(I18n.locale(), format);
|
||||||
}
|
}
|
||||||
property var timeParts: fullTimeStr.split(':')
|
property var timeParts: fullTimeStr.split(':')
|
||||||
property string hours: timeParts[0] || ""
|
property string hours: timeParts[0] || ""
|
||||||
@@ -876,7 +876,7 @@ Item {
|
|||||||
anchors.top: clockContainer.bottom
|
anchors.top: clockContainer.bottom
|
||||||
anchors.topMargin: 4
|
anchors.topMargin: 4
|
||||||
text: {
|
text: {
|
||||||
return systemClock.date.toLocaleDateString(Qt.locale(), GreetdSettings.getEffectiveLockDateFormat());
|
return systemClock.date.toLocaleDateString(I18n.locale(), GreetdSettings.getEffectiveLockDateFormat());
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeXLarge
|
font.pixelSize: Theme.fontSizeXLarge
|
||||||
color: "white"
|
color: "white"
|
||||||
@@ -1012,15 +1012,15 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: {
|
text: {
|
||||||
if (GreeterState.unlocking) {
|
if (GreeterState.unlocking) {
|
||||||
return "Logging in...";
|
return I18n.tr("Logging in...");
|
||||||
}
|
}
|
||||||
if (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse) {
|
if (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse) {
|
||||||
return "Authenticating...";
|
return I18n.tr("Authenticating...");
|
||||||
}
|
}
|
||||||
if (GreeterState.showPasswordInput) {
|
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
|
color: (GreeterState.unlocking || (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse)) ? Theme.primary : Theme.outline
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
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
|
- **Multi user**: Login with any system user
|
||||||
- **dms sync**: Sync settings with dms for consistent styling between shell and greeter
|
- **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`
|
- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/greetd`
|
||||||
- **Session Memory**: Remembers last selected session and user
|
- **Session Memory**: Remembers last selected session and user
|
||||||
- Can be disabled via `settings.json` keys: `greeterRememberLastSession` and `greeterRememberLastUser`
|
- 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:
|
5. Create greeter cache directory with proper permissions:
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /var/cache/dms-greeter
|
sudo mkdir -p /var/cache/dms-greeter
|
||||||
sudo chown greeter:greeter /var/cache/dms-greeter
|
sudo chown <greeter-user>:<greeter-group> /var/cache/dms-greeter
|
||||||
sudo chmod 750 /var/cache/dms-greeter
|
sudo chmod 2770 /var/cache/dms-greeter
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Edit or create `/etc/greetd/config.toml`:
|
6. Edit or create `/etc/greetd/config.toml`:
|
||||||
@@ -163,7 +163,7 @@ vt = 1
|
|||||||
|
|
||||||
[default_session]
|
[default_session]
|
||||||
user = "greeter"
|
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"
|
command = "/usr/local/bin/dms-greeter --command niri"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -238,9 +238,12 @@ DMS_RUN_GREETER=1 qs -p /path/to/dms
|
|||||||
|
|
||||||
#### Compositor
|
#### 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
|
#### 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`.
|
**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_DATA_HOME="$CACHE_DIR/.local/share"
|
||||||
export XDG_CACHE_HOME="$CACHE_DIR/.cache"
|
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.
|
# Keep greeter VT clean by default; callers can override via env or --debug.
|
||||||
if [[ -z "${RUST_LOG:-}" ]]; then
|
if [[ -z "${RUST_LOG:-}" ]]; then
|
||||||
|
|||||||
@@ -365,9 +365,9 @@ Item {
|
|||||||
visible: SettingsData.lockScreenShowDate
|
visible: SettingsData.lockScreenShowDate
|
||||||
text: {
|
text: {
|
||||||
if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) {
|
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
|
font.pixelSize: Theme.fontSizeXLarge
|
||||||
color: "white"
|
color: "white"
|
||||||
@@ -719,14 +719,24 @@ Item {
|
|||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
name: {
|
name: {
|
||||||
|
if (pam.u2fPending)
|
||||||
|
return "passkey";
|
||||||
if (pam.fprint.tries >= SettingsData.maxFprintTries)
|
if (pam.fprint.tries >= SettingsData.maxFprintTries)
|
||||||
return "fingerprint_off";
|
return "fingerprint_off";
|
||||||
if (pam.fprint.active)
|
if (pam.fprint.active)
|
||||||
return "fingerprint";
|
return "fingerprint";
|
||||||
|
if (pam.u2f.active)
|
||||||
|
return "passkey";
|
||||||
return "lock";
|
return "lock";
|
||||||
}
|
}
|
||||||
size: 20
|
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
|
opacity: pam.passwd.active ? 0 : 1
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
@@ -792,6 +802,11 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === Qt.Key_Escape) {
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
if (pam.u2fPending) {
|
||||||
|
pam.cancelU2fPending();
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,6 +871,11 @@ Item {
|
|||||||
if (root.unlocking) {
|
if (root.unlocking) {
|
||||||
return "Unlocking...";
|
return "Unlocking...";
|
||||||
}
|
}
|
||||||
|
if (pam.u2fPending) {
|
||||||
|
if (pam.u2fState === "insert")
|
||||||
|
return "Insert your security key...";
|
||||||
|
return "Touch your security key...";
|
||||||
|
}
|
||||||
if (pam.passwd.active) {
|
if (pam.passwd.active) {
|
||||||
return "Authenticating...";
|
return "Authenticating...";
|
||||||
}
|
}
|
||||||
@@ -930,7 +950,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
iconName: "keyboard"
|
iconName: "keyboard"
|
||||||
buttonSize: 32
|
buttonSize: 32
|
||||||
visible: !demoMode && !pam.passwd.active && !root.unlocking
|
visible: !demoMode && !pam.passwd.active && !root.unlocking && !pam.u2fPending
|
||||||
enabled: visible
|
enabled: visible
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (keyboardController.isKeyboardActive) {
|
if (keyboardController.isKeyboardActive) {
|
||||||
@@ -1031,7 +1051,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
iconName: "keyboard_return"
|
iconName: "keyboard_return"
|
||||||
buttonSize: 36
|
buttonSize: 36
|
||||||
visible: (demoMode || (!pam.passwd.active && !root.unlocking))
|
visible: (demoMode || (!pam.passwd.active && !root.unlocking && !pam.u2fPending))
|
||||||
enabled: !demoMode
|
enabled: !demoMode
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!demoMode && !root.unlocking && !pam.u2fPending) {
|
if (!demoMode && !root.unlocking && !pam.u2fPending) {
|
||||||
@@ -1637,6 +1657,14 @@ Item {
|
|||||||
root.passwordBuffer = "";
|
root.passwordBuffer = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onU2fPendingChanged: {
|
||||||
|
if (u2fPending) {
|
||||||
|
passwordField.text = "";
|
||||||
|
root.passwordBuffer = "";
|
||||||
|
if (keyboardController.isKeyboardActive)
|
||||||
|
keyboardController.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ Scope {
|
|||||||
|
|
||||||
readonly property alias passwd: passwd
|
readonly property alias passwd: passwd
|
||||||
readonly property alias fprint: fprint
|
readonly property alias fprint: fprint
|
||||||
|
readonly property alias u2f: u2f
|
||||||
property string lockMessage
|
property string lockMessage
|
||||||
property string state
|
property string state
|
||||||
property string fprintState
|
property string fprintState
|
||||||
|
property string u2fState
|
||||||
|
property bool u2fPending: false
|
||||||
property string buffer
|
property string buffer
|
||||||
|
|
||||||
signal flashMsg
|
signal flashMsg
|
||||||
@@ -127,9 +130,8 @@ Scope {
|
|||||||
onCompleted: res => {
|
onCompleted: res => {
|
||||||
if (res === PamResult.Success) {
|
if (res === PamResult.Success) {
|
||||||
if (!root.unlockInProgress) {
|
if (!root.unlockInProgress) {
|
||||||
root.unlockInProgress = true;
|
|
||||||
fprint.abort();
|
fprint.abort();
|
||||||
root.unlockRequested();
|
root.proceedAfterPrimaryAuth();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -192,9 +194,8 @@ Scope {
|
|||||||
|
|
||||||
if (res === PamResult.Success) {
|
if (res === PamResult.Success) {
|
||||||
if (!root.unlockInProgress) {
|
if (!root.unlockInProgress) {
|
||||||
root.unlockInProgress = true;
|
|
||||||
passwd.abort();
|
passwd.abort();
|
||||||
root.unlockRequested();
|
root.proceedAfterPrimaryAuth();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -356,6 +357,8 @@ Scope {
|
|||||||
SettingsData.refreshAuthAvailability();
|
SettingsData.refreshAuthAvailability();
|
||||||
root.state = "";
|
root.state = "";
|
||||||
root.fprintState = "";
|
root.fprintState = "";
|
||||||
|
root.u2fState = "";
|
||||||
|
root.u2fPending = false;
|
||||||
root.lockMessage = "";
|
root.lockMessage = "";
|
||||||
root.resetAuthFlows();
|
root.resetAuthFlows();
|
||||||
fprint.checkAvail();
|
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