From 260006ad6533c72b6996269ef7026a7758f30f4f Mon Sep 17 00:00:00 2001 From: Roman Priesol Date: Thu, 27 Aug 2026 18:25:31 +0200 Subject: [PATCH] Support multiple allowed users for write access MAPTOOL_ALLOWED_GITEA_USER now accepts a comma-separated list of Gitea usernames instead of just one, for when more than one person needs upload/delete/move access. --- app.rb | 14 +++++++------- docs/architecture.adoc | 8 +++++--- docs/deployment.adoc | 17 +++++++++++------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app.rb b/app.rb index ac7e5e4..99b7138 100644 --- a/app.rb +++ b/app.rb @@ -24,13 +24,13 @@ module Maptool # Login delegates to the Gitea instance the user already has an account # on, rather than maintaining a local username/password — see - # docs/architecture.adoc. Only ALLOWED_GITEA_USER may write; anyone else - # can authenticate against Gitea but is still refused. No defaults for - # the OAuth2 client id/secret/user: blank values just mean login (and - # thus writing) doesn't work, which is fine outside production — nothing - # here is eagerly validated at load time. + # docs/architecture.adoc. Only users listed in ALLOWED_GITEA_USERS may + # write; anyone else can authenticate against Gitea but is still + # refused. No defaults for the OAuth2 client id/secret/user list: blank + # values just mean login (and thus writing) doesn't work, which is fine + # outside production — nothing here is eagerly validated at load time. GITEA_URL = ENV.fetch("GITEA_URL", "https://git.priesol.net") - ALLOWED_GITEA_USER = ENV.fetch("MAPTOOL_ALLOWED_GITEA_USER", "") + ALLOWED_GITEA_USERS = ENV.fetch("MAPTOOL_ALLOWED_GITEA_USER", "").split(",").map(&:strip) OAUTH_CLIENT = OAuth2::Client.new( ENV.fetch("GITEA_OAUTH_CLIENT_ID", ""), ENV.fetch("GITEA_OAUTH_CLIENT_SECRET", ""), @@ -67,7 +67,7 @@ module Maptool token = OAUTH_CLIENT.auth_code.get_token(params[:code], redirect_uri: callback_url) user = token.get("/api/v1/user").parsed - halt 403, "not authorized" unless user["login"] == ALLOWED_GITEA_USER + halt 403, "not authorized" unless ALLOWED_GITEA_USERS.include?(user["login"]) session[:user] = user["login"] redirect "/" diff --git a/docs/architecture.adoc b/docs/architecture.adoc index fedebd1..902c69a 100644 --- a/docs/architecture.adoc +++ b/docs/architecture.adoc @@ -260,9 +260,11 @@ 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. +`login` against `MAPTOOL_ALLOWED_GITEA_USER` (a comma-separated +allowlist, e.g. `randy,friend1,friend2`), so registering (or already +having) any other account on that Gitea instance doesn't grant access +here. It's a flat allowlist — everyone in it has equal write access, +no per-user roles or permissions. Session state is a signed cookie (`Rack::Session::Cookie`, `secure` in production, `httponly`, `same_site: lax`) keyed off diff --git a/docs/deployment.adoc b/docs/deployment.adoc index a8a619b..a0afa4e 100644 --- a/docs/deployment.adoc +++ b/docs/deployment.adoc @@ -95,12 +95,17 @@ 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. +Register the OAuth2 application once, under any one Gitea account +(doesn't need to be an allowed user itself — any Gitea account can +authenticate through it, `MAPTOOL_ALLOWED_GITEA_USER` is what actually +decides who gets write access): *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 `OAUTH_CLIENT_*` secrets above. + +`MAPTOOL_ALLOWED_GITEA_USER` itself is a comma-separated list of Gitea +usernames, e.g. `randy,friend1,friend2` — not their emails, the +`login` field from Gitea's `/api/v1/user`. == CI deploy job