Skip to content

Commit

Permalink
api: check ownership in unsubscribe endpoint
Browse files Browse the repository at this point in the history
Let a user unsubscribe only from his/her own subscriptions. Prior to
this change, anyone could unsubscribe anybody else from whatever active
subscription.

Signed-off-by: Ricardo Cañuelo <[email protected]>
  • Loading branch information
Ricardo Cañuelo committed Dec 1, 2023
1 parent 4305111 commit 8be9929
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 3 deletions.
7 changes: 6 additions & 1 deletion api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,17 @@ async def subscribe(channel: str, user: User = Depends(get_current_user)):
async def unsubscribe(sub_id: int, user: User = Depends(get_current_user)):
"""Unsubscribe handler for Pub/Sub channel"""
try:
await pubsub.unsubscribe(sub_id)
await pubsub.unsubscribe(sub_id, user.username)
except KeyError as error:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Subscription id not found: {str(error)}"
) from error
except RuntimeError as error:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(error)
) from error


@app.get('/listen/{sub_id}')
Expand Down
11 changes: 9 additions & 2 deletions api/pubsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,21 @@ async def subscribe(self, channel, user=None):
self._start_keep_alive_timer()
return sub

async def unsubscribe(self, sub_id):
async def unsubscribe(self, sub_id, user=None):
"""Unsubscribe from a Pub/Sub channel
Unsubscribe from a channel using the provided subscription id as found
in a Subscription object.
"""
async with self._lock:
sub = self._subscriptions.pop(sub_id)
if sub_id not in self._subscriptions:
raise KeyError(sub_id)
sub = self._subscriptions[sub_id]
if user and user != sub['sub'].user:
# Subscription is from a different user
raise RuntimeError(f"Subscription {sub_id} "
f"not owned by {user}")
self._subscriptions.pop(sub_id)
self._update_channels()
await sub['redis_sub'].unsubscribe()

Expand Down

0 comments on commit 8be9929

Please sign in to comment.