fix: remaining MEDIUM/LOW findings from 2026-07-21 audit rerun

- consume-invite: check-then-act race on single-use invite redemption —
  two concurrent redemptions could both pass the pre-check. Now guarded
  with an atomic updateMany(where: {code, usedById: null, revoked: false}).
- schema.prisma: added missing index on Report.targetPostId (used by
  admin.ts's groupBy/filter).
- RepostCard.tsx: reposter link used a raw <a> (full page reload) instead
  of next/link; the original poster's header had no link at all.
- Sidebar.tsx/MobileNav.tsx: removed the duplicated "set active pet on
  first load" effect — ActivePetInitializer already does this centrally
  and is mounted alongside both in the app layout.
- prisma.ts: removed the dead Vercel/Prisma Accelerate code path
  (PRISMA_ACCELERATE_URL is never set — this is a self-hosted Docker
  deployment) and the now-unused @prisma/extension-accelerate dependency.
- .env.example: corrected the NEXT_PUBLIC_APP_URL comment (Mux cors_origin
  is intentionally "*", not wired to it) and documented CRON_SECRET,
  which was missing despite both cron routes requiring it.
- reactions.ts: removed hasReacted/getCount — dead code with no frontend
  callers; getCount also duplicated the denormalized Post.reactionCount.
This commit is contained in:
admin committed 2026-07-22 19:34:18 +02:00
1 parent bf49024ace
commit 4fcde7eb2a
11 files changed
+358 -749

No files matched your search

+6 -2
View File
@@ -39,10 +39,14 @@ async function consumeInviteCode(userId: string, code: string) {
if (!invite || invite.usedById || invite.revoked) return;
await prisma.$transaction(async (tx) => {
await tx.inviteCode.update({
where: { code },
// Guard the update with usedById: null so a concurrent redemption of the
// same single-use code can't both pass the pre-check above and both
// succeed — only the transaction that wins the race actually flips it.
const claimed = await tx.inviteCode.updateMany({
where: { code, usedById: null, revoked: false },
data: { usedById: userId, usedAt: new Date() },
});
if (claimed.count === 0) return;
await tx.owner.upsert({
where: { id: userId },