65 lines
1.9 KiB
TypeScript
65 lines
1.9 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import crypto from 'crypto';
|
|
import jwt from 'jsonwebtoken';
|
|
import { db } from "@/drizzle/db";
|
|
import { users } from "@/drizzle/schema";
|
|
import { eq } from 'drizzle-orm';
|
|
|
|
export async function POST(req: Request) {
|
|
try {
|
|
const { sessionId, signature, email } = await req.json();
|
|
|
|
// TAHAP NANO: Validasi Kriptografis Challenge QR Code
|
|
if (!sessionId || !signature || !email) {
|
|
return NextResponse.json({ error: 'Missing challenge parameters' }, { status: 400 });
|
|
}
|
|
|
|
// Server memverifikasi bahwa signature adalah hash dari sessionId + email + secret
|
|
const expectedSignature = crypto
|
|
.createHmac('sha256', process.env.JWT_SECRET as string)
|
|
.update(`${sessionId}:${email}`)
|
|
.digest('hex');
|
|
|
|
if (signature !== expectedSignature) {
|
|
return NextResponse.json({ error: 'Invalid QR cryptographic signature' }, { status: 401 });
|
|
}
|
|
|
|
// Verifikasi berhasil, generate real JWT token
|
|
const userResult = await db.select().from(users).where(eq(users.email, email)).limit(1);
|
|
|
|
if (userResult.length === 0) {
|
|
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
|
}
|
|
|
|
const user = userResult[0];
|
|
|
|
const token = jwt.sign(
|
|
{
|
|
id: user.id,
|
|
email: user.email,
|
|
role: user.role,
|
|
tenantId: user.tenantId,
|
|
},
|
|
process.env.JWT_SECRET as string,
|
|
{ expiresIn: '8h' }
|
|
);
|
|
|
|
const response = NextResponse.json({ message: 'QR Auth Berhasil' });
|
|
response.cookies.set({
|
|
name: 'jumpa_token',
|
|
value: token,
|
|
httpOnly: true,
|
|
secure: true,
|
|
sameSite: 'lax',
|
|
path: '/',
|
|
domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN || undefined,
|
|
maxAge: 8 * 60 * 60
|
|
});
|
|
return response;
|
|
|
|
} catch (e) {
|
|
console.error("QR Auth Verify Error:", e);
|
|
return NextResponse.json({ error: 'Server error' }, { status: 500 });
|
|
}
|
|
}
|