The clubmanager.app domain was taken, so the platform is now RosterChief (rosterchief.app). Renames the Django project package clubmanager/ -> rosterchief/ (git tracks it as a move, so history follows), every `from rosterchief.base import ...`, the settings/wsgi/asgi module paths, env vars (ROSTERCHIEF_BASE_DOMAIN / ROSTERCHIEF_RP_NAME), the MFA adapter (RosterChiefMFAAdapter), brand text, and the docs. Two things were deliberately NOT swept: - club.models.ClubManager stays: it is the Django manager *for Club*, not the brand. A blind rename would have silently broken it. - Migrations are untouched (history is not rewritten). The only reference was a cosmetic help_text, so a normal AlterField migration carries the new domain. Note the WebAuthn RP ID is the base domain, so moving to rosterchief.app cryptographically invalidates any passkey enrolled under the old one; they cannot be migrated and must be re-enrolled. Nothing is in production, so the real cost is zero. Add django-lucide (from bsiebens/lucide) for icons: the theme toggle now swaps sun/moon against the effective theme, and the control panel gets icons on its tabs, actions and stat groups. Its classifiers stop at Django 5.0, but that is stale metadata — verified rendering on Django 6 / Python 3.14. Also add formbuilder, shop and controlpanel to ruff's known-first-party list, which had drifted behind the apps that landed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
38 lines
1.3 KiB
Python
38 lines
1.3 KiB
Python
"""allauth adapters.
|
|
|
|
The MFA adapter exists for one important reason: WebAuthn credentials are bound
|
|
to a **Relying Party ID** (a domain). allauth's default RP ID is the request's
|
|
host — which under our subdomain tenancy would be ``ajax-united.rosterchief.app``,
|
|
binding a passkey to *one club*. A member of two clubs would then need two
|
|
passkeys, and a credential registered at one club would silently fail at another.
|
|
|
|
Pinning the RP ID to the registrable parent domain (``rosterchief.app``) makes a
|
|
single passkey work across every club subdomain.
|
|
"""
|
|
|
|
from allauth.mfa.adapter import DefaultMFAAdapter
|
|
from django.conf import settings
|
|
|
|
|
|
class RosterChiefMFAAdapter(DefaultMFAAdapter):
|
|
def get_public_key_credential_rp_entity(self) -> dict[str, str]:
|
|
return {
|
|
"id": webauthn_rp_id(),
|
|
"name": settings.MFA_WEBAUTHN_RP_NAME,
|
|
}
|
|
|
|
|
|
def webauthn_rp_id() -> str:
|
|
"""The registrable parent domain that passkeys are bound to.
|
|
|
|
Falls back to the request host when no base domain is configured (e.g. a
|
|
bare ``localhost`` dev server), which keeps WebAuthn usable there.
|
|
"""
|
|
base_domain = getattr(settings, "ROSTERCHIEF_BASE_DOMAIN", "")
|
|
if base_domain:
|
|
return base_domain
|
|
|
|
from allauth.core import context
|
|
|
|
return context.request.get_host().partition(":")[0]
|