Expand e2e auth coverage, Vitest CI, and shared URL defaults
Wire viewer-frontend Vitest into Gitea Actions, centralize DEV base URLs in env-defaults.json, expand playkit API catalog specs, and land auth/mail flows plus verify-email public-host redirect and idle-logout e2e hooks.
This commit is contained in:
@@ -1,43 +1,53 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prismaAuth } from '@/lib/db';
|
||||
|
||||
/**
|
||||
* Public site origin for redirects. Behind Caddy, `request.url` is often
|
||||
* http://localhost:3001 which sends browsers (and e2e) to a LAN/loopback
|
||||
* host — same class of bug as NEXTAUTH_URL → 10.x (#57).
|
||||
*/
|
||||
function publicOrigin(request: NextRequest): string {
|
||||
const fromEnv = (process.env.NEXTAUTH_URL || process.env.AUTH_URL || '').replace(/\/$/, '');
|
||||
if (fromEnv) return fromEnv;
|
||||
|
||||
const xfProto = request.headers.get('x-forwarded-proto');
|
||||
const xfHost = request.headers.get('x-forwarded-host') || request.headers.get('host');
|
||||
if (xfHost) {
|
||||
const proto = xfProto || 'https';
|
||||
return `${proto}://${xfHost.split(',')[0].trim()}`;
|
||||
}
|
||||
return request.nextUrl.origin;
|
||||
}
|
||||
|
||||
function redirectLogin(request: NextRequest, query: string): NextResponse {
|
||||
return NextResponse.redirect(new URL(`/login?${query}`, publicOrigin(request)));
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const token = searchParams.get('token');
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.redirect(
|
||||
new URL('/login?error=missing_token', request.url)
|
||||
);
|
||||
return redirectLogin(request, 'error=missing_token');
|
||||
}
|
||||
|
||||
// Find user with this token
|
||||
const user = await prismaAuth.user.findUnique({
|
||||
where: { emailConfirmationToken: token },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.redirect(
|
||||
new URL('/login?error=invalid_token', request.url)
|
||||
);
|
||||
return redirectLogin(request, 'error=invalid_token');
|
||||
}
|
||||
|
||||
// Check if token has expired
|
||||
if (user.emailConfirmationTokenExpiry && user.emailConfirmationTokenExpiry < new Date()) {
|
||||
return NextResponse.redirect(
|
||||
new URL('/login?error=token_expired', request.url)
|
||||
);
|
||||
return redirectLogin(request, 'error=token_expired');
|
||||
}
|
||||
|
||||
// Check if already verified
|
||||
if (user.emailVerified) {
|
||||
return NextResponse.redirect(
|
||||
new URL('/login?message=already_verified', request.url)
|
||||
);
|
||||
return redirectLogin(request, 'message=already_verified');
|
||||
}
|
||||
|
||||
// Verify the email
|
||||
await prismaAuth.user.update({
|
||||
where: { id: user.id },
|
||||
data: {
|
||||
@@ -47,21 +57,9 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
|
||||
// Redirect to login with success message
|
||||
return NextResponse.redirect(
|
||||
new URL('/login?verified=true', request.url)
|
||||
);
|
||||
} catch (error: any) {
|
||||
return redirectLogin(request, 'verified=true');
|
||||
} catch (error: unknown) {
|
||||
console.error('Error verifying email:', error);
|
||||
return NextResponse.redirect(
|
||||
new URL('/login?error=verification_failed', request.url)
|
||||
);
|
||||
return redirectLogin(request, 'error=verification_failed');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user