Require Gitea login to write GPX data; IPv6-capable bind
CI / check (push) Successful in 6m28s
CI / deploy (push) Successful in 13s

Upload/delete/move/create-folder now require logging in via Gitea
OAuth2 (only MAPTOOL_ALLOWED_GITEA_USER is granted write access);
reading stays public. Deploy secrets (session secret, OAuth2 client
credentials, allowed user) are written to .env from Gitea Actions
repo secrets on every deploy instead of living on the server by hand.

Also switch the container's bind address to "[::]" (dual-stack) so
the app is reachable over IPv6, not just IPv4.
This commit is contained in:
randy committed 2026-08-27 18:02:37 +02:00
1 parent ae67cc72c7
commit e13d1a1e97
13 files changed
+261 -11

No files matched your search

+29 -2
View File
@@ -239,5 +239,32 @@ Online/Offline) with no extra re-add handling needed.
== Networking
The Sinatra server only binds to `127.0.0.1`. It is not meant to be
reachable from other machines.
By default (local dev) the Sinatra server only binds to `127.0.0.1`
and isn't reachable from other machines. The deployed instance is an
exception — see `docs/deployment.adoc` for `BIND_HOST` and how it's
exposed via Docker/nginx as `map.priesol.net`.
== Authentication
The GPX store's read endpoints (viewing the map, the folder tree,
individual files) are public — anyone with the URL can look. Its write
endpoints (`POST /api/gpx`, `POST /api/gpx/folder`, `DELETE
/api/gpx/file/*`, `DELETE /api/gpx/folder/*`, `POST /api/gpx/move`)
require login, guarded by `require_login!` in `app.rb`.
Login delegates to the Gitea instance at `git.priesol.net` via OAuth2
(`GET /login` redirects to Gitea's authorize endpoint, `GET
/auth/callback` exchanges the code and fetches
`/api/v1/user`) rather than maintaining a separate local
username/password — there's already an account to reuse, and it keeps
credential storage (password hash, resets, ...) out of this app
entirely. Successfully authenticating with Gitea is not by itself
enough to write, though — the callback also checks the returned
`login` against `MAPTOOL_ALLOWED_GITEA_USER`, so registering (or
already having) any other account on that Gitea instance doesn't grant
access here.
Session state is a signed cookie (`Rack::Session::Cookie`, `secure`
in production, `httponly`, `same_site: lax`) keyed off
`SESSION_SECRET` — see `docs/deployment.adoc` for where that and the
OAuth2 client id/secret live (not committed to the repo).
+34
View File
@@ -68,6 +68,40 @@ the deployed container specifically; Docker's own port publishing
(`ports:` in the compose file) is the network boundary there instead
of Puma's bind address.
== Secrets (`.env`)
`docker-compose.yaml` reads `SESSION_SECRET`, `GITEA_OAUTH_CLIENT_ID`,
`GITEA_OAUTH_CLIENT_SECRET` and `MAPTOOL_ALLOWED_GITEA_USER` from the
environment (see `docs/architecture.adoc` for what they're for) —
docker compose loads these automatically from a `.env` file next to
`docker-compose.yaml`, i.e. `/srv/docker/maptool/.env`. That file is
gitignored and dockerignored on purpose: nothing here ever puts
secrets in the repository or a built image layer.
It's not created by hand on the server — the deploy job's "Write
.env" step regenerates it on every deploy from repo-level Gitea
Actions secrets (*Settings → Actions → Secrets*): `SESSION_SECRET`,
`OAUTH_CLIENT_ID`, `OAUTH_CLIENT_SECRET`, `MAPTOOL_ALLOWED_GITEA_USER`.
The OAuth2 ones aren't named `GITEA_OAUTH_CLIENT_*` to match the `.env`
var names 1:1 — Gitea rejects secret names starting with `GITEA_` or
`GITHUB_` as reserved — but the workflow step maps them to the right
`.env` var names regardless. Gitea masks secret values in the job log
automatically. Set these once in the repo settings and every deploy
since keeps `.env` in sync — no server-side step needed beyond the
first-time OAuth2 application registration below.
`SESSION_SECRET` must stay the same value across deploys (regenerating
it every push would silently log everyone out every time `main`
changes) — generate it once (`openssl rand -hex 32`) and store that
same value as the secret from then on, don't regenerate per-deploy.
Register the OAuth2 application on the Gitea side (as the
`MAPTOOL_ALLOWED_GITEA_USER` account): *Settings → Applications →
Manage OAuth2 Applications → Create a new OAuth2 Application*, with
redirect URI `https://map.priesol.net/auth/callback`. That gives you
the client id/secret to store as the two `GITEA_OAUTH_*` secrets
above.
== CI deploy job
`.gitea/workflows/ci.yml`'s `deploy` job runs after `check` passes, only