Skip to content

Server-side checkPermGate Member case does not verify membership #290

@evoskamp

Description

@evoskamp

Problem

The server-side checkPermGate helper in packages/server/src/api/routers/games.ts returns true for the Member perm-gate value without actually verifying the user has an active membership record.

The frontend equivalent (getFlagBoolean in packages/amber/utils/settings.tsx) checks isAdmin || isMember, where isMember verifies the user has an active membership for the current year.

This semantic mismatch means that when a perm-gate flag is set to Member, any authenticated user passes the server-side check, even if they don't have a membership.

Current behavior

case 'Member':
  return true  // Any authenticated user passes

Expected behavior

case 'Member': {
  if (isAdmin || isGameAdmin) return true
  if (!userId) return false
  const membership = await tx.membership.findFirst({
    where: { userId, attending: true },
  })
  return membership !== null
}

Risk

Currently low risk because the flags gated by checkPermGate (allow_game_submission, allow_game_editing) are unlikely to be set to Member in practice. However, if the helper is reused for other perm-gate flags, the mismatch could become a real authorization gap.

Context

Found during code review of PR #289.

References: #182

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions