admin: user accounts and session login

The admin was one shared HTTP Basic login: no way to give someone
partial access, revoke one person, or tell who changed what. Add a users
table and a session login form. Passwords are scrypt hashes from Ruby's
OpenSSL, so no native gem is needed. Sessions carry a per-user version
that is bumped on password change, which logs that user out everywhere.

ADMIN_USER/ADMIN_PASSWORD now bootstrap the first superuser on an empty
table and afterwards only work while no active superuser exists, as a
recovery path that re-creates one. Until per-area permissions land,
non-superusers only reach the dashboard and their own password page.

Assisted-by: Claude:opus-5
This commit is contained in:
Sergei Poljanski 2026-10-10 08:25:46 +04:00
commit 9bf40690e5
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
13 changed files with 436 additions and 59 deletions

View file

@ -37,6 +37,8 @@ if ENV['DATABASE_URL']
require_relative 'lib/invoice_pdf'
require_relative 'lib/bingo'
Bingo.seed!
require_relative 'lib/user'
User.bootstrap!(ENV['ADMIN_USER'], ENV['ADMIN_PASSWORD'])
else
$logger.warn('DATABASE_URL not set — invoicing disabled')
end
@ -63,7 +65,7 @@ class AsxpioWeb < Sinatra::Base
same_site: :lax
use Rack::Protection::AuthenticityToken
use AdminAuth
register AdminAuth
register BingoAdmin
Mailer.configure!