From 8b4ab415fdacd124c834e1915b03a45bba9fa1fd Mon Sep 17 00:00:00 2001 From: kurihada Date: Tue, 3 Mar 2026 12:06:03 +0800 Subject: [PATCH] fix: validate swipe restaurant ids against room candidates --- PROJECT_AUDIT_2026-03-03.md | 7 ++++++- src/app/api/room/[id]/swipe/route.test.ts | 15 +++++++++++++++ src/app/api/room/[id]/swipe/route.ts | 4 +++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/PROJECT_AUDIT_2026-03-03.md b/PROJECT_AUDIT_2026-03-03.md index 517c5b7..3ed65a0 100644 --- a/PROJECT_AUDIT_2026-03-03.md +++ b/PROJECT_AUDIT_2026-03-03.md @@ -38,7 +38,12 @@ - 后端补充房间号格式校验与明确错误提示; - 增加 E2E 用例覆盖“手输邀请码加入”。 -### P0-2 投票接口未校验 `restaurantId` 是否属于房间候选列表(可污染房间状态) +### P0-2 投票接口未校验 `restaurantId` 是否属于房间候选列表(可污染房间状态)【已完成】 +- 修复状态:✅ 已完成(2026-03-03) +- 修复内容: + - `POST /api/room/[id]/swipe` 增加 `restaurantId` 必须属于当前房间候选列表的强校验; + - 对非法 `restaurantId` 返回 400; + - 增加对应 API 测试用例,防止状态污染回归。 - 证据: - `src/app/api/room/[id]/swipe/route.ts:25`(仅查 index) - `src/app/api/room/[id]/swipe/route.ts:32-42`(即使 `restaurantIndex === -1` 仍可写入 `likes` 并可能设置 `match`) diff --git a/src/app/api/room/[id]/swipe/route.test.ts b/src/app/api/room/[id]/swipe/route.test.ts index 0e62941..cf9e5b4 100644 --- a/src/app/api/room/[id]/swipe/route.test.ts +++ b/src/app/api/room/[id]/swipe/route.test.ts @@ -113,6 +113,21 @@ describe("POST /api/room/[id]/swipe", () => { expect(res.status).toBe(400); }); + it("returns 400 when restaurantId is not in room candidates", async () => { + mockAtomicUpdate.mockImplementation(async (_id, updater) => { + const data = structuredClone(TEST_ROOM_DATA); + return updater(data); + }); + + const req = createRequest("/api/room/ROOM01/swipe", { + method: "POST", + body: { userId: "user-1", restaurantId: "unknown-id", action: "like" }, + }); + const ctx = createRouteContext({ id: "ROOM01" }); + const res = await POST(req, ctx); + expect(res.status).toBe(400); + }); + it("returns 404 when room not found", async () => { mockAtomicUpdate.mockResolvedValue(null); diff --git a/src/app/api/room/[id]/swipe/route.ts b/src/app/api/room/[id]/swipe/route.ts index a84f380..390a2d4 100644 --- a/src/app/api/room/[id]/swipe/route.ts +++ b/src/app/api/room/[id]/swipe/route.ts @@ -23,8 +23,10 @@ export const POST = apiHandler(async (req, { params }) => { } const restaurantIndex = data.restaurants.findIndex((r) => r.id === rid); + if (restaurantIndex < 0) { + throw new ApiError("restaurantId 不存在于该房间候选列表", 400); + } const alreadySwiped = - restaurantIndex >= 0 && restaurantIndex < (data.swipeCounts[userId] ?? 0); if (alreadySwiped) return data;