Skip to content

Commit 8a0e1b2

Browse files
author
guttermonk
committed
Added a nix module and systemd for improved statefulness.
1 parent 49f1e12 commit 8a0e1b2

File tree

4 files changed

+286
-28
lines changed

4 files changed

+286
-28
lines changed

readme.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,47 @@ This Waybar module is intended to be used with hardware like the following (ref
1414
- [usbutils](http://www.linux-usb.org/) needed to run `lsusb`
1515

1616
## Installation Instructions
17+
18+
### Option 1: NixOS with Home Manager (Recommended for NixOS users)
19+
20+
For NixOS users with Home Manager, you can use the included NixOS module for automatic systemd service management:
21+
22+
1. Import the module in your Home Manager configuration:
23+
```nix
24+
{ config, pkgs, ... }:
25+
{
26+
imports = [
27+
/path/to/yubilock/yubilock.nix
28+
];
29+
30+
services.yubilock = {
31+
enable = true;
32+
autoRestore = true; # Automatically restore yubilock state on login
33+
};
34+
}
35+
```
36+
37+
2. Copy the Waybar scripts to `~/.config/waybar/scripts/`:
38+
```bash
39+
mkdir -p ~/.config/waybar/scripts/
40+
cp scripts/*.sh ~/.config/waybar/scripts/
41+
chmod +x ~/.config/waybar/scripts/*.sh
42+
```
43+
44+
3. Add the custom module to your Waybar config (see [Waybar Configuration](#part-3-waybar-configuration)).
45+
46+
4. Add the CSS to your Waybar style.css (see [Waybar CSS Style](#part-4-waybar-css-style)).
47+
48+
5. Rebuild your NixOS configuration:
49+
```bash
50+
home-manager switch
51+
```
52+
53+
The systemd services will be automatically configured:
54+
- `yubilock.service` - Monitors YubiKey presence and locks screen on removal
55+
- `yubilock-restore.service` - Restores yubilock state on login (if `autoRestore = true`)
56+
57+
### Option 2: Manual Installation (All Linux distributions)
1758
1. Save the three scripts to: `~/.config/waybar/scripts/`
1859
2. Make them executable:
1960
```

scripts/yubilock-restore.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
3+
STATE_FILE="$HOME/.cache/yubilock-state"
4+
LOG_FILE="$HOME/.cache/yubilock-restore.log"
5+
6+
echo "[$(date)] Checking yubilock state on login" >> "$LOG_FILE"
7+
8+
# Create state file if it doesn't exist
9+
if [ ! -f "$STATE_FILE" ]; then
10+
echo "off" > "$STATE_FILE"
11+
echo "[$(date)] No state file found, defaulting to off" >> "$LOG_FILE"
12+
exit 0
13+
fi
14+
15+
# Read the saved state
16+
saved_state=$(cat "$STATE_FILE")
17+
echo "[$(date)] Saved state: $saved_state" >> "$LOG_FILE"
18+
19+
# If it was enabled before, re-enable it
20+
if [ "$saved_state" = "on" ]; then
21+
if ! systemctl --user is-active yubilock.service > /dev/null 2>&1; then
22+
echo "[$(date)] Restoring yubilock service" >> "$LOG_FILE"
23+
systemctl --user start yubilock.service
24+
echo "[$(date)] Yubilock service restored" >> "$LOG_FILE"
25+
else
26+
echo "[$(date)] Yubilock service already running" >> "$LOG_FILE"
27+
fi
28+
fi

scripts/yubilock.sh

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,36 @@
11
#!/usr/bin/env bash
22

3+
PID_FILE="$HOME/.cache/yubilock.pid"
34
STATE_FILE="$HOME/.cache/yubilock-state"
45
LOG_FILE="$HOME/.cache/yubilock.log"
5-
PID_FILE="$HOME/.cache/yubilock.pid"
6+
### UPDATE THE LOCKSCREEN FUNCTION BELOW WITH YOUR PREFERRED SCREEN LOCKING COMMAND
7+
8+
# Log startup
9+
echo "[$(date)] Yubilock starting with PID $$" >> "$LOG_FILE"
10+
11+
# Create state file if it doesn't exist, but preserve existing state
12+
if [ ! -f "$STATE_FILE" ]; then
13+
echo "off" > "$STATE_FILE"
14+
echo "[$(date)] No state file found, defaulting to off" >> "$LOG_FILE"
15+
else
16+
echo "[$(date)] Using existing state: $(cat "$STATE_FILE")" >> "$LOG_FILE"
17+
fi
18+
19+
# Write PID to file
20+
echo $$ > "$PID_FILE"
21+
echo "[$(date)] PID file written, state: $(cat "$STATE_FILE")" >> "$LOG_FILE"
22+
23+
# Function to clean up on exit
24+
cleanup() {
25+
echo "[$(date)] Cleanup triggered" >> "$LOG_FILE"
26+
rm -f "$PID_FILE"
27+
# Don't modify state file - preserve it across reboots
28+
pkill -SIGRTMIN+5 waybar 2>/dev/null
29+
exit 0
30+
}
31+
32+
# Set up signal handlers
33+
trap cleanup EXIT TERM INT
634

735
# Function to check if a YubiKey is currently plugged in
836
check_yubikey() {
@@ -13,55 +41,56 @@ check_yubikey() {
1341
fi
1442
}
1543

16-
# Function to lock the screen
44+
### Function to lock the screen
45+
### You can replace this with your preferred screen locking command
46+
### Examples:
47+
### gnome-screensaver-command -l # For GNOME
48+
### loginctl lock-session # systemd-based systems
49+
### xscreensaver-command -lock # For xscreensaver
50+
### i3lock # For i3
1751
lock_screen() {
18-
# You can replace this with your preferred screen locking command
19-
# Examples:
20-
# gnome-screensaver-command -l # For GNOME
21-
# loginctl lock-session # systemd-based systems
22-
# xscreensaver-command -lock # For xscreensaver
23-
# i3lock # For i3
24-
2552
lockscreen
26-
echo "Screen locked at $(date)" >> "$LOG_FILE"
53+
echo "Screen locked at $(date)"
2754
}
2855

29-
# Create state file if it doesn't exist
30-
if [ ! -f "$STATE_FILE" ]; then
31-
echo "off" > "$STATE_FILE"
32-
fi
33-
34-
# Record PID for later termination
35-
echo "$$" > "$PID_FILE"
36-
3756
# Main monitoring loop
38-
echo "YubiKey monitoring started at $(date)" >> "$LOG_FILE"
57+
echo "[$(date)] YubiKey monitoring started" >> "$LOG_FILE"
58+
echo "YubiKey monitoring started at $(date)"
59+
60+
# Signal waybar to update
61+
pkill -SIGRTMIN+5 waybar 2>/dev/null
3962

4063
while true; do
41-
# Check if monitoring is still enabled
64+
# Check if monitoring is enabled
4265
if [ "$(cat "$STATE_FILE")" != "on" ]; then
43-
echo "YubiKey monitoring stopped at $(date)" >> "$LOG_FILE"
44-
exit 0
66+
# Monitoring is paused, wait and check again
67+
echo "[$(date)] YubiKey monitoring paused (state: off)" >> "$LOG_FILE"
68+
sleep 5
69+
continue
4570
fi
4671

72+
# Only monitor when state is "on"
4773
if check_yubikey; then
48-
echo "YubiKey detected at $(date)" >> "$LOG_FILE"
74+
echo "[$(date)] YubiKey detected" >> "$LOG_FILE"
75+
echo "YubiKey detected at $(date)"
4976

5077
# Wait until the YubiKey is removed
5178
while check_yubikey && [ "$(cat "$STATE_FILE")" = "on" ]; do
5279
sleep 1
5380
done
5481

55-
# If we exited because service was disabled, exit gracefully
82+
# If we exited because service was disabled, continue the loop
5683
if [ "$(cat "$STATE_FILE")" != "on" ]; then
57-
echo "YubiKey monitoring stopped at $(date)" >> "$LOG_FILE"
58-
exit 0
84+
echo "[$(date)] YubiKey monitoring paused" >> "$LOG_FILE"
85+
continue
5986
fi
6087

61-
echo "YubiKey removed at $(date)" >> "$LOG_FILE"
88+
echo "[$(date)] YubiKey removed - locking screen" >> "$LOG_FILE"
89+
echo "YubiKey removed at $(date)"
6290
lock_screen
6391
else
64-
echo "No YubiKey detected. Checking again in 10 seconds..." >> "$LOG_FILE"
92+
echo "[$(date)] No YubiKey detected. Checking again..." >> "$LOG_FILE"
93+
echo "No YubiKey detected. Checking again in 10 seconds..."
6594
# Check less frequently to reduce system load
6695
sleep 10
6796
fi

yubilock.nix

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
{ config, lib, pkgs, ... }:
2+
3+
with lib;
4+
5+
let
6+
cfg = config.services.yubilock;
7+
8+
# Script paths - users should copy scripts to their ~/.config/waybar/scripts/
9+
yubilockScript = pkgs.writeShellScript "yubilock" ''
10+
STATE_FILE="$HOME/.cache/yubilock-state"
11+
LOG_FILE="$HOME/.cache/yubilock.log"
12+
PID_FILE="$HOME/.cache/yubilock.pid"
13+
14+
# Function to check if a YubiKey is currently plugged in
15+
check_yubikey() {
16+
if ${pkgs.usbutils}/bin/lsusb | ${pkgs.gnugrep}/bin/grep -i "yubikey" > /dev/null; then
17+
return 0 # device is present
18+
else
19+
return 1 # device is not present
20+
fi
21+
}
22+
23+
# Function to lock the screen
24+
lock_screen() {
25+
# Using loginctl for systemd-based systems
26+
${pkgs.systemd}/bin/loginctl lock-session
27+
echo "Screen locked at $(date)" >> "$LOG_FILE"
28+
}
29+
30+
# Create state file if it doesn't exist
31+
if [ ! -f "$STATE_FILE" ]; then
32+
echo "off" > "$STATE_FILE"
33+
fi
34+
35+
# Record PID for later termination
36+
echo "$$" > "$PID_FILE"
37+
38+
# Main monitoring loop
39+
echo "YubiKey monitoring started at $(date)" >> "$LOG_FILE"
40+
41+
while true; do
42+
# Check if monitoring is still enabled
43+
if [ "$(cat "$STATE_FILE")" != "on" ]; then
44+
echo "YubiKey monitoring stopped at $(date)" >> "$LOG_FILE"
45+
exit 0
46+
fi
47+
48+
if check_yubikey; then
49+
echo "YubiKey detected at $(date)" >> "$LOG_FILE"
50+
51+
# Wait until the YubiKey is removed
52+
while check_yubikey && [ "$(cat "$STATE_FILE")" = "on" ]; do
53+
sleep 1
54+
done
55+
56+
# If we exited because service was disabled, exit gracefully
57+
if [ "$(cat "$STATE_FILE")" != "on" ]; then
58+
echo "YubiKey monitoring stopped at $(date)" >> "$LOG_FILE"
59+
exit 0
60+
fi
61+
62+
echo "YubiKey removed at $(date)" >> "$LOG_FILE"
63+
lock_screen
64+
else
65+
echo "No YubiKey detected. Checking again in 10 seconds..." >> "$LOG_FILE"
66+
# Check less frequently to reduce system load
67+
sleep 10
68+
fi
69+
done
70+
'';
71+
72+
yubilockRestoreScript = pkgs.writeShellScript "yubilock-restore" ''
73+
STATE_FILE="$HOME/.cache/yubilock-state"
74+
LOG_FILE="$HOME/.cache/yubilock-restore.log"
75+
76+
echo "[$(date)] Checking yubilock state on login" >> "$LOG_FILE"
77+
78+
# Create state file if it doesn't exist
79+
if [ ! -f "$STATE_FILE" ]; then
80+
echo "off" > "$STATE_FILE"
81+
echo "[$(date)] No state file found, defaulting to off" >> "$LOG_FILE"
82+
exit 0
83+
fi
84+
85+
# Read the saved state
86+
saved_state=$(cat "$STATE_FILE")
87+
echo "[$(date)] Saved state: $saved_state" >> "$LOG_FILE"
88+
89+
# If it was enabled before, re-enable it
90+
if [ "$saved_state" = "on" ]; then
91+
if ! ${pkgs.systemd}/bin/systemctl --user is-active yubilock.service > /dev/null 2>&1; then
92+
echo "[$(date)] Restoring yubilock service" >> "$LOG_FILE"
93+
${pkgs.systemd}/bin/systemctl --user start yubilock.service
94+
echo "[$(date)] Yubilock service restored" >> "$LOG_FILE"
95+
else
96+
echo "[$(date)] Yubilock service already running" >> "$LOG_FILE"
97+
fi
98+
fi
99+
'';
100+
101+
in {
102+
options.services.yubilock = {
103+
enable = mkEnableOption "YubiKey screen lock monitor";
104+
105+
autoRestore = mkOption {
106+
type = types.bool;
107+
default = true;
108+
description = ''
109+
Automatically restore yubilock state on login.
110+
If enabled, the yubilock service will be restarted on login
111+
if it was running when you last logged out.
112+
'';
113+
};
114+
};
115+
116+
config = mkIf cfg.enable {
117+
# Systemd user service for yubilock
118+
systemd.user.services.yubilock = {
119+
Unit = {
120+
Description = "YubiKey lock screen monitor";
121+
After = [ "graphical-session.target" ];
122+
PartOf = [ "graphical-session.target" ];
123+
};
124+
Service = {
125+
Type = "simple";
126+
ExecStart = "${yubilockScript}";
127+
Restart = "on-failure";
128+
RestartSec = "5s";
129+
# Ensure state persists
130+
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p %h/.cache";
131+
# Clean state on stop
132+
ExecStopPost = "${pkgs.bash}/bin/bash -c 'echo off > %h/.cache/yubilock-state'";
133+
};
134+
Install = {
135+
WantedBy = [ "graphical-session.target" ];
136+
};
137+
};
138+
139+
# Systemd user service to restore yubilock state on login
140+
systemd.user.services.yubilock-restore = mkIf cfg.autoRestore {
141+
Unit = {
142+
Description = "Restore YubiKey monitor state on login";
143+
After = [ "graphical-session.target" ];
144+
};
145+
Service = {
146+
Type = "oneshot";
147+
ExecStart = "${yubilockRestoreScript}";
148+
RemainAfterExit = false;
149+
};
150+
Install = {
151+
WantedBy = [ "graphical-session.target" ];
152+
};
153+
};
154+
155+
# Ensure required packages are available
156+
home.packages = with pkgs; [
157+
usbutils # for lsusb command
158+
];
159+
};
160+
}

0 commit comments

Comments
 (0)