revoke_self and revoke_device each loaded the caller's DeviceToken, deleted it, committed and audited DEVICE_UNLINKED; _unlink_device(which) is that, owner-scoped as before, with each route keeping only how it names the row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+9
-18
@@ -659,21 +659,9 @@ async def revoke_own_device():
|
|||||||
# using" is meaningless rather than merely unauthorized. The web app
|
# using" is meaningless rather than merely unauthorized. The web app
|
||||||
# revokes by id.
|
# revokes by id.
|
||||||
return json_error("no device token was presented", 400)
|
return json_error("no device token was presented", 400)
|
||||||
async with session_scope() as db:
|
# Owner-scoped like every other device route. The hash already pins a single
|
||||||
row = await db.scalar(
|
# row; the guarantee shouldn't rest on one column.
|
||||||
select(DeviceToken).where(
|
return await _unlink_device(DeviceToken.token_hash == hash_token(token))
|
||||||
DeviceToken.token_hash == hash_token(token),
|
|
||||||
# Owner-scoped like every other device route. The hash already pins
|
|
||||||
# a single row; the guarantee shouldn't rest on one column.
|
|
||||||
DeviceToken.user_id == g.user_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if row is None:
|
|
||||||
return not_found()
|
|
||||||
await db.delete(row)
|
|
||||||
await db.commit()
|
|
||||||
await audit.record(audit.DEVICE_UNLINKED, user_id=g.user_id, email=await _email_of(db), detail=row.name)
|
|
||||||
return jsonify({"ok": True})
|
|
||||||
|
|
||||||
|
|
||||||
@bp.delete("/devices/<device_id>")
|
@bp.delete("/devices/<device_id>")
|
||||||
@@ -682,10 +670,13 @@ async def revoke_device(device_id: str):
|
|||||||
did = parse_uuid(device_id)
|
did = parse_uuid(device_id)
|
||||||
if did is None:
|
if did is None:
|
||||||
return not_found()
|
return not_found()
|
||||||
|
return await _unlink_device(DeviceToken.id == did)
|
||||||
|
|
||||||
|
|
||||||
|
async def _unlink_device(which):
|
||||||
|
"""Delete the caller's device token matching `which`, and say so in the audit log."""
|
||||||
async with session_scope() as db:
|
async with session_scope() as db:
|
||||||
row = await db.scalar(
|
row = await db.scalar(select(DeviceToken).where(which, DeviceToken.user_id == g.user_id))
|
||||||
select(DeviceToken).where(DeviceToken.id == did, DeviceToken.user_id == g.user_id)
|
|
||||||
)
|
|
||||||
if row is None:
|
if row is None:
|
||||||
return not_found()
|
return not_found()
|
||||||
await db.delete(row)
|
await db.delete(row)
|
||||||
|
|||||||
Reference in New Issue
Block a user