Dev mode: panneau connexion rapide avec 4 profils pre-configures

Ajout d'un panneau dev sous le login (Alice=membre, Bob=forgeron,
Charlie=comite tech, Dave=observateur) pour tester les differents
roles sans keypair Ed25519. Endpoint GET /auth/dev/profiles renvoie
les profils uniquement en ENVIRONMENT=development.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-02 03:09:40 +01:00
parent 8dc0dfd452
commit 11e4a4d60a
3 changed files with 237 additions and 5 deletions

View File

@@ -27,6 +27,38 @@ from app.services.auth_service import (
router = APIRouter()
# ── Dev profiles (only available when ENVIRONMENT == "development") ─────────
DEV_PROFILES = [
{
"address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"display_name": "Alice (Membre WoT)",
"wot_status": "member",
"is_smith": False,
"is_techcomm": False,
},
{
"address": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"display_name": "Bob (Forgeron)",
"wot_status": "member",
"is_smith": True,
"is_techcomm": False,
},
{
"address": "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmkP7j4bJa3zN7d8tY",
"display_name": "Charlie (Comite Tech)",
"wot_status": "member",
"is_smith": True,
"is_techcomm": True,
},
{
"address": "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy",
"display_name": "Dave (Observateur)",
"wot_status": "unknown",
"is_smith": False,
"is_techcomm": False,
},
]
# ── In-memory challenge store (short-lived, no persistence needed) ──────────
# Structure: { address: { "challenge": str, "expires_at": datetime } }
_pending_challenges: dict[str, dict] = {}
@@ -113,8 +145,11 @@ async def verify_challenge(
# 5. Consume the challenge
del _pending_challenges[payload.address]
# 6. Get or create identity
identity = await get_or_create_identity(db, payload.address)
# 6. Get or create identity (apply dev profile if available)
dev_profile = None
if settings.ENVIRONMENT == "development":
dev_profile = next((p for p in DEV_PROFILES if p["address"] == payload.address), None)
identity = await get_or_create_identity(db, payload.address, dev_profile=dev_profile)
# 7. Create session token
token = await create_session(db, identity)
@@ -125,6 +160,14 @@ async def verify_challenge(
)
@router.get("/dev/profiles")
async def list_dev_profiles():
"""List available dev profiles for quick login. Only available in development."""
if settings.ENVIRONMENT != "development":
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not available")
return DEV_PROFILES
@router.get("/me", response_model=IdentityOut)
async def get_me(
identity: DuniterIdentity = Depends(get_current_identity),

View File

@@ -82,15 +82,38 @@ async def get_current_identity(
return identity
async def get_or_create_identity(db: AsyncSession, address: str) -> DuniterIdentity:
"""Get an existing identity by address or create a new one."""
async def get_or_create_identity(
db: AsyncSession,
address: str,
dev_profile: dict | None = None,
) -> DuniterIdentity:
"""Get an existing identity by address or create a new one.
If dev_profile is provided, apply the profile attributes on create or update.
"""
result = await db.execute(select(DuniterIdentity).where(DuniterIdentity.address == address))
identity = result.scalar_one_or_none()
if identity is None:
identity = DuniterIdentity(address=address)
kwargs: dict = {"address": address}
if dev_profile:
kwargs.update({
"display_name": dev_profile.get("display_name"),
"wot_status": dev_profile.get("wot_status", "unknown"),
"is_smith": dev_profile.get("is_smith", False),
"is_techcomm": dev_profile.get("is_techcomm", False),
})
identity = DuniterIdentity(**kwargs)
db.add(identity)
await db.commit()
await db.refresh(identity)
elif dev_profile:
# Update existing identity with dev profile data
identity.display_name = dev_profile.get("display_name", identity.display_name)
identity.wot_status = dev_profile.get("wot_status", identity.wot_status)
identity.is_smith = dev_profile.get("is_smith", identity.is_smith)
identity.is_techcomm = dev_profile.get("is_techcomm", identity.is_techcomm)
await db.commit()
await db.refresh(identity)
return identity