Commit graph

6 commits

Author SHA1 Message Date
Randall Stillwell
51a3a970e0 feat(security): rate-limit search/upload/import + gate import routes (P0 #6)
Closes P0 #6 (no rate limiting) from PARTIAL → RESOLVED. With
this merge, all 8 P0 ship-blockers are RESOLVED. fix-auth-bypass
Brief 4 shipped lib/rate-limit.js with a single 5/15min auth
limiter wired into login + register; this brief extends the
module to 5 named limiters (auth/search/upload/generate/import)
and wires them into the remaining abusable surface.

Per architect Decision 1 — Option A (gate all 3 import routes
uniformly). The architect's investigation found a critical
secondary bug: pages/admin/card-import.js's fetch sends NO
Authorization header today. Adding getUserFromRequest to the
import APIs without fixing the admin UI atomically would have
returned 401 on every "Import Cards" click. Both edits ship in
this single commit — API gating + admin UI Bearer fix — for
atomic safety. Lorcana is dead in frontend today (only
scripts/import-lorcana.js uses that path) but gated uniformly
to future-proof per AGENTS.md § 1 status; a
delete-dead-lorcana-import follow-up convoy is queued for later
if we decide to drop Lorcana entirely.

Per Decision 2 — hybrid named-limiter shape in lib/rate-limit.js.
checkAuthRateLimit(req) signature + return shape preserved
verbatim (don't break Brief 4's contract); 4 new named functions
added (checkSearchRateLimit, checkUploadRateLimit,
checkGenerateRateLimit, checkImportRateLimit). Map<className,
Ratelimit> cache, per-class Redis prefix (tcgvault:auth,
tcgvault:search, tcgvault:upload, tcgvault:generate,
tcgvault:import) so each class has its own budget.

Per Decision 3 — per-class limit values tuned with evidence:
  auth      5  / 15min  IP-keyed   (unchanged from Brief 4)
  search    60 / 1min   IP-keyed   (bumped from 30 — ShareModal
                                    has no debounce; 17-char email
                                    = 16 requests in <5s)
  upload    10 / 1hr    user-keyed
  generate  5  / 1hr    user-keyed (DiceBear is free, kept at 5)
  import    5  / 1hr    user-keyed (admin-only; external APIs
                                    have their own limits)

Per Decision 4 — two extractors. extractIpIdentifier (existing,
unchanged) and extractUserIdentifier (new). The new one THROWS on
null/undefined/empty/NaN userId to prevent silent fallback-to-IP
(which would convert per-user limits into per-IP and lock out
households). Architect's R-finding: places the gate AFTER the
auth check on every per-user-keyed route, never before.

Per Decision 5 — uniform 429 response shape verbatim matching
login.js/register.js: Retry-After header + JSON
{ error: 'Too many attempts. Try again later.' }. Anti-
fingerprinting (per-class messages would tell an attacker which
classes have which limits).

Per Decision 6 — no new per-route handler tests this convoy.
Vitest 21/21 unchanged at merge.

Verification:
  - npm run lint: 128 problems (baseline match)
  - npm run test:run: 21/21 vitest pass (no regression;
    auth-utils tests don't transitively load rate-limit per
    architect D6 evidence)
  - 5 named limiter exports verified via per-route grep counts
  - Admin UI sends Authorization: Bearer <token> from
    localStorage in the import fetch (matching pattern from
    other admin pages)
  - Brief 4's login.js + register.js byte-identical at HEAD
  - .cursor/rules/api-routes.mdc § Rate limiting extended with
    per-class table + gate-ordering rules

No new dependencies (Brief 4's @upstash/ratelimit + @upstash/redis
suffice). No workflow YAML changes. No AGENTS.md edits (doc-
writer pass at convoy close handles Gotcha #12 update + § 6
testing update + ship-readiness Status summary 7/8 → 8/8).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 22:46:27 -05:00
varutasu
da50d78406
fix(security): drop wildcard CORS + redundant OPTIONS from 24 API routes (P0 #5)
Closes P0 #5 from PARTIAL to RESOLVED. Sweeps the remaining 24 pages/api/** handlers that carried the identical scaffolded wildcard-CORS + OPTIONS preflight pattern (Brief 4 cleaned login + register; this finishes the job). Adds a blocking forbidden-cors-headers CI job modeled on forbidden-endpoints to lock the cleanup against future regression. 25 files changed (+29/-261). Local: lint 128 baseline, vitest 21/21, zero CORS matches, YAML valid. CI: Playwright smoke 3/3 in 3.3s against post-removal preview (login/verify flow still works), new forbidden-cors-headers job passes in 4s, all gates green. PR #19 architect-commit ec22b70, implementer-commit a843736.
2026-05-24 20:41:38 -05:00
Randall Stillwell
a7ee884d02 🖼️ Complete Avatar Upload System with Vercel Blob
📤 Avatar Upload API (/api/user/avatar):
- File upload with multipart form data parsing
- Comprehensive validation (file type, size limits)
- Support for JPEG, PNG, GIF, WebP images up to 5MB
- Automatic cleanup of old avatars before new uploads
- Vercel Blob integration with public access
- Database tracking in user_avatars table
- Error handling for upload failures

🎨 Avatar Generation API (/api/user/avatar/generate):
- Custom avatar generation using DiceBear API
- Fire-themed color scheme (matching app branding)
- Personalized based on user initials/username/email
- SVG format for crisp display at any size
- Automatic fallback if generation fails
- Same cleanup and storage workflow as uploads

🗑️ Account Deletion API (/api/user/delete):
- Complete user data cleanup including Vercel Blob files
- Cascading deletion respecting foreign key constraints
- Admin account protection (prevents self-deletion)
- Comprehensive cleanup order:
  * User avatars from Vercel Blob storage
  * Deck cards, decks, collection cards, collections
  * User cards, avatar records, settings
  * Finally the user account itself
- Detailed logging for audit trail
- Graceful error handling with specific error messages

🔧 Technical Features:
- Custom multipart form data parser for file uploads
- Vercel Blob put/del operations with error handling
- Unique filename generation with timestamps
- Database transaction-like cleanup for deletions
- File type validation and size limits
- Proper CORS headers for all endpoints

🎯 Integration Ready:
- Works seamlessly with existing profile page UI
- Supports both upload and generate avatar buttons
- Returns avatar URLs for immediate display
- Database consistency with user profile system
- Production-ready error handling and validation

The avatar system is now fully functional with Vercel Blob! 📸
2025-07-26 21:39:42 -05:00
Randall Stillwell
afec905856 🎯 Build Comprehensive User Profile & Settings System
👤 Profile Page Features:
- Complete user profile with avatar, name, username, bio, and email
- Avatar upload with file validation (5MB limit, image types only)
- Avatar generation functionality for custom avatars
- Favorite games selection (MTG, Pokemon, Lorcana)
- Collection statistics display (total cards, collections, decks, value)
- Profile editing with real-time validation
- Member since date and role display

⚙️ Settings Page Features:
- Multi-section tabbed interface (Account, Security, Preferences, Notifications, Display)
- Account settings: email (read-only), collection visibility, preferred currency
- Security settings: password change with validation, 2FA toggle, account deletion
- Preferences: cards per page (25/50/100), default view (grid/list)
- Notifications: email notifications, marketing emails (toggle switches)
- Display settings: theme (light/dark/system), language selection

🗄️ Database Schema Updates:
- Added user profile fields: first_name, last_name, username, bio, avatar_url
- Added preference fields: favorite_games (JSONB), collection_visibility, preferred_currency, cards_per_page, default_view
- Added notification settings: notifications_email, notifications_marketing, two_factor_enabled
- Added display settings: theme, language
- Created user_settings table for complex settings
- Created user_avatars table for avatar management
- Added performance indexes and data validation constraints

📡 API Endpoints Created:
- GET/PUT /api/user/profile - Profile information management
- GET/PUT /api/user/settings - Settings and preferences management
- PUT /api/user/password - Secure password change with bcrypt validation
- GET /api/user/stats - Collection statistics and analytics

🔒 Security & Validation:
- Password change requires current password verification
- Username uniqueness validation
- Input validation for all enum fields (currency, theme, view mode, etc.)
- Proper error handling and user feedback
- Authentication required for all user endpoints

🎨 UI/UX Features:
- Beautiful fire-themed design matching app branding
- Responsive design for mobile and desktop
- Loading states and success/error messages
- Avatar placeholder with user initials
- Tabbed settings interface with icons
- Toggle switches for boolean settings
- Form validation with helpful error messages

 Additional Features:
- Collection stats with game/rarity breakdowns
- Recent activity tracking
- Danger zone for account deletion with double confirmation
- Member since display with formatted dates
- Currency formatting for collection values
- Game icons and themed styling throughout

The profile and settings system is now fully functional with comprehensive user management! 👨‍💻
2025-07-26 18:05:55 -05:00
Randall Stillwell
7be41b4490 Clean slate: Remove React traces and create pure Next.js setup 2025-07-23 09:32:31 -05:00
Randall Stillwell
2cc332e0a0 Move API routes to pages/api/ for proper Next.js structure 2025-07-23 08:27:14 -05:00