fix: authenticate_passcode — priority ordering, full role flags, per-role TTL, min_length

This commit is contained in:
Scott Idem
2026-04-10 11:53:58 -04:00
parent f9f588ddf2
commit 7f9666dc1e

View File

@@ -21,10 +21,21 @@ router = APIRouter()
# --- Passcode Authentication --- # --- Passcode Authentication ---
ROLE_PRIORITY = ['super', 'manager', 'administrator', 'trusted', 'public', 'authenticated']
ROLE_TTL = {
'super': 8 * 3600, # 8 hours
'manager': 24 * 3600, # 24 hours
'administrator': 48 * 3600, # 48 hours
'trusted': 48 * 3600, # 48 hours
'public': 24 * 3600, # 24 hours
'authenticated': 12 * 3600, # 12 hours
}
class PasscodeAuthRequest(BaseModel): class PasscodeAuthRequest(BaseModel):
"""Request model for site-based passcode authentication.""" """Request model for site-based passcode authentication."""
site_id: str = Field(..., description="The random string ID of the site") site_id: str = Field(..., description="The random string ID of the site")
passcode: str = Field(..., description="The passcode to verify") passcode: str = Field(..., min_length=5, description="The passcode to verify")
@router.post('/authenticate_passcode', response_model=Resp_Body_Base) @router.post('/authenticate_passcode', response_model=Resp_Body_Base)
async def authenticate_passcode( async def authenticate_passcode(
@@ -54,10 +65,11 @@ async def authenticate_passcode(
except Exception as e: except Exception as e:
log.error(f"Failed to parse access_code_kv_json for site {site_id}: {e}") log.error(f"Failed to parse access_code_kv_json for site {site_id}: {e}")
# 3. Verify Passcode and Resolve Role # 3. Verify passcode in explicit priority order (highest privilege wins)
matched_role = None matched_role = None
for role, code in access_codes.items(): for role in ROLE_PRIORITY:
if str(code) == str(passcode): code = access_codes.get(role)
if code and str(code) == str(passcode):
matched_role = role matched_role = role
break break
@@ -70,22 +82,25 @@ async def authenticate_passcode(
if account_id_int := record.get('account_id'): if account_id_int := record.get('account_id'):
account_id_random = get_id_random(record_id=account_id_int, table_name='account') account_id_random = get_id_random(record_id=account_id_int, table_name='account')
# 5. Mint JWT # 5. Mint JWT with complete role flags and per-role TTL
payload = { payload = {
'account_id': account_id_random, 'account_id': account_id_random,
'super': (matched_role == 'super'),
'manager': (matched_role == 'manager'),
'administrator': (matched_role == 'administrator'), 'administrator': (matched_role == 'administrator'),
'manager': (matched_role == 'manager'), 'trusted': (matched_role == 'trusted'),
'super': (matched_role == 'super'), 'public': (matched_role == 'public'),
'authenticated': (matched_role == 'authenticated'),
'json_str': json.dumps({ 'json_str': json.dumps({
'auth_type': 'passcode', 'auth_type': 'passcode',
'site_id': site_id, 'site_id': site_id,
'role': matched_role 'role': matched_role
}) })
} }
token = sign_jwt( token = sign_jwt(
secret_key=settings.JWT_KEY, secret_key=settings.JWT_KEY,
ttl=3600 * 24, # 24 hour session ttl=ROLE_TTL[matched_role],
**payload **payload
) )