TelegramBot/webui/app/api/auth/verify/route.ts

107 lines
3.1 KiB
TypeScript
Executable file

import { NextRequest, NextResponse } from "next/server";
import { eq, and, gt } from "drizzle-orm";
import * as schema from "@/lib/schema";
import { db } from "@/lib/db";
import { createSession, getSessionCookieOptions } from "@/lib/auth";
import { SESSION_COOKIE_NAME } from "@/lib/auth-constants";
export async function POST(request: NextRequest) {
try {
const contentType = request.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
return NextResponse.json({
success: false,
error: "Invalid content type"
}, { status: 400 });
}
const body = await request.json();
const { userId, code } = body;
if (!userId || !code) {
return NextResponse.json({
success: false,
error: "User ID and code are required"
}, { status: 400 });
}
if (typeof userId !== 'string' || typeof code !== 'string') {
return NextResponse.json({
success: false,
error: "Invalid input format"
}, { status: 400 });
}
if (!/^\d{6}$/.test(code)) {
return NextResponse.json({
success: false,
error: "Invalid code format"
}, { status: 400 });
}
const twoFactorRecord = await db.query.twoFactorTable.findFirst({
where: and(
eq(schema.twoFactorTable.userId, userId),
gt(schema.twoFactorTable.codeExpiresAt, new Date())
),
});
if (!twoFactorRecord) {
return NextResponse.json({
success: false,
error: "No valid 2FA code found or code has expired"
}, { status: 404 });
}
if (twoFactorRecord.codeAttempts >= 5) {
await db.delete(schema.twoFactorTable)
.where(eq(schema.twoFactorTable.userId, userId));
return NextResponse.json({
success: false,
error: "Too many failed attempts. Please request a new code."
}, { status: 429 });
}
if (twoFactorRecord.currentCode !== code) {
await db.update(schema.twoFactorTable)
.set({
codeAttempts: twoFactorRecord.codeAttempts + 1,
updatedAt: new Date()
})
.where(eq(schema.twoFactorTable.userId, userId));
console.log(`2FA verification failed for user: ${userId}, attempts: ${twoFactorRecord.codeAttempts + 1}`);
return NextResponse.json({
success: false,
error: "Invalid 2FA code"
}, { status: 401 });
}
const session = await createSession(userId);
await db.delete(schema.twoFactorTable)
.where(eq(schema.twoFactorTable.userId, userId));
console.log("2FA verification successful for user:", userId);
const response = NextResponse.json({
success: true,
message: "2FA verification successful",
redirectTo: "/account",
sessionToken: session.sessionToken
});
const cookieOptions = getSessionCookieOptions();
response.cookies.set(SESSION_COOKIE_NAME, session.sessionToken, cookieOptions);
return response;
} catch (error) {
console.error("Error in verify API:", error);
return NextResponse.json({
success: false,
error: "Internal server error"
}, { status: 500 });
}
}