fix: refactor session handling
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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}`)}`
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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<Session>
|
||||
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"),
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user