import { notFound } from "next/navigation" import { type NextMiddleware, NextResponse } from "next/server" import { findLang } from "@/constants/languages" import { loyaltyPagesWebviews, myPagesWebviews, refreshWebviews, webviews, } from "@/constants/routes/webviews" import { env } from "@/env/server" import { badRequest } from "@/server/errors/next" import { decryptData } from "@/utils/aes" import type { MiddlewareMatcher } from "@/types/middleware" export const middleware: NextMiddleware = async (request) => { const { nextUrl } = request const lang = findLang(nextUrl.pathname) const pathNameWithoutLang = nextUrl.pathname.replace(`/${lang}/webview`, "") const headers = new Headers() // If user is redirected to /lang/webview/refresh/, the webview token is invalid and we remove the cookie if (refreshWebviews.includes(nextUrl.pathname)) { headers.set( "Set-Cookie", `webviewToken=0; Max-Age=0; Secure; HttpOnly; Path=/; SameSite=Strict;` ) return NextResponse.rewrite(new URL(`/${lang}/webview/refresh`, nextUrl), { headers, }) } const searchParams = new URLSearchParams(request.nextUrl.searchParams) searchParams.set("uri", pathNameWithoutLang) const webviewToken = request.cookies.get("webviewToken") if (webviewToken) { // since the token exists, this is a subsequent visit // we're done, allow it if (myPagesWebviews.includes(nextUrl.pathname)) { return NextResponse.rewrite( new URL(`/${lang}/webview/my-pages?${searchParams.toString()}`, nextUrl) ) } else if (loyaltyPagesWebviews.includes(nextUrl.pathname)) { return NextResponse.rewrite( new URL( `/${lang}/webview/loyalty-page?${searchParams.toString()}`, nextUrl ) ) } else { return notFound() } } try { // 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() } const decryptedData = await decryptData( env.WEBVIEW_ENCRYPTION_KEY, initializationVector, authorization ) headers.set( "Set-Cookie", `webviewToken=${decryptedData}; Secure; HttpOnly; Path=/; SameSite=Strict;` ) headers.set("Cookie", `webviewToken=${decryptedData}`) console.log("IN WEBVIEW MIDDLEWARE", decryptedData) if (myPagesWebviews.includes(nextUrl.pathname)) { return NextResponse.rewrite( new URL( `/${lang}/webview/my-pages?${searchParams.toString()}`, nextUrl ), { headers, } ) } else if (loyaltyPagesWebviews.includes(nextUrl.pathname)) { return NextResponse.rewrite( new URL( `/${lang}/webview/loyalty-page?${searchParams.toString()}`, nextUrl ), { headers, } ) } } catch (e) { if (e instanceof Error) { console.error(`${e.name}: ${e.message}`) } return badRequest() } } export const matcher: MiddlewareMatcher = (request) => { const { nextUrl } = request return webviews.includes(nextUrl.pathname) }