6 Commits

Author SHA1 Message Date
Daniel Redetzke 3e8dba6072 Fixes from the audit: input checks, apply order, sign-in limits
- The server endpoint must be a plain host name or IP address. It is
  written into client configs as is, so a newline could add lines such
  as PreUp, which wg-quick runs as root on the client.
- Listen addresses and the session length (1–720 hours) are checked.
  Before web settings or a restore are saved, the server tries the new
  listen addresses and certificate files, so a value it cannot start
  with is refused instead of stopping the service at the next restart.
- Kernel applies run one at a time and read the config once it is
  their turn, so an older config can no longer be applied last.
- Pending passkey sign-ins are capped: 10 per address, 1000 in total.
- Behind a local proxy, the last X-Forwarded-For entry is the client;
  earlier ones come from the client and are ignored.
- With LAN access off, peers are also kept from the IPv6 networks on
  the uplink, not only from its private IPv4 networks.
- A change that leaves no user with a password is refused, and so is a
  backup without one or from a newer version.
2026-10-05 23:09:03 +03:00
Daniel Redetzke 592b738f10 Cap concurrent password checks and count attempts before checking
Every argon2 run takes 64 MiB and nothing limited how many ran at once,
so parallel sign-in attempts could run the server out of memory (8 at
once used about 600 MB). At most two now run at once; at most 16
sign-ins wait for one, more get HTTP 429. 30 parallel sign-ins peaked
at 275 MB.

A sign-in attempt now counts toward the lockout before its password is
checked, so parallel attempts cannot get past it; a right password
takes its own attempt back. IPv6 addresses are locked out by /64.
2026-10-05 00:23:05 +03:00
Daniel Redetzke 9d54d2d5ad Two-step sign-in: authenticator app, security keys and passkeys 2026-10-04 21:55:53 +03:00
Daniel Redetzke 0444a0b2be My account page
The signed-in user's profile, password and own app tokens move from the
Settings card to their own page at #/account, ready for more user
functions. The sidebar footer links to it with the user's name. Users
can now set their own note; the page header shows when and from where
the session started, which the server now records. Settings keeps the
Users table, where your own row links to My account.
2026-10-04 16:07:21 +03:00
Daniel Redetzke 15b1983a0b Multiple users, all admins
The single admin account becomes a list of users; config.json moves to
version 2 and the old admin is migrated on first start. Every user is an
admin. Sessions are tied to a user and their password, so deleting a user
or resetting a password signs them out at once. API tokens belong to the
user who made them and go away with that user.

Admins add users with a temporary password and choose whether it must be
changed at first sign-in; until then the API refuses everything but the
password change. Settings gets My account and Users cards, and the token
table shows each token's owner. 'GHOSTWIRE passwd [username]' resets any
user's password. A failed update now also restores config.json, since the
new version may have upgraded it.
2026-10-04 15:51:14 +03:00
Daniel Redetzke 155dd7e264 GHOSTWIRE 0.1.2: WireGuard server manager with web UI and API
Single Go binary that manages a WireGuard server based on pivpn's defaults:
- config.json as the single source of truth, reconciled to the kernel via
  netlink, wgctrl and its own nftables table (NAT, forward, input)
- web interface (dashboard, peers, peer detail, add peer, server, settings)
  and a JSON API for the future iOS app, with session and API-token auth
- client private keys are never stored; configs and QR codes shown once
- per-peer traffic statistics in stats.json, logs in GHOSTWIRE.jsonl
- HTTPS via Let's Encrypt, self-signed, certificate files or off
- self-managing: install, update (restores the old binary on failure),
  uninstall and passwd subcommands; systemd unit generated by the binary

Tested end to end on Ubuntu 26.04 (kernel 7.0) at dev.redetzke.aero.
2026-10-03 16:54:37 +03:00