Skip to content

fix(api): secure featured hunt routes and use postgres datastore - #1040

Open
Devadakene wants to merge 3 commits into
Samuel1-ona:mainfrom
Devadakene:fix/featured-hunt-auth-db
Open

fix(api): secure featured hunt routes and use postgres datastore#1040
Devadakene wants to merge 3 commits into
Samuel1-ona:mainfrom
Devadakene:fix/featured-hunt-auth-db

Conversation

@Devadakene

Copy link
Copy Markdown

Closes #858

Objective

This PR resolves a critical vulnerability and reliability issue with the "Featured Hunt" API routes. Previously, the /api/admin/featured and /api/admin/featured/rotate endpoints lacked proper authentication, allowing anonymous users to change the featured hunt. Additionally, the featured hunt state was being written to a local JSON file (featuredHuntServer.json) inside process.cwd(). This file-based approach silently failed in our serverless deployment environment because the filesystem is read-only, leading to state regressions upon every deployment.

This PR enforces admin authorization across these endpoints and migrates the featured hunt state to a robust PostgreSQL datastore.

Changes Implemented

1. Enforced Admin Authentication

  • Files Modified: apps/web/app/api/admin/featured/route.ts, apps/web/app/api/admin/featured/rotate/route.ts
  • Details: Integrated the assertAdminAuth(req) utility at the top of the GET and POST handlers for both the main featured route and the rotate route.
  • Impact: Ensures that only authenticated administrators can modify the featured hunt state. Unauthorized requests will now immediately throw an authorization error, which is caught and surfaced as a 401 Unauthorized or 403 Forbidden response.

2. Migrated State to PostgreSQL

  • Files Modified: apps/web/lib/featuredHuntDb.ts (and related migration scripts)
  • Details: Replaced the ephemeral file-based storage with a robust database implementation. The active featured hunt ID is now stored in the app_settings table under the featured_hunt_id key.
  • Impact:
    • The featured hunt state is now consistent across all serverless instances.
    • The state survives deployments and instance recycling.
    • Eliminates the silent write failures caused by read-only serverless filesystems.

3. Improved Error Handling

  • Files Modified: apps/web/lib/featuredHuntDb.ts, apps/web/app/api/admin/featured/rotate/route.ts
  • Details: Removed the logger.error swallow pattern. The writeFeaturedId function now executes direct raw SQL queries via getDb() and allows any database connection or query failures to throw exceptions naturally.
  • Impact: Database write failures are now accurately caught by the withErrorHandling higher-order wrapper, converting them into standardized HTTP 500 Internal Server Error responses with appropriate request IDs for tracing.

4. Consistent Application to Rotate Endpoint

  • Files Modified: apps/web/app/api/admin/featured/rotate/route.ts
  • Details: The rotation logic was updated to use the new readFeaturedId and writeFeaturedId database abstractions.
  • Impact: Ensures the round-robin selection of the next active seeded hunt is consistent across all instances and properly secured.

Acceptance Criteria Validated

  • Admin authentication is enforced on all relevant API endpoints.
  • Featured-hunt state moves to a real datastore (PostgreSQL app_settings table) instead of a file under process.cwd().
  • Write failures surface as errors (HTTP 500) rather than being swallowed into logger.error.
  • The identical fix is applied to the /api/admin/featured/rotate endpoint.

How to Test

  1. Unauthenticated Access: Attempt to send a POST request to /api/admin/featured and /api/admin/featured/rotate without valid admin credentials. Verify that the request is rejected.
  2. Authenticated Access: Send a valid POST request with a huntId to /api/admin/featured. Verify that the request succeeds and the new featured hunt ID is returned in a subsequent GET request.
  3. Database Verification: Query the app_settings table in your local Postgres database and verify that the featured_hunt_id key exists and matches the ID you set.
  4. Rotation Testing: Hit the /api/admin/featured/rotate endpoint as an admin. Verify that the featured hunt successfully advances to the next active seeded hunt, and that the database is updated accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SECURITY] /api/admin/featured is unauthenticated and writes to the filesystem

1 participant