146 lines
4.5 KiB
Python
146 lines
4.5 KiB
Python
"""User information formatting and retrieval logic."""
|
|
|
|
from datetime import timezone
|
|
|
|
from paskia import aaguid, db
|
|
from paskia.authsession import EXPIRES
|
|
from paskia.util import hostutil, permutil, useragent
|
|
|
|
|
|
def _format_datetime(dt):
|
|
"""Format a datetime object to ISO 8601 string with UTC timezone."""
|
|
if dt is None:
|
|
return None
|
|
if dt.tzinfo:
|
|
return dt.astimezone(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
else:
|
|
return dt.replace(tzinfo=timezone.utc).isoformat().replace("+00:00", "Z")
|
|
|
|
|
|
async def format_user_info(
|
|
*,
|
|
user_uuid,
|
|
auth: str,
|
|
session_record,
|
|
request_host: str | None,
|
|
) -> dict:
|
|
"""Format complete user information for authenticated users.
|
|
|
|
Args:
|
|
user_uuid: UUID of the user to fetch information for
|
|
auth: Authentication token
|
|
session_record: Current session record
|
|
request_host: Host header from the request
|
|
|
|
Returns:
|
|
Dictionary containing formatted user information including:
|
|
- User details
|
|
- Organization and role information
|
|
- Credentials list
|
|
- Sessions list
|
|
- Permissions
|
|
"""
|
|
u = db.get_user_by_uuid(user_uuid)
|
|
ctx = await permutil.session_context(auth, request_host)
|
|
|
|
# Fetch and format credentials
|
|
user_credentials = db.get_credentials_by_user_uuid(user_uuid)
|
|
credentials: list[dict] = []
|
|
user_aaguids: set[str] = set()
|
|
|
|
for c in user_credentials:
|
|
aaguid_str = str(c.aaguid)
|
|
user_aaguids.add(aaguid_str)
|
|
credentials.append(
|
|
{
|
|
"credential_uuid": str(c.uuid),
|
|
"aaguid": aaguid_str,
|
|
"created_at": _format_datetime(c.created_at),
|
|
"last_used": _format_datetime(c.last_used),
|
|
"last_verified": _format_datetime(c.last_verified),
|
|
"sign_count": c.sign_count,
|
|
"is_current_session": session_record.credential_uuid == c.uuid,
|
|
}
|
|
)
|
|
|
|
credentials.sort(key=lambda cred: cred["created_at"])
|
|
aaguid_info = aaguid.filter(user_aaguids)
|
|
|
|
# Format role and org information
|
|
role_info = None
|
|
org_info = None
|
|
effective_permissions: list[str] = []
|
|
|
|
if ctx:
|
|
role_info = {
|
|
"uuid": str(ctx.role.uuid),
|
|
"display_name": ctx.role.display_name,
|
|
"permissions": ctx.role.permissions,
|
|
}
|
|
org_info = {
|
|
"uuid": str(ctx.org.uuid),
|
|
"display_name": ctx.org.display_name,
|
|
"permissions": ctx.org.permissions,
|
|
}
|
|
effective_permissions = [p.scope for p in (ctx.permissions or [])]
|
|
|
|
# Format sessions
|
|
normalized_request_host = hostutil.normalize_host(request_host)
|
|
session_records = db.list_sessions_for_user(user_uuid)
|
|
current_session_key = auth
|
|
sessions_payload: list[dict] = []
|
|
|
|
for entry in session_records:
|
|
sessions_payload.append(
|
|
{
|
|
"id": entry.key,
|
|
"credential_uuid": str(entry.credential_uuid),
|
|
"host": entry.host,
|
|
"ip": entry.ip,
|
|
"user_agent": useragent.compact_user_agent(entry.user_agent),
|
|
"last_renewed": _format_datetime(entry.expiry - EXPIRES),
|
|
"is_current": entry.key == current_session_key,
|
|
"is_current_host": bool(
|
|
normalized_request_host
|
|
and entry.host
|
|
and entry.host == normalized_request_host
|
|
),
|
|
}
|
|
)
|
|
|
|
return {
|
|
"authenticated": True,
|
|
"user": {
|
|
"user_uuid": str(u.uuid),
|
|
"user_name": u.display_name,
|
|
"created_at": _format_datetime(u.created_at),
|
|
"last_seen": _format_datetime(u.last_seen),
|
|
"visits": u.visits,
|
|
},
|
|
"org": org_info,
|
|
"role": role_info,
|
|
"permissions": effective_permissions,
|
|
"credentials": credentials,
|
|
"aaguid_info": aaguid_info,
|
|
"sessions": sessions_payload,
|
|
}
|
|
|
|
|
|
async def format_reset_user_info(user_uuid, reset_token) -> dict:
|
|
"""Format minimal user information for reset token requests.
|
|
|
|
Args:
|
|
user_uuid: UUID of the user
|
|
reset_token: Reset token record
|
|
|
|
Returns:
|
|
Dictionary with minimal user info for password reset flow
|
|
"""
|
|
u = db.get_user_by_uuid(user_uuid)
|
|
|
|
return {
|
|
"authenticated": False,
|
|
"session_type": reset_token.token_type,
|
|
"user": {"user_uuid": str(u.uuid), "user_name": u.display_name},
|
|
}
|