diff --git a/README.md b/README.md index 5782196..d1ca9e3 100644 --- a/README.md +++ b/README.md @@ -386,11 +386,14 @@ close · `SUPER+1..9` workspaces · `Print` region screenshot. logo/lock/bullet → text, entry/progress-box → surface, progress-bar → accent. Reads on light and dark; follows the theme as of the last system rebuild (like the background tint). -- **Hibernate double-unlock:** on resume from hibernate the LUKS +- ✓ **Hibernate double-unlock:** on resume from hibernate the LUKS passphrase already gates the machine, but hypridle's `before_sleep_cmd` - also locks hyprlock, so the user types a password twice. Lock only on - suspend (not hibernate), or skip the hyprlock prompt when resuming from - a LUKS-encrypted hibernate — see `modules/home/idle.nix`. + also locked hyprlock, so the user typed a password twice. Fixed with a + `nomarchy-hibernate-unlock` systemd unit (`modules/nixos/default.nix`) + that dismisses hyprlock *after* a hibernate resume (`WantedBy + hibernate.target`, `After systemd-hibernate.service` → runs post-resume), + gated on the disk being LUKS-encrypted. Suspend (and the RAM-resume phase + of suspend-then-hibernate) keep locking — they have no passphrase gate. - ✓ **Key agents & pinentry:** ships `modules/home/keys.nix` (`nomarchy.keys.enable`): one agent — `services.gpg-agent` with `enableSshSupport` fronts SSH, so a single `pinentry-qt` (native-Wayland, diff --git a/modules/home/idle.nix b/modules/home/idle.nix index db4b173..eaec51b 100644 --- a/modules/home/idle.nix +++ b/modules/home/idle.nix @@ -54,6 +54,10 @@ in settings = { general = { lock_cmd = "pidof hyprlock || hyprlock"; + # Locks before every sleep. For suspend that's exactly right; on an + # encrypted hibernate the LUKS resume already gates the machine, so + # the system side dismisses this lock post-resume to avoid a double + # unlock — see nomarchy-hibernate-unlock in modules/nixos/default.nix. before_sleep_cmd = "loginctl lock-session"; after_sleep_cmd = "hyprctl dispatch dpms on"; }; diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 0433e72..c24c95d 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -114,6 +114,26 @@ in services.upower.enable = lib.mkDefault true; networking.networkmanager.enable = lib.mkDefault true; + # No double-unlock on hibernate. hypridle locks hyprlock before every + # sleep (right for suspend), but a hibernate resume is already gated by + # the LUKS passphrase entered at boot — so the user would type a password + # twice. Once we're back from an *encrypted* hibernate, drop the now- + # redundant hyprlock. Ordered After the hibernate service, so it runs + # post-resume; pulled in only by hibernate.target (suspend, and the + # RAM-resume phase of suspend-then-hibernate, stay locked — they have no + # passphrase gate). Gated on LUKS: an unencrypted hibernate keeps its lock. + systemd.services.nomarchy-hibernate-unlock = + lib.mkIf (builtins.attrNames config.boot.initrd.luks.devices != [ ]) { + description = "Dismiss hyprlock after resuming from an encrypted hibernate"; + after = [ "systemd-hibernate.service" ]; + wantedBy = [ "hibernate.target" ]; + serviceConfig = { + Type = "oneshot"; + # `-`: a missing hyprlock (idle disabled, or not locked) isn't a failure. + ExecStart = "-${pkgs.procps}/bin/pkill -x hyprlock"; + }; + }; + # zsh as the default login shell (the desktop's shell experience — # starship/bat/eza/zoxide — is configured home-side in shell.nix). # programs.zsh.enable wires /etc/zshrc, completion and /etc/shells;