Skip to content

v0.3.0

Choose a tag to compare

@wushilin wushilin released this 06 Sep 04:21
· 1 commit to master since this release

Remember this device (opt-in)

A browser that has already passed a TOTP challenge can be trusted for a bounded window, so it is asked for a password but not a code. Off by default — set remember_device = true under [mfa].

The bypass is the second factor and nothing else. The local password or the Google sign-in is verified on every login regardless, and enrollment is never skipped. A trust record is not a credential that logs anyone in; it is evidence that this browser has already proved possession of the authenticator for one identity.

  • Trust is bound to the identity and to the enrolment's enrolled_at, so re-enrolling a TOTP secret strands every older device with no separate revocation step. That is also the recovery path: drop someone's mfa_secret from enrollment.toml and their devices stop working.
  • The window is absolute from the moment the box was ticked and is never extended by use — a sliding window would let a stolen cookie refresh its own lifetime indefinitely.
  • Not bound to IP or User-Agent. Phones roam and browsers auto-update, so comparing either would un-trust honest users at random. Both are recorded for display only.
  • Turning remember_device back off revokes trust immediately rather than merely stopping new grants.
  • Manage your own devices from the devices button in the terminal toolbar: which browser you are on, when each was last used, revoke one or all. Self-service and scoped to you, exactly like share links.

New [mfa] options: remember_device, remember_device_days (default 30, clamped 1–90), device_path, max_devices_per_identity.

Fix: a lost-update race in all three state stores

The device, enrolment and session stores all mutated under a lock, cloned a snapshot, released the lock, and then wrote. That is not equivalent to writing under the lock: two writers interleave, and the slower one lands a snapshot taken before the faster one's change — reverting it on disk while memory still looks correct. It only surfaced after a restart, as a revoked device or a logged-out session coming back.

All three now hold the lock across the write, which is what their doc comments already claimed. Covered by concurrency tests that fail against the old shape. The rename is now durable too — the parent directory is fsynced, so a crash cannot lose the swap even though the bytes it points at were safely on disk.

Static binaries for both architectures

Prebuilt statically linked musl binaries for x86_64 and aarch64, verified to carry no PT_INTERP and to run on both musl and glibc userlands. Nothing here touches the host auth stack any more — no PAM, no dlopen, no setuid helper — so one file per architecture runs on any Linux.

VER=0.3.0
ARCH=x86_64          # or aarch64
BASE=https://github.com/wushilin/webshell/releases/download/v$VER
curl -fsSLO $BASE/webshell-$VER-linux-$ARCH-musl
curl -fsSLO $BASE/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
sudo install -m 0755 webshell-$VER-linux-$ARCH-musl /usr/local/bin/webshell

The one thing a static build gives up is NSS: getpwuid reads /etc/passwd directly rather than LDAP/SSSD. Set [terminals] login_cmd if the account webshell runs as is not local.

Also

  • Dropped stale "PAM-authenticated" claims from the crate description (visible in --help) and from several doc comments; PAM was replaced by self-managed argon2id hashes some releases ago.
  • README: an install section for the prebuilt binaries, the new [mfa] options, and how to recover if Google-only sign-in locks you out.

Upgrading is a drop-in binary swap. No config change is required — the new options default to off, and existing config files keep parsing unchanged.