From b329026cc9d5fda73ac024b2ee92f1127e3ff47a Mon Sep 17 00:00:00 2001 From: rissrice2105-agent <289161642+rissrice2105-agent@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:31:48 -0600 Subject: [PATCH] fix(comments): validate pagination params --- .../api/torrents/[id]/comments/route.test.ts | 19 +++++++++++++++++++ src/app/api/torrents/[id]/comments/route.ts | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/app/api/torrents/[id]/comments/route.test.ts b/src/app/api/torrents/[id]/comments/route.test.ts index 5bad00f4..a522fe24 100644 --- a/src/app/api/torrents/[id]/comments/route.test.ts +++ b/src/app/api/torrents/[id]/comments/route.test.ts @@ -134,6 +134,25 @@ describe('Torrent Comments API', () => { expect(mockService.getCommentsWithUserVotes).toHaveBeenCalledWith(TEST_TORRENT_ID, null, 10, 20); }); + it('should fall back to safe pagination for malformed params', async () => { + const mockService = { + getCommentsWithUserVotes: vi.fn().mockResolvedValue([]), + getCommentCount: vi.fn().mockResolvedValue(0), + }; + + (getCommentsService as ReturnType).mockReturnValue(mockService); + (getActiveProfileId as ReturnType).mockResolvedValue(null); + + const request = new NextRequest( + `http://localhost/api/torrents/${TEST_TORRENT_ID}/comments?limit=10items&offset=-20` + ); + const response = await GET(request, { params: Promise.resolve({ id: TEST_TORRENT_ID }) }); + + expect(response.status).toBe(200); + expect(mockService.getCommentsWithUserVotes).toHaveBeenCalledWith(TEST_TORRENT_ID, null, 50, 0); + await expect(response.json()).resolves.toMatchObject({ limit: 50, offset: 0 }); + }); + it('should return 400 for missing torrent ID', async () => { const request = new NextRequest('http://localhost/api/torrents//comments'); const response = await GET(request, { params: Promise.resolve({ id: '' }) }); diff --git a/src/app/api/torrents/[id]/comments/route.ts b/src/app/api/torrents/[id]/comments/route.ts index 95ced6d2..0eb0b1a8 100644 --- a/src/app/api/torrents/[id]/comments/route.ts +++ b/src/app/api/torrents/[id]/comments/route.ts @@ -12,6 +12,7 @@ import { NextRequest, NextResponse } from 'next/server'; import { getCommentsService } from '@/lib/comments'; import { getAuthenticatedUser } from '@/lib/auth'; import { getActiveProfileId } from '@/lib/profiles/profile-utils'; +import { parseIntegerParam } from '@/lib/api/pagination'; interface RouteParams { params: Promise<{ id: string }>; @@ -50,8 +51,8 @@ export async function GET( // Parse pagination params const searchParams = request.nextUrl.searchParams; - const limit = parseInt(searchParams.get('limit') ?? '50', 10); - const offset = parseInt(searchParams.get('offset') ?? '0', 10); + const limit = parseIntegerParam(searchParams.get('limit'), { min: 1, max: 100 }) ?? 50; + const offset = parseIntegerParam(searchParams.get('offset'), { min: 0 }) ?? 0; // DHT torrents (non-UUID IDs) don't support comments // Return empty results instead of failing