From d757602e7c48841e280b572721dd717c6d2ddaf3 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Mon, 20 Jul 2026 18:27:29 +0800 Subject: [PATCH] fix: reject array profile payloads --- frontend/src/app/api/account/route.ts | 2 +- frontend/src/app/api/chart-profiles/route.ts | 2 +- tests/test_supabase_user_data_contract.py | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/api/account/route.ts b/frontend/src/app/api/account/route.ts index 0a8daad6..e4da60b5 100644 --- a/frontend/src/app/api/account/route.ts +++ b/frontend/src/app/api/account/route.ts @@ -95,7 +95,7 @@ export async function PATCH(request: Request) { } const payload = await request.json().catch(() => null) as ProfilePatchPayload | null; - if (!payload || typeof payload !== "object") { + if (!payload || typeof payload !== "object" || Array.isArray(payload)) { return NextResponse.json({ error: "账户资料格式不正确" }, { status: 400 }); } diff --git a/frontend/src/app/api/chart-profiles/route.ts b/frontend/src/app/api/chart-profiles/route.ts index af08e3c4..a9f37060 100644 --- a/frontend/src/app/api/chart-profiles/route.ts +++ b/frontend/src/app/api/chart-profiles/route.ts @@ -41,7 +41,7 @@ export async function POST(request: Request) { if (!user) return NextResponse.json({ error: "请先登录" }, { status: 401 }); const body = await request.json().catch(() => null) as ChartProfilePayload | null; - if (!body?.profile || typeof body.profile !== "object") { + if (!body?.profile || typeof body.profile !== "object" || Array.isArray(body.profile)) { return NextResponse.json({ error: "星盘资料格式不正确" }, { status: 400 }); } const role = body.role === "self" ? "self" : "other"; diff --git a/tests/test_supabase_user_data_contract.py b/tests/test_supabase_user_data_contract.py index e51b43fb..43e7000b 100644 --- a/tests/test_supabase_user_data_contract.py +++ b/tests/test_supabase_user_data_contract.py @@ -38,6 +38,7 @@ SYNASTRY_REPORT_MIGRATION = ( / "20260718101000_repair_missing_synastry_reports.sql" ) PAGE = Path(__file__).resolve().parents[1] / "frontend" / "src" / "app" / "page.tsx" +ACCOUNT_ROUTE = Path(__file__).resolve().parents[1] / "frontend" / "src" / "app" / "api" / "account" / "route.ts" CHART_PROFILE_ROUTE = Path(__file__).resolve().parents[1] / "frontend" / "src" / "app" / "api" / "chart-profiles" / "route.ts" CHART_PROFILE_DELETE_ROUTE = Path(__file__).resolve().parents[1] / "frontend" / "src" / "app" / "api" / "chart-profiles" / "[id]" / "route.ts" SYNASTRY_ROUTE = Path(__file__).resolve().parents[1] / "frontend" / "src" / "app" / "api" / "synastry" / "route.ts" @@ -115,6 +116,12 @@ def test_chat_page_uses_authenticated_cloud_persistence() -> None: assert 'localStorage.setItem("chat_sessions"' not in source +def test_account_profile_patch_rejects_array_payloads() -> None: + route = ACCOUNT_ROUTE.read_text(encoding="utf-8") + assert 'typeof payload !== "object" || Array.isArray(payload)' in route + assert "账户资料格式不正确" in route + + def test_chart_profile_library_has_cloud_table_api_and_local_fallback() -> None: sql = re.sub(r"\s+", " ", CHART_PROFILE_MIGRATION.read_text(encoding="utf-8").lower()).strip() route = CHART_PROFILE_ROUTE.read_text(encoding="utf-8") @@ -140,6 +147,7 @@ def test_chart_profile_library_has_cloud_table_api_and_local_fallback() -> None: 'from("chart_profiles")', 'eq("user_id", user.id)', 'eq("role", "self")', + "Array.isArray(body.profile)", 'insert({ user_id: user.id, role, profile: body.profile', 'insert({ user_id: user.id, role, profile: body.profile, updated_at: updatedAt })', ):