diff --git a/api/admin/index.js b/api/admin/index.js index c2e059c..8c9d722 100644 --- a/api/admin/index.js +++ b/api/admin/index.js @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server'; import { sql } from '@vercel/postgres'; -import { verifyToken } from '../setup-auth.js'; +import { verifyToken, isAdmin } from '../auth-utils.js'; // Rate limiting for external APIs const rateLimiters = { @@ -291,6 +291,10 @@ export async function GET(request) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } + if (!isAdmin(user)) { + return NextResponse.json({ error: 'Admin access required' }, { status: 403 }); + } + const { searchParams } = new URL(request.url); const action = searchParams.get('action'); @@ -353,6 +357,10 @@ export async function POST(request) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } + if (!isAdmin(user)) { + return NextResponse.json({ error: 'Admin access required' }, { status: 403 }); + } + const { searchParams } = new URL(request.url); const action = searchParams.get('action'); diff --git a/api/auth-utils.js b/api/auth-utils.js new file mode 100644 index 0000000..c709d62 --- /dev/null +++ b/api/auth-utils.js @@ -0,0 +1,53 @@ +import jwt from 'jsonwebtoken'; +import { sql } from '@vercel/postgres'; + +export async function verifyToken(token) { + if (!token) { + return null; + } + + try { + const jwtSecret = process.env.JWT_SECRET || 'fallback-secret-change-in-production'; + const decoded = jwt.verify(token, jwtSecret); + + // Get user from database + const result = await sql.query(` + SELECT + up.user_id, + up.username, + up.email, + up.first_name, + up.last_name, + up.avatar_url, + up.roles, + up.created_at, + up.updated_at + FROM user_preferences up + WHERE up.user_id = $1 + `, [decoded.userId]); + + if (result.rows.length === 0) { + return null; + } + + const user = result.rows[0]; + return { + id: user.user_id, + username: user.username, + email: user.email, + firstName: user.first_name, + lastName: user.last_name, + avatarUrl: user.avatar_url, + roles: user.roles || [], + createdAt: user.created_at, + updatedAt: user.updated_at + }; + } catch (error) { + console.error('Token verification failed:', error); + return null; + } +} + +export function isAdmin(user) { + return user && user.roles && user.roles.includes('admin'); +} \ No newline at end of file diff --git a/api/cards/index.js b/api/cards/index.js index b3b7b45..1369d49 100644 --- a/api/cards/index.js +++ b/api/cards/index.js @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server'; import { sql } from '@vercel/postgres'; -import { verifyToken } from '../setup-auth.js'; +import { verifyToken } from '../auth-utils.js'; // GET /api/cards - Search cards from database export async function GET(request) { diff --git a/api/collections/index.js b/api/collections/index.js index 1b95a09..5d86a8b 100644 --- a/api/collections/index.js +++ b/api/collections/index.js @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server'; import { sql } from '@vercel/postgres'; -import { verifyToken } from '../setup-auth.js'; +import { verifyToken } from '../auth-utils.js'; // GET /api/collections - Get user collections export async function GET(request) { diff --git a/api/user-cards.js b/api/user-cards.js index f30d465..3df9dae 100644 --- a/api/user-cards.js +++ b/api/user-cards.js @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server'; import { sql } from '@vercel/postgres'; -import { verifyToken } from './setup-auth.js'; +import { verifyToken } from './auth-utils.js'; // GET /api/user-cards - Get user's cards with optional filters export async function GET(request) { diff --git a/api/user-cards/[id].js b/api/user-cards/[id].js index 22fb8d8..ab4b844 100644 --- a/api/user-cards/[id].js +++ b/api/user-cards/[id].js @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server'; import { sql } from '@vercel/postgres'; -import { verifyToken } from '../setup-auth.js'; +import { verifyToken } from '../auth-utils.js'; // GET /api/user-cards/[id] - Get single user card export async function GET(request, { params }) {