mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
fix(admin): harden the Danger-Zone wipe to match the Backups Restore gate
The global data wipe auto-supplied confirm:'DELETE ALL' from a single-click dialog, leaving the server's typed-token defence dead and making the most destructive action a weaker gate than the less-destructive restore. Mirror RestoreRowDialog: require typing 'DELETE ALL' into an Input that arms the destructive button, reset on close. Also attach an Idempotency-Key header to the wipe so a double-submit cannot re-run the transaction, add the documented post-requireAdmin() 'admin-data-delete:<userId>' rate-limit bucket alongside the anonymous IP throttle, and switch BackupsSection off the non-reactive formatDateTime onto the locale-reactive useFormatters() hook its siblings use.
This commit is contained in:
1 parent
e23f57448a
commit
88c4a8428f
9 files changed
+81
-7
No files matched your search
@@ -26,6 +26,22 @@ export const DELETE = apiHandler(async (request: NextRequest) => {
|
||||
const { user } = await requireAdmin();
|
||||
annotate({ action: { name: "admin.data.delete" } });
|
||||
|
||||
// v1.18.1 — the documented convention buckets authenticated admin
|
||||
// mutations on `userId`, not the (pre-auth, spoofable) client IP. The
|
||||
// IP bucket above is the anonymous first-line throttle; this is the
|
||||
// canonical per-admin bucket the rate-limit contract specifies.
|
||||
const userRl = await checkRateLimit(
|
||||
`admin-data-delete:${user.id}`,
|
||||
5,
|
||||
60 * 1000,
|
||||
);
|
||||
if (!userRl.allowed) {
|
||||
return NextResponse.json(
|
||||
{ data: null, error: "Rate limit exceeded" },
|
||||
{ status: 429, headers: rateLimitHeaders(userRl) },
|
||||
);
|
||||
}
|
||||
|
||||
let confirm = "";
|
||||
try {
|
||||
const raw = await request.text();
|
||||
|
||||
Reference in new issue
Block a user