diff options
| author | Fuwn <[email protected]> | 2026-02-08 09:21:50 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-08 09:21:50 -0800 |
| commit | 396c3f450e0f17b77478a0525029aa2534e764a9 (patch) | |
| tree | ac6d5f30c4cac6a7e9d07045d15b8388cd19791d /apps/web/app/api/share | |
| parent | security: harden database functions and policies (diff) | |
| download | asa.news-396c3f450e0f17b77478a0525029aa2534e764a9.tar.xz asa.news-396c3f450e0f17b77478a0525029aa2534e764a9.zip | |
security: harden API routes
- Add rate limiting to /api/share (30/min), /api/export (5/hr),
/api/account/data (3/day)
- Add client-side 30s throttle to forgot-password form
- Remove immediate tier upgrade on plan change; let invoice.paid
webhook handle tier promotion to prevent free upgrades on payment
failure
- Add SSRF validation to webhook URLs: block localhost, private IPs,
link-local, and metadata endpoints
- Log Stripe webhook signature verification errors instead of
swallowing silently
- Mask webhook secret in GET response (show first/last 4 chars only)
- Add error logging to API key last_used_at update
- Remove internal error message leaking from checkout session route
Diffstat (limited to 'apps/web/app/api/share')
| -rw-r--r-- | apps/web/app/api/share/route.ts | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/apps/web/app/api/share/route.ts b/apps/web/app/api/share/route.ts index 324d1e9..5f67bc6 100644 --- a/apps/web/app/api/share/route.ts +++ b/apps/web/app/api/share/route.ts @@ -2,6 +2,7 @@ import { NextResponse } from "next/server" import { randomBytes } from "crypto" import { createSupabaseServerClient } from "@/lib/supabase/server" import { checkBotId } from "botid/server" +import { rateLimit } from "@/lib/rate-limit" const MAX_NOTE_LENGTH = 1000 @@ -27,6 +28,11 @@ export async function POST(request: Request) { return NextResponse.json({ error: "not authenticated" }, { status: 401 }) } + const rateLimitResult = rateLimit(`share:${user.id}`, 30, 60_000) + if (!rateLimitResult.success) { + return NextResponse.json({ error: "too many requests" }, { status: 429 }) + } + const { data: userProfile } = await supabaseClient .from("user_profiles") .select("tier") |