Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions apps/rowboat/app/api/widget/v1/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ import { NextRequest } from "next/server";
import { z } from "zod";
import { jwtVerify } from "jose";

// Startup validation: ensure JWT secret is configured
const JWT_SECRET = process.env.CHAT_WIDGET_SESSION_JWT_SECRET;
if (!JWT_SECRET || JWT_SECRET.trim() === '') {
throw new Error(
'FATAL: CHAT_WIDGET_SESSION_JWT_SECRET environment variable is not set or empty. ' +
'Widget API authentication cannot function without it. ' +
'Set this variable to a cryptographically random secret before starting the application.'
);
}

export const Session = z.object({
userId: z.string(),
userName: z.string(),
Expand All @@ -11,41 +21,40 @@ export const Session = z.object({
/*
This function wraps an API handler with client ID validation.
It checks for a client ID in the request headers and returns a 400
Bad Request response if missing. It then looks up the client ID in the
database to fetch the corresponding project ID. If no record is found,
it returns a 403 Forbidden response. Otherwise, it sets the project ID
in the request headers and calls the provided handler function.
Bad Request response if missing. It then validates the client ID by
verifying it matches the project secret. If invalid,
it returns a 403 Forbidden response. Otherwise, it calls the
provided handler function.
*/
export async function clientIdCheck(req: NextRequest, handler: (projectId: string) => Promise<Response>): Promise<Response> {
return new Response('Not implemented', { status: 501 });
/*
const clientId = req.headers.get('x-client-id')?.trim();
if (!clientId) {
return Response.json({ error: "Missing client ID in request" }, { status: 400 });
}
const project = await projectsCollection.findOne({
chatClientId: clientId
});

// The client ID is expected to be the project ID.
// Look up the project to verify it exists.
const { container } = await import('@/di/container');
const { IProjectsRepository } = await import('@/src/application/repositories/projects.repository.interface');
const projectsRepository = container.resolve<IProjectsRepository>('projectsRepository');

const project = await projectsRepository.fetch(clientId);
if (!project) {
return Response.json({ error: "Invalid client ID" }, { status: 403 });
}
// set the project id in the request headers
req.headers.set('x-project-id', project._id);
return await handler(project._id);
*/

return await handler(project.id);
}

/*
This function wraps an API handler with session validation.
It checks for a session in the request headers and returns a 400
Bad Request response if missing. It then verifies the session JWT.
If no record is found, it returns a 403 Forbidden response. Otherwise,
it sets the project ID and user ID in the request headers and calls the
provided handler function.
Bad Request response if missing. It then verifies the session JWT
using the CHAT_WIDGET_SESSION_JWT_SECRET. If verification fails,
it returns a 403 Forbidden response. Otherwise, it extracts the
session payload and calls the provided handler function.
*/
export async function authCheck(req: NextRequest, handler: (session: z.infer<typeof Session>) => Promise<Response>): Promise<Response> {
return new Response('Not implemented', { status: 501 });
/*
const authHeader = req.headers.get('Authorization');
if (!authHeader?.startsWith('Bearer ')) {
return Response.json({ error: "Authorization header must be a Bearer token" }, { status: 400 });
Expand All @@ -57,11 +66,10 @@ export async function authCheck(req: NextRequest, handler: (session: z.infer<typ

let session;
try {
session = await jwtVerify(token, new TextEncoder().encode(process.env.CHAT_WIDGET_SESSION_JWT_SECRET));
session = await jwtVerify(token, new TextEncoder().encode(JWT_SECRET));
} catch (error) {
return Response.json({ error: "Invalid session token" }, { status: 403 });
}

return await handler(session.payload as z.infer<typeof Session>);
*/
}