| import { cookies } from 'next/headers'; |
| import { createHmac, timingSafeEqual } from 'crypto'; |
| import { apiError, apiSuccess } from '@/lib/server/api-response'; |
|
|
| |
| function createAccessToken(accessCode: string): string { |
| const timestamp = Date.now().toString(); |
| const signature = createHmac('sha256', accessCode).update(timestamp).digest('hex'); |
| return `${timestamp}.${signature}`; |
| } |
|
|
| |
| export function verifyAccessToken(token: string, accessCode: string): boolean { |
| const dotIndex = token.indexOf('.'); |
| if (dotIndex === -1) return false; |
|
|
| const timestamp = token.substring(0, dotIndex); |
| const signature = token.substring(dotIndex + 1); |
|
|
| const expected = createHmac('sha256', accessCode).update(timestamp).digest('hex'); |
|
|
| const sigBuf = Buffer.from(signature, 'hex'); |
| const expBuf = Buffer.from(expected, 'hex'); |
| if (sigBuf.length !== expBuf.length) return false; |
|
|
| return timingSafeEqual(sigBuf, expBuf); |
| } |
|
|
| export async function POST(request: Request) { |
| const accessCode = process.env.ACCESS_CODE; |
| if (!accessCode) { |
| return apiSuccess({ valid: true }); |
| } |
|
|
| let body: { code?: string }; |
| try { |
| body = await request.json(); |
| } catch { |
| return apiError('INVALID_REQUEST', 400, 'Invalid JSON body'); |
| } |
|
|
| |
| if (!body.code) { |
| return apiError('INVALID_REQUEST', 401, 'Invalid access code'); |
| } |
| const encoder = new TextEncoder(); |
| const a = encoder.encode(body.code); |
| const b = encoder.encode(accessCode); |
| if (a.byteLength !== b.byteLength || !timingSafeEqual(a, b)) { |
| return apiError('INVALID_REQUEST', 401, 'Invalid access code'); |
| } |
|
|
| const token = createAccessToken(accessCode); |
| const cookieStore = await cookies(); |
| cookieStore.set('multimind_access', token, { |
| httpOnly: true, |
| sameSite: 'lax', |
| path: '/', |
| maxAge: 60 * 60 * 24 * 7, |
| secure: process.env.NODE_ENV === 'production', |
| }); |
|
|
| return apiSuccess({ valid: true }); |
| } |
|
|