Commit Graph

19 Commits

Author SHA1 Message Date
Daniel Redetzke dcc3f91740 Send adminUsername in /settings again
iOS app builds before Companion 2c9cc1c cannot decode /settings without
it, and App Review still tests such builds. A test keeps it in place.
2026-10-05 08:51:19 +03:00
Daniel Redetzke c79ea08f19 API tokens no longer manage users, passwords or tokens
A full-access token could create a user or reset a password, sign in as
that user and so reach backups and two-step sign-in settings. Users,
passwords, API tokens and the sign-in rules in PATCH /settings now need
a signed-in user again. /auth/me no longer returns tokenId, and
/settings no longer returns adminUsername.
2026-10-05 08:41:18 +03:00
Daniel Redetzke 0a0efd9115 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 9ecc188269 Keep IPv6 router announcements working with forwarding on
With net.ipv6.conf.all.forwarding=1, Linux ignores router announcements
unless accept_ra is 2, so a server that gets its IPv6 route by SLAAC
(e.g. a Raspberry Pi at home) lost IPv6 once the route expired.

The sysctl file now also sets accept_ra=2 for the default and for every
network card and the IPv6 default-route interface, except where
accept_ra is 0. "update" rewrites the file, which fixes existing
installs. A new health check warns while the uplink still has
accept_ra=1.
2026-10-05 00:10:13 +03:00
Daniel Redetzke 490d055cec Delete stored security keys 2026-10-04 22:35:19 +03:00
Daniel Redetzke 56978b28e9 Passkeys only: drop adding security keys 2026-10-04 22:13:31 +03:00
Daniel Redetzke 3e44022b0b Two-step sign-in: authenticator app, security keys and passkeys 2026-10-04 21:55:53 +03:00
Daniel Redetzke f5e0da5ccd Fingerprint app.js, setup.js and app.css 2026-10-04 20:56:35 +03:00
Daniel Redetzke 82228faeba More web interface pages 2026-10-04 20:47:12 +03:00
Daniel Redetzke 6afef85b2b Full-access tokens manage users, passwords and tokens 2026-10-04 20:37:46 +03:00
Daniel Redetzke bbbef00329 Web interface setting 2026-10-04 20:16:57 +03:00
Daniel Redetzke 19008f8a33 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 4ecfddf06a 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 7391aac429 Peers: optional latency check with per-peer setting
The server pings a peer's tunnel address every 30 s and shows the median
of the last 5 minutes in the peer list (with a 1-hour sparkline) and a
24-hour chart on the peer page. Off by default; "active" pings only
while the device sends traffic, "always" keeps the tunnel up.
2026-10-04 14:28:44 +03:00
Daniel Redetzke 7d4cd48ca4 Interactive install, with flags kept for unattended installs
In a terminal, install now asks for the domain, Let's Encrypt email,
endpoint, WireGuard port and admin password, shows a summary and changes
nothing until confirmed. Re-runs offer the current settings and say how
many devices need a new config when the endpoint or port changes.

Flags still work and skip their question; -y or no terminal skips all
questions. New -port flag sets the WireGuard UDP port. Every value is
checked before the system is touched.
2026-10-03 23:46:04 +03:00
Daniel Redetzke ef1988e4d0 Add one-time setup links as an alternative to the QR code
A config can now be handed over as a one-time link, valid for 1 h, 24 h or
7 days and protected by a PIN by default. Keys are made only when the link
is opened; the link works once and is revoked after 5 wrong PINs. Issuing a
new config offers the same choice, and the current config keeps working
until the link is used.

Remove the option to paste a client's public key, in the web UI, the API
and the iOS app.
2026-10-03 23:10:28 +03:00
Daniel Redetzke 37ab26b415 Add connection history per peer with country and network lookup
- The stats sampler records sessions per peer: start, end, address and
  traffic. A session ends when the peer goes quiet or is disabled; a new
  one starts when the device changes networks. Stored in stats.json and
  kept as long as the daily traffic history (max 1000 per peer).
- Country and network operator come from the free DB-IP Lite databases
  (CC BY 4.0), downloaded monthly and looked up locally, so peer
  addresses never leave the server. Settings → Data retention can switch
  this off, which deletes the databases.
- API: GET /peers/{id}/sessions; peer stats include the current location;
  settings include the database status.
- Web UI and iOS app: connection history card, location line, country
  code in the peer list (web), switch in data retention.

Claude-Session: https://claude.ai/code/session_01RAnLbyQZ5ZTA7KqwXP98nw
2026-10-03 19:21:10 +03:00
Daniel Redetzke 1543069089 Make log and traffic retention configurable; limit DNS presets to Quad9
- Settings → Data retention: log file size, number of old log files,
  hourly and daily traffic history. Stored as log and stats in
  config.json, validated, and applied without a restart; lowering a
  limit deletes older log files and history after confirmation.
- Traffic history is now pruned by time instead of by bucket count.
- Server page DNS provider list offers only Quad9 and Custom.

Claude-Session: https://claude.ai/code/session_01RAnLbyQZ5ZTA7KqwXP98nw
2026-10-03 17:48:33 +03:00
Daniel Redetzke 4793e8dfba 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.

Claude-Session: https://claude.ai/code/session_01RAnLbyQZ5ZTA7KqwXP98nw
2026-10-03 16:54:37 +03:00