Files
2026-07-26 21:19:04 +02:00

6.1 KiB
Raw Permalink Blame History

att_lock

An Android-style 4×4 dot pattern screen locker for wlroots-based Wayland compositors (Sway, Hyprland, river, labwc, …). It uses the secure ext-session-lock-v1 protocol, verifies the drawn pattern against a salted hash stored in an XDG-compliant directory, and falls back to PAM password authentication.

Features

  • 4×4 dot grid, drawn by dragging with a pointer or touch — including Android's rule that intermediate dots on a straight line get captured.
  • Rotation / any aspect ratio: the grid is a centred square sized from the compositor-provided surface dimensions, so portrait, landscape and rotated outputs all just work. HiDPI (integer wl_output scale) is honoured.
  • First-run setup: with no stored pattern (or --setup) you draw the pattern twice to confirm it. It is stored as a salted yescrypt hash (falling back to sha512crypt) at $XDG_DATA_HOME/att_lock/pattern.hash (mode 0600), never in plaintext. The hash uses cost factor 9 (~0.22 s per attempt) and covers your username as well as the pattern, so the same pattern on two accounts produces unrelated hashes.
  • PAM password fallback: start typing at the unlock screen to switch to a password field authenticated through PAM (for "forgot pattern").
  • Background image via a command-line argument (PNG), scaled to cover.
  • Secure by construction: if the process dies while locked, the compositor keeps the session locked (a guarantee of ext-session-lock-v1).

Build

The build system is Nix flakes.

# One-off build:
nix build            # -> ./result/bin/att_lock

# Or a dev shell + meson:
nix develop
meson setup build
ninja -C build       # -> ./build/att_lock

Dependencies (provided by the flake): wayland, wayland-scanner, cairo, libxkbcommon, pam (linux-pam), libxcrypt, plus meson/ninja/pkg-config.

Usage

att_lock [options] [IMAGE]

  -i, --image PATH        Background image (PNG); also accepted positionally
  -p, --pam-service NAME  PAM service for the password fallback (default: login)
  -m, --min-dots N        Minimum dots in a pattern (default: 4)
      --setup             Force (re)creation of the stored pattern
  -h, --help              Show help

Examples:

att_lock ~/wallpaper.png            # lock with a background
att_lock --setup                    # re-record the pattern, then unlock
att_lock -p att_lock -i bg.png     # use a dedicated PAM service

Unlocking

  • Draw your pattern (≥ --min-dots dots) and release to unlock.
  • Type any character to switch to the password field; press Enter to authenticate via PAM, Esc to go back to the pattern.

After 4 failed attempts, further attempts are locked out for an escalating delay — 15 s, then 30 s, 60 s, 120 s, 240 s, capped at 5 minutes — with the remaining time shown on screen. The counter is shared between the pattern and the password field, so switching to the password does not sidestep an active lockout, and it is held in memory only (there is no way to restart the locker to clear it, since the compositor keeps the session locked regardless). The countdown uses a monotonic clock, so it cannot be skipped by changing the system time or by suspending the machine.

PAM configuration

The password fallback authenticates through PAM using the service named by --pam-service (default login, which exists on most systems). For a dedicated service, create one that stacks pam_unix:

NixOS (configuration.nix):

security.pam.services.att_lock = {};   # inherits sane defaults (pam_unix)

then run att_lock --pam-service att_lock.

Other distros (/etc/pam.d/att_lock):

auth     include  login
account  include  login

The pattern itself is not checked by PAM — it is verified against the local salted hash. PAM only backs the password fallback.

Wiring it into your compositor

Use it as your lock command, e.g. with swayidle:

swayidle -w \
  timeout 300 'att_lock ~/wallpaper.png' \
  before-sleep 'att_lock ~/wallpaper.png'

or bind it in Sway:

bindsym $mod+Escape exec att_lock ~/wallpaper.png

Notes & limitations

  • A pattern is not a password. The lockout above throttles online guessing at the lock screen, but it cannot help offline: even at cost factor 9 there are only 43,680 possible 4-dot patterns, so anyone who obtains pattern.hash can search that space at their own pace. Raise --min-dots if that matters to you; each extra dot multiplies the space by roughly an order of magnitude.
  • Patterns are also far more shoulder-surfable than typed passwords, and on touchscreens finger smudges can reveal them.
  • Hash files written by versions before the att_lock-hash-v3 format are not readable; att_lock reports this and asks you to draw a new pattern. The PAM password fallback still works in the meantime. In particular, v3 is the format written since this project was renamed from wlpattern: the account name and the project name are both baked into the hash input, so a pattern enrolled under wlpattern (in $XDG_DATA_HOME/wlpattern/) cannot be carried over and must be re-drawn once.
  • Background images must be PNG (loaded via Cairo). Convert other formats first (e.g. magick in.jpg out.png).
  • The pattern is rendered identically on every connected output; the live drag segment is drawn on the output receiving input.
  • Rendering uses wl_shm + Cairo (no GPU/EGL dependency).

Layout

flake.nix                         Nix flake: package + dev shell
meson.build                       build definition
protocols/ext-session-lock-v1.xml vendored Wayland protocol
src/main.c                        Wayland client, input, unlock/setup logic
src/pattern.c                     grid geometry + pattern sequence model
src/render.c                      wl_shm buffers + Cairo drawing
src/auth.c                        hashing/storage (crypt) + PAM
src/att_lock.h                   shared types and interfaces

License

MIT. The vendored protocol XML is MIT (wlroots contributors).