Skip to content

Commit 468d637

Browse files
committed
paginate me pastes and enforce paste size limit for hastebin endpoint
1 parent 5269393 commit 468d637

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

mystbin/backend/routers/pastes.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ async def get_paste(request: MystbinRequest, paste_id: str, password: Optional[s
317317
response_model=List[responses.PasteGetAllResponse],
318318
responses={
319319
200: {"model": Optional[List[responses.PasteGetAllResponse]]},
320+
400: {"content": {"application/json": {"example": {"error": "You have provided an invalid query argument"}}}},
320321
401: {"model": errors.Unauthorized},
321322
},
322323
name="Get user pastes",
@@ -325,13 +326,17 @@ async def get_paste(request: MystbinRequest, paste_id: str, password: Optional[s
325326
@limit("getpaste")
326327
async def get_all_pastes(
327328
request: MystbinRequest,
328-
limit: Optional[int] = None,
329+
limit: int = 50,
330+
page: int = 1
329331
) -> Union[UJSONResponse, Dict[str, List[Dict[str, str]]]]:
330332
user = request.state.user
331333
if not user:
332334
return UJSONResponse({"error": "Unathorized", "notice": "You must be signed in to use this route"}, status_code=401)
335+
336+
if limit < 1 or page < 1:
337+
return UJSONResponse({"error": "limit and page must be greater than 1"}, status_code=400)
333338

334-
pastes = await request.app.state.db.get_all_user_pastes(user["id"], limit)
339+
pastes = await request.app.state.db.get_all_user_pastes(user["id"], limit, page)
335340
pastes = [dict(entry) for entry in pastes]
336341

337342
return UJSONResponse({"pastes": jsonable_encoder(pastes)})
@@ -450,7 +455,7 @@ async def delete_paste(request: MystbinRequest, paste_id: str) -> Union[UJSONRes
450455
403: {"model": errors.Forbidden},
451456
},
452457
status_code=200,
453-
name="Delete multiple pastes",
458+
name="Bulk delete pastes",
454459
description=desc,
455460
)
456461
@limit("deletepaste")
@@ -490,13 +495,20 @@ async def delete_pastes(
490495
"/documents",
491496
tags=["pastes"],
492497
deprecated=True,
493-
response_description='{"key": "string"}',
498+
responses={
499+
200: {"application/json": {"example": {"key": "string"}, "description": "A key containing the slug for your paste"}},
500+
400: {"application/json": {"example": {"error": "You have provided an invalid paste body"}}}
501+
},
494502
name="Hastebin create paste",
495503
description=desc,
496504
)
497505
@limit("postpastes")
498506
async def compat_create_paste(request: MystbinRequest):
499507
content = await request.body()
508+
limit = request.app.config["paste"]["character_limit"]
509+
if len(content) > limit:
510+
return UJSONResponse({"error": f"body: file size exceeds character limit of {limit}"}, status_code=400)
511+
500512
paste: Record = await request.app.state.db.put_paste(
501513
paste_id=generate_paste_id(),
502514
pages=[payloads.PasteFile(filename="file.txt", content=content.decode("utf8"))],

mystbin/backend/utils/db.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ async def _do_query(
118118
except asyncio.TimeoutError:
119119
return None
120120
else:
121+
return response
122+
finally:
121123
if not conn:
122124
await self.pool.release(_conn)
123125

124-
return response
125-
126126
@wrapped_hook_callback
127127
async def get_all_pastes(self, page: int, count: int, reverse=False) -> List[Dict[str, Any]]:
128128
"""
@@ -388,7 +388,7 @@ async def set_paste_password(self, paste_id: str, password: str | None) -> Optio
388388
return None
389389

390390
@wrapped_hook_callback
391-
async def get_all_user_pastes(self, author_id: Optional[int], limit: Optional[int] = None) -> List[asyncpg.Record]:
391+
async def get_all_user_pastes(self, author_id: Optional[int], limit: int, page: int) -> List[asyncpg.Record]:
392392
"""Get all pastes for an author and/or with a limit.
393393
Parameters
394394
------------
@@ -409,9 +409,13 @@ async def get_all_user_pastes(self, author_id: Optional[int], limit: Optional[in
409409
WHERE author_id = $1
410410
ORDER BY created_at DESC
411411
LIMIT $2
412+
OFFSET $3
412413
"""
413414

414-
response = await self._do_query(query, author_id, limit)
415+
assert page > 1 and limit > 1, ValueError("limit and page cannot be smaller than 1")
416+
response = await self._do_query(query, author_id, limit, page - 1)
417+
if not response:
418+
return []
415419

416420
return response
417421

0 commit comments

Comments
 (0)