62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
import { type NextMiddleware, NextResponse } 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
|
|
)
|
|
|
|
const response = NextResponse.next()
|
|
response.cookies.set("webviewToken", decryptedData, {
|
|
httpOnly: true,
|
|
secure: true,
|
|
})
|
|
|
|
return response
|
|
} 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/")
|
|
}
|