Refactor API to match database, no _uuid postfixes.
This commit is contained in:
@@ -72,4 +72,4 @@ async def refresh_session_token(token: str, *, ip: str, user_agent: str):
|
|||||||
async def delete_credential(credential_uuid: UUID, auth: str, host: str | None = None):
|
async def delete_credential(credential_uuid: UUID, auth: str, host: str | None = None):
|
||||||
"""Delete a specific credential for the current user."""
|
"""Delete a specific credential for the current user."""
|
||||||
s = await get_session(auth, host=host)
|
s = await get_session(auth, host=host)
|
||||||
db.delete_credential(credential_uuid, s.user_uuid)
|
db.delete_credential(credential_uuid, s.user)
|
||||||
|
|||||||
@@ -55,11 +55,6 @@ class Role(msgspec.Struct, dict=True):
|
|||||||
role.uuid = uuid7.create()
|
role.uuid = uuid7.create()
|
||||||
return role
|
return role
|
||||||
|
|
||||||
# Legacy alias for org field
|
|
||||||
@property
|
|
||||||
def org_uuid(self) -> UUID:
|
|
||||||
return self.org
|
|
||||||
|
|
||||||
|
|
||||||
class Org(msgspec.Struct, dict=True):
|
class Org(msgspec.Struct, dict=True):
|
||||||
display_name: str
|
display_name: str
|
||||||
@@ -165,15 +160,6 @@ class Session(msgspec.Struct, dict=True):
|
|||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.key: str | None = None # Convenience field, not serialized
|
self.key: str | None = None # Convenience field, not serialized
|
||||||
|
|
||||||
# Legacy aliases
|
|
||||||
@property
|
|
||||||
def user_uuid(self) -> UUID:
|
|
||||||
return self.user
|
|
||||||
|
|
||||||
@property
|
|
||||||
def credential_uuid(self) -> UUID:
|
|
||||||
return self.credential
|
|
||||||
|
|
||||||
def metadata(self) -> dict:
|
def metadata(self) -> dict:
|
||||||
"""Return session metadata for backwards compatibility."""
|
"""Return session metadata for backwards compatibility."""
|
||||||
return {
|
return {
|
||||||
@@ -191,11 +177,6 @@ class ResetToken(msgspec.Struct, dict=True):
|
|||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.key: bytes | None = None # Convenience field, not serialized
|
self.key: bytes | None = None # Convenience field, not serialized
|
||||||
|
|
||||||
# Legacy alias
|
|
||||||
@property
|
|
||||||
def user_uuid(self) -> UUID:
|
|
||||||
return self.user
|
|
||||||
|
|
||||||
|
|
||||||
class SessionContext(msgspec.Struct):
|
class SessionContext(msgspec.Struct):
|
||||||
session: Session
|
session: Session
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import timezone
|
from datetime import timezone
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import Body, FastAPI, HTTPException, Request, Response
|
from fastapi import Body, FastAPI, HTTPException, Request, Response
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
@@ -308,7 +308,7 @@ async def admin_update_role_name(
|
|||||||
status_code=403, detail="Insufficient permissions", mode="forbidden"
|
status_code=403, detail="Insufficient permissions", mode="forbidden"
|
||||||
)
|
)
|
||||||
role = db.get_role(role_uuid)
|
role = db.get_role(role_uuid)
|
||||||
if role.org_uuid != org_uuid:
|
if role.org != org_uuid:
|
||||||
raise HTTPException(status_code=404, detail="Role not found in organization")
|
raise HTTPException(status_code=404, detail="Role not found in organization")
|
||||||
|
|
||||||
display_name = payload.get("display_name")
|
display_name = payload.get("display_name")
|
||||||
@@ -340,7 +340,7 @@ async def admin_add_role_permission(
|
|||||||
)
|
)
|
||||||
|
|
||||||
role = db.get_role(role_uuid)
|
role = db.get_role(role_uuid)
|
||||||
if role.org_uuid != org_uuid:
|
if role.org != org_uuid:
|
||||||
raise HTTPException(status_code=404, detail="Role not found in organization")
|
raise HTTPException(status_code=404, detail="Role not found in organization")
|
||||||
|
|
||||||
# Verify permission exists and org can grant it
|
# Verify permission exists and org can grant it
|
||||||
@@ -376,7 +376,7 @@ async def admin_remove_role_permission(
|
|||||||
)
|
)
|
||||||
|
|
||||||
role = db.get_role(role_uuid)
|
role = db.get_role(role_uuid)
|
||||||
if role.org_uuid != org_uuid:
|
if role.org != org_uuid:
|
||||||
raise HTTPException(status_code=404, detail="Role not found in organization")
|
raise HTTPException(status_code=404, detail="Role not found in organization")
|
||||||
|
|
||||||
# Sanity check: prevent admin from removing their own access
|
# Sanity check: prevent admin from removing their own access
|
||||||
@@ -419,7 +419,7 @@ async def admin_delete_role(
|
|||||||
status_code=403, detail="Insufficient permissions", mode="forbidden"
|
status_code=403, detail="Insufficient permissions", mode="forbidden"
|
||||||
)
|
)
|
||||||
role = db.get_role(role_uuid)
|
role = db.get_role(role_uuid)
|
||||||
if role.org_uuid != org_uuid:
|
if role.org != org_uuid:
|
||||||
raise HTTPException(status_code=404, detail="Role not found in organization")
|
raise HTTPException(status_code=404, detail="Role not found in organization")
|
||||||
|
|
||||||
# Sanity check: prevent admin from deleting their own role
|
# Sanity check: prevent admin from deleting their own role
|
||||||
@@ -797,7 +797,7 @@ async def admin_delete_user_session(
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_session = db.get_session(session_id)
|
target_session = db.get_session(session_id)
|
||||||
if not target_session or target_session.user_uuid != user_uuid:
|
if not target_session or target_session.user != user_uuid:
|
||||||
raise HTTPException(status_code=404, detail="Session not found")
|
raise HTTPException(status_code=404, detail="Session not found")
|
||||||
|
|
||||||
db.delete_session(session_id, ctx=ctx)
|
db.delete_session(session_id, ctx=ctx)
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ async def token_info(credentials=Depends(bearer_auth)):
|
|||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise HTTPException(401, str(e))
|
raise HTTPException(401, str(e))
|
||||||
|
|
||||||
u = db.get_user_by_uuid(reset_token.user_uuid)
|
u = db.get_user_by_uuid(reset_token.user)
|
||||||
return {
|
return {
|
||||||
"token_type": reset_token.token_type,
|
"token_type": reset_token.token_type,
|
||||||
"display_name": u.display_name,
|
"display_name": u.display_name,
|
||||||
@@ -178,7 +178,7 @@ async def forward_authentication(
|
|||||||
.isoformat()
|
.isoformat()
|
||||||
.replace("+00:00", "Z")
|
.replace("+00:00", "Z")
|
||||||
),
|
),
|
||||||
"Remote-Credential": str(ctx.session.credential_uuid),
|
"Remote-Credential": str(ctx.session.credential),
|
||||||
}
|
}
|
||||||
return Response(status_code=204, headers=remote_headers)
|
return Response(status_code=204, headers=remote_headers)
|
||||||
except authz.AuthException as e:
|
except authz.AuthException as e:
|
||||||
@@ -239,7 +239,7 @@ async def api_user_info(
|
|||||||
raise HTTPException(401, str(e))
|
raise HTTPException(401, str(e))
|
||||||
|
|
||||||
return await userinfo.format_user_info(
|
return await userinfo.format_user_info(
|
||||||
user_uuid=session_record.user_uuid,
|
user_uuid=session_record.user,
|
||||||
auth=auth,
|
auth=auth,
|
||||||
session_record=session_record,
|
session_record=session_record,
|
||||||
request_host=request.headers.get("host"),
|
request_host=request.headers.get("host"),
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ async def user_update_display_name(
|
|||||||
raise HTTPException(status_code=400, detail="display_name required")
|
raise HTTPException(status_code=400, detail="display_name required")
|
||||||
if len(new_name) > 64:
|
if len(new_name) > 64:
|
||||||
raise HTTPException(status_code=400, detail="display_name too long")
|
raise HTTPException(status_code=400, detail="display_name too long")
|
||||||
db.update_user_display_name(s.user_uuid, new_name)
|
db.update_user_display_name(s.user, new_name)
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ async def api_logout_all(request: Request, response: Response, auth=AUTH_COOKIE)
|
|||||||
raise authz.AuthException(
|
raise authz.AuthException(
|
||||||
status_code=401, detail="Session expired", mode="login"
|
status_code=401, detail="Session expired", mode="login"
|
||||||
)
|
)
|
||||||
db.delete_sessions_for_user(s.user_uuid)
|
db.delete_sessions_for_user(s.user)
|
||||||
session.clear_session_cookie(response)
|
session.clear_session_cookie(response)
|
||||||
return {"message": "Logged out from all hosts"}
|
return {"message": "Logged out from all hosts"}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ async def api_delete_session(
|
|||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
target_session = db.get_session(session_id)
|
target_session = db.get_session(session_id)
|
||||||
if not target_session or target_session.user_uuid != current_session.user_uuid:
|
if not target_session or target_session.user != current_session.user:
|
||||||
raise HTTPException(status_code=404, detail="Session not found")
|
raise HTTPException(status_code=404, detail="Session not found")
|
||||||
|
|
||||||
db.delete_session(session_id)
|
db.delete_session(session_id)
|
||||||
@@ -137,7 +137,7 @@ async def api_create_link(
|
|||||||
token = passphrase.generate()
|
token = passphrase.generate()
|
||||||
expiry = expires()
|
expiry = expires()
|
||||||
db.create_reset_token(
|
db.create_reset_token(
|
||||||
user_uuid=s.user_uuid,
|
user_uuid=s.user,
|
||||||
passphrase=token,
|
passphrase=token,
|
||||||
expiry=expiry,
|
expiry=expiry,
|
||||||
token_type="device addition",
|
token_type="device addition",
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ async def websocket_register_add(
|
|||||||
f"The reset link for {passkey.instance.rp_name} is invalid or has expired"
|
f"The reset link for {passkey.instance.rp_name} is invalid or has expired"
|
||||||
)
|
)
|
||||||
s = await get_reset(reset)
|
s = await get_reset(reset)
|
||||||
user_uuid = s.user_uuid
|
user_uuid = s.user
|
||||||
else:
|
else:
|
||||||
# Require recent authentication for adding a new passkey
|
# Require recent authentication for adding a new passkey
|
||||||
ctx = await authz.verify(auth, perm=[], host=host, max_age="5m")
|
ctx = await authz.verify(auth, perm=[], host=host, max_age="5m")
|
||||||
user_uuid = ctx.session.user_uuid
|
user_uuid = ctx.session.user
|
||||||
s = ctx.session
|
s = ctx.session
|
||||||
|
|
||||||
# Get user information and determine effective user_name for this registration
|
# Get user information and determine effective user_name for this registration
|
||||||
@@ -113,7 +113,7 @@ async def websocket_authenticate(ws: WebSocket, auth=AUTH_COOKIE):
|
|||||||
if auth:
|
if auth:
|
||||||
try:
|
try:
|
||||||
session = await get_session(auth, host=host)
|
session = await get_session(auth, host=host)
|
||||||
session_user_uuid = session.user_uuid
|
session_user_uuid = session.user
|
||||||
credentials = db.get_credentials_by_user_uuid(session_user_uuid)
|
credentials = db.get_credentials_by_user_uuid(session_user_uuid)
|
||||||
credential_ids = (
|
credential_ids = (
|
||||||
[c.credential_id for c in credentials] if credentials else None
|
[c.credential_id for c in credentials] if credentials else None
|
||||||
|
|||||||
Reference in New Issue
Block a user