import { NextResponse, type NextMiddleware } from "next/server" import { findLang } from "@/constants/languages" import { env } from "@/env/server" import { badRequest, internalServerError } from "@/server/errors/next" import { decryptData } from "@/utils/aes" import type { MiddlewareMatcher } from "@/types/middleware" export const middleware: NextMiddleware = async (request) => { const webviewToken = request.cookies.get("webviewToken") if (webviewToken) { // since the token exists, this is a subsequent visit // we're done, allow it return NextResponse.next() } // Authorization header is required for webviews // It should be base64 encoded const authorization = request.headers.get("Authorization")! if (!authorization) { return badRequest() } // Initialization vector header is required for webviews // It should be base64 encoded const initializationVector = request.headers.get("X-AES-IV")! if (!initializationVector) { return badRequest() } try { const decryptedData = await decryptData( env.WEBVIEW_ENCRYPTION_KEY, initializationVector, authorization ) // Pass the webview token via cookie to the page return NextResponse.next({ headers: { "Set-Cookie": `webviewToken=${decryptedData}; Secure; HttpOnly;`, }, }) } catch (e) { if (e instanceof Error) { console.error(`${e.name}: ${e.message}`) } return badRequest() } } export const matcher: MiddlewareMatcher = (request) => { const { nextUrl } = request const lang = findLang(nextUrl.pathname) const pathNameWithoutLang = nextUrl.pathname.replace(`/${lang}`, "") return pathNameWithoutLang.startsWith("/webview/") }