From 07f81c34e3d7663847fce5f8b6410c00ae4fc2e6 Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Tue, 28 May 2024 14:41:05 +0200 Subject: [PATCH] fix: refactor session handling --- app/[lang]/webview/refresh/page.module.css | 1 - components/LoadingSpinner/loading.module.css | 2 +- constants/routes/webviews.ts | 15 --------------- lib/trpc/server.ts | 11 +++++++---- middlewares/webView.ts | 18 ++++++++++-------- server/context.ts | 17 +++++++++++++++-- server/trpc.ts | 6 +----- 7 files changed, 34 insertions(+), 36 deletions(-) diff --git a/app/[lang]/webview/refresh/page.module.css b/app/[lang]/webview/refresh/page.module.css index dcd8c64de..e34ab4222 100644 --- a/app/[lang]/webview/refresh/page.module.css +++ b/app/[lang]/webview/refresh/page.module.css @@ -1,6 +1,5 @@ .container { display: flex; - flex-direction: column; align-items: center; justify-content: center; height: 100vh; diff --git a/components/LoadingSpinner/loading.module.css b/components/LoadingSpinner/loading.module.css index dd10b4d09..ae97df077 100644 --- a/components/LoadingSpinner/loading.module.css +++ b/components/LoadingSpinner/loading.module.css @@ -26,7 +26,7 @@ width: 3px; height: 9px; border-radius: 20%; - background: var(--Brand-Main-Strong); + background: var(--Scandic-Brand-Burgundy); } .spinner div:nth-child(1) { diff --git a/constants/routes/webviews.ts b/constants/routes/webviews.ts index 890a355d4..c024bfc1a 100644 --- a/constants/routes/webviews.ts +++ b/constants/routes/webviews.ts @@ -1,13 +1,3 @@ -/** - * @file Due to these records being used in next.config.js, and that is required - * to be a js file, we use jsdoc to type these. - */ - -/** - * These are routes that define code entries for My pages - */ - -/** @type {import('@/types/routes').LangRoute} */ const myPages = { da: "/da/webview/mine-sider", de: "/de/webview/mein-profil", @@ -17,7 +7,6 @@ const myPages = { sv: "/sv/webview/mina-sidor", } -/** @type {import('@/types/routes').LangRoute} */ export const overview = { da: `${myPages.da}/oversigt`, de: `${myPages.de}/uberblick`, @@ -27,7 +16,6 @@ export const overview = { sv: `${myPages.sv}/oversikt`, } -/** @type {import('@/types/routes').LangRoute} */ export const benefits = { da: `${myPages.da}/fordele`, de: `${myPages.de}/vorteile`, @@ -37,7 +25,6 @@ export const benefits = { sv: `${myPages.sv}/formaner`, } -/** @type {import('@/types/routes').LangRoute} */ export const points = { da: `${myPages.da}/point`, de: `${myPages.de}/punkte`, @@ -47,7 +34,6 @@ export const points = { sv: `${myPages.sv}/poang`, } -/** @type {import('@/types/routes').LangRoute} */ export const programOverview = { da: `/da/webview/about-scandic-friends`, de: `/de/webview/about-scandic-friends`, @@ -57,7 +43,6 @@ export const programOverview = { sv: `/sv/webview/om-scandic-friends`, } -/** @type {import('@/types/routes').LangRoute} */ const refreshUrl = { da: `/da/webview/refresh`, de: `/de/webview/refresh`, diff --git a/lib/trpc/server.ts b/lib/trpc/server.ts index 2107762f6..e3bf0bcb5 100644 --- a/lib/trpc/server.ts +++ b/lib/trpc/server.ts @@ -3,6 +3,7 @@ import { redirect } from "next/navigation" import { NextResponse } from "next/server" import { Lang } from "@/constants/languages" +import { webviews } from "@/constants/routes/webviews" import { env } from "@/env/server" import { appRouter } from "@/server" import { createContext } from "@/server/context" @@ -24,8 +25,12 @@ export function serverClient() { if (error instanceof TRPCError) { if (error.code === "UNAUTHORIZED") { const lang = ctx?.lang || Lang.en - if (ctx?.webToken) { - const returnUrl = ctx.url + + const langIndex = ctx!.url.indexOf(`/${lang}`) + const pathname = ctx?.url.substring(langIndex) + + if (pathname && webviews.includes(pathname)) { + const returnUrl = ctx!.url const redirectUrl = `/${lang}/webview/refresh?returnurl=${encodeURIComponent(returnUrl)}` console.error( @@ -36,8 +41,6 @@ export function serverClient() { redirect(redirectUrl) } - const pathname = ctx?.pathname || "/" - redirect( `/${lang}/login?redirectTo=${encodeURIComponent(`/${lang}/${pathname}`)}` ) diff --git a/middlewares/webView.ts b/middlewares/webView.ts index 21b5aba1a..d97d0f74c 100644 --- a/middlewares/webView.ts +++ b/middlewares/webView.ts @@ -77,10 +77,10 @@ export const middleware: NextMiddleware = async (request) => { try { // Authorization header is required for webviews // It should be base64 encoded - const authorization = request.headers.get("Authorization")! + const authorization = request.headers.get("X-Authorization")! if (!authorization) { console.error("Authorization header is missing") - return badRequest() + return badRequest("Authorization header is missing") } // Initialization vector header is required for webviews @@ -88,7 +88,7 @@ export const middleware: NextMiddleware = async (request) => { const initializationVector = request.headers.get("X-AES-IV")! if (!initializationVector) { console.error("initializationVector header is missing") - return badRequest() + return badRequest("initializationVector header is missing") } const decryptedData = await decryptData( @@ -97,16 +97,15 @@ export const middleware: NextMiddleware = async (request) => { authorization ) - headers.set( - "Set-Cookie", - `webviewToken=${decryptedData}; Secure; HttpOnly; Path=/; SameSite=Strict;` - ) - headers.set("Cookie", `webviewToken=${decryptedData}`) + headers.append("Cookie", `webviewToken=${decryptedData}`) if (myPagesWebviews.includes(nextUrl.pathname)) { return NextResponse.rewrite( new URL(`/${lang}/webview/account-page/${uid}`, nextUrl), { + headers: { + "Set-Cookie": `webviewToken=${decryptedData}; Secure; HttpOnly; Path=/; SameSite=Strict;`, + }, request: { headers, }, @@ -116,6 +115,9 @@ export const middleware: NextMiddleware = async (request) => { return NextResponse.rewrite( new URL(`/${lang}/webview/loyalty-page/${uid}`, nextUrl), { + headers: { + "Set-Cookie": `webviewToken=${decryptedData}; Secure; HttpOnly; Path=/; SameSite=Strict;`, + }, request: { headers, }, diff --git a/server/context.ts b/server/context.ts index aa4f117eb..e58e1ba6f 100644 --- a/server/context.ts +++ b/server/context.ts @@ -1,11 +1,16 @@ import { cookies, headers } from "next/headers" +import { type Session } from "next-auth" import { Lang } from "@/constants/languages" import { auth } from "@/auth" +import { unauthorizedError } from "./errors/trpc" + +typeof auth + type CreateContextOptions = { - auth: typeof auth + auth: () => Promise lang: Lang pathname: string uid?: string | null @@ -39,7 +44,15 @@ export function createContext() { const webviewTokenCookie = cookie.get("webviewToken") return createContextInner({ - auth, + auth: async () => { + const session = await auth() + const webToken = webviewTokenCookie?.value + if (!session?.token && !webToken) { + throw unauthorizedError() + } + + return session || ({ token: { access_token: webToken } } as Session) + }, lang: h.get("x-lang") as Lang, pathname: h.get("x-pathname")!, uid: h.get("x-uid"), diff --git a/server/trpc.ts b/server/trpc.ts index 016f14624..e29f5e477 100644 --- a/server/trpc.ts +++ b/server/trpc.ts @@ -41,13 +41,9 @@ export const protectedProcedure = t.procedure.use(async function (opts) { throw sessionExpiredError() } - if (!session?.token.access_token && !opts.ctx.webToken) { - throw unauthorizedError() - } - return opts.next({ ctx: { - session: session || { token: { access_token: opts.ctx.webToken } }, + session, }, }) })