diff --git a/app/[lang]/webview/loyalty-page/page.tsx b/app/[lang]/webview/loyalty-page/page.tsx
index 0c2ee7c00..d3e821aab 100644
--- a/app/[lang]/webview/loyalty-page/page.tsx
+++ b/app/[lang]/webview/loyalty-page/page.tsx
@@ -1,7 +1,6 @@
-import { notFound } from "next/navigation"
-
import { serverClient } from "@/lib/trpc/server"
+import BackButton from "@/components/BackButton"
import { Blocks } from "@/components/Loyalty/Blocks/WebView"
import Sidebar from "@/components/Loyalty/Sidebar"
import MaxWidth from "@/components/MaxWidth"
@@ -19,6 +18,7 @@ export default async function AboutScandicFriends({
{loyaltyPage.sidebar ? : null}
+
diff --git a/app/[lang]/webview/my-pages/page.tsx b/app/[lang]/webview/my-pages/page.tsx
index f6ef509a5..199ee2425 100644
--- a/app/[lang]/webview/my-pages/page.tsx
+++ b/app/[lang]/webview/my-pages/page.tsx
@@ -1,11 +1,11 @@
import "@/app/globals.css"
import "@scandic-hotels/design-system/style.css"
-import { notFound } from "next/navigation"
-
+import { overview } from "@/constants/routes/myPages"
import { _ } from "@/lib/translation"
import { serverClient } from "@/lib/trpc/server"
+import BackButton from "@/components/BackButton"
import MaxWidth from "@/components/MaxWidth"
import Content from "@/components/MyPages/AccountPage/Webview/Content"
@@ -16,8 +16,11 @@ import { LangParams, PageArgs } from "@/types/params"
export default async function MyPages({ params }: PageArgs) {
const accountPage = await serverClient().contentstack.accountPage.get()
+ const isNotOverviewPage = accountPage.url !== overview[params.lang]
+
return (
+ {isNotOverviewPage ? : null}
)
diff --git a/components/BackButton/index.tsx b/components/BackButton/index.tsx
new file mode 100644
index 000000000..b9eebdddd
--- /dev/null
+++ b/components/BackButton/index.tsx
@@ -0,0 +1,15 @@
+"use client"
+
+import { useRouter } from "next/navigation"
+
+import Button from "../TempDesignSystem/Button"
+
+export default function BackButton() {
+ const router = useRouter()
+
+ function goBack() {
+ router.back()
+ }
+
+ return
+}
diff --git a/components/Loyalty/Blocks/WebView/index.tsx b/components/Loyalty/Blocks/WebView/index.tsx
index f5b5fea0f..fbf96d315 100644
--- a/components/Loyalty/Blocks/WebView/index.tsx
+++ b/components/Loyalty/Blocks/WebView/index.tsx
@@ -3,7 +3,7 @@ import DynamicContentBlock from "@/components/Loyalty/Blocks/DynamicContent"
import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
import { modWebviewLink } from "@/utils/webviews"
-import CardGrid from "../CardGrid"
+import CardsGrid from "../CardsGrid"
import type { BlocksProps } from "@/types/components/loyalty/blocks"
import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums"
@@ -12,20 +12,8 @@ import { LangParams } from "@/types/params"
export function Blocks({ lang, blocks }: BlocksProps & LangParams) {
return blocks.map((block) => {
switch (block.__typename) {
- case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid:
- const cardGrid = {
- ...block.card_grid,
- cards: block.card_grid.cards.map((card) => {
- return {
- ...card,
- link: card.link
- ? { ...card.link, href: modWebviewLink(card.link.href, lang) }
- : undefined,
- }
- }),
- }
-
- return
+ case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid:
+ return
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent:
return (
diff --git a/lib/trpc/server.ts b/lib/trpc/server.ts
index 765c5fbbe..7f3966979 100644
--- a/lib/trpc/server.ts
+++ b/lib/trpc/server.ts
@@ -25,7 +25,7 @@ export function serverClient() {
const lang = ctx?.lang || Lang.en
if (ctx?.webToken) {
console.log({ ctx })
- const returnUrl = ctx.pathname || overview[lang]
+ const returnUrl = ctx.url
const redirectUrl = `/${lang}/webview/refresh?returnurl=${encodeURIComponent(returnUrl)}`
console.error(
diff --git a/middlewares/utils.ts b/middlewares/utils.ts
index 209dbf5c8..feba8f258 100644
--- a/middlewares/utils.ts
+++ b/middlewares/utils.ts
@@ -7,7 +7,10 @@ export function getDefaultRequestHeaders(request: NextRequest) {
const headers = new Headers(request.headers)
headers.set("x-lang", lang)
- headers.set("x-pathname", request.nextUrl.pathname.replace(`/${lang}`, ""))
+ headers.set(
+ "x-pathname",
+ request.nextUrl.pathname.replace(`/${lang}`, "").replace(`/webview`, "")
+ )
headers.set("x-url", request.nextUrl.href)
return headers
diff --git a/middlewares/webView.ts b/middlewares/webView.ts
index d6ad52dac..6d62b9f74 100644
--- a/middlewares/webView.ts
+++ b/middlewares/webView.ts
@@ -1,4 +1,3 @@
-import { notFound } from "next/navigation"
import { type NextMiddleware, NextResponse } from "next/server"
import { findLang } from "@/constants/languages"
@@ -9,9 +8,12 @@ import {
webviews,
} from "@/constants/routes/webviews"
import { env } from "@/env/server"
-import { badRequest } from "@/server/errors/next"
+import { badRequest, notFound } from "@/server/errors/next"
import { decryptData } from "@/utils/aes"
+import { resolve as resolveEntry } from "@/utils/entry"
+
+import { getDefaultRequestHeaders } from "./utils"
import type { MiddlewareMatcher } from "@/types/middleware"
@@ -19,22 +21,25 @@ 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,
+ headers: {
+ "Set-Cookie": `webviewToken=0; Max-Age=0; Secure; HttpOnly; Path=/; SameSite=Strict;`,
+ },
})
}
- const searchParams = new URLSearchParams(request.nextUrl.searchParams)
- searchParams.set("uri", pathNameWithoutLang)
+ const pathNameWithoutLang = nextUrl.pathname.replace(`/${lang}/webview`, "")
+
+ const { uid } = await resolveEntry(pathNameWithoutLang, lang)
+ if (!uid) {
+ throw notFound(
+ `Unable to resolve CMS entry for locale "${lang}": ${pathNameWithoutLang}`
+ )
+ }
+ const headers = getDefaultRequestHeaders(request)
+ headers.set("x-uid", uid)
const webviewToken = request.cookies.get("webviewToken")
if (webviewToken) {
@@ -42,14 +47,21 @@ export const middleware: NextMiddleware = async (request) => {
// we're done, allow it
if (myPagesWebviews.includes(nextUrl.pathname)) {
return NextResponse.rewrite(
- new URL(`/${lang}/webview/my-pages?${searchParams.toString()}`, nextUrl)
+ new URL(`/${lang}/webview/my-pages`, nextUrl),
+ {
+ request: {
+ headers,
+ },
+ }
)
} else if (loyaltyPagesWebviews.includes(nextUrl.pathname)) {
return NextResponse.rewrite(
- new URL(
- `/${lang}/webview/loyalty-page?${searchParams.toString()}`,
- nextUrl
- )
+ new URL(`/${lang}/webview/loyalty-page`, nextUrl),
+ {
+ request: {
+ headers,
+ },
+ }
)
} else {
return notFound()
@@ -77,32 +89,30 @@ export const middleware: NextMiddleware = async (request) => {
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
- ),
+ new URL(`/${lang}/webview/my-pages`, nextUrl),
{
- headers,
+ headers: {
+ "Set-Cookie": `webviewToken=${decryptedData}; Secure; HttpOnly; Path=/; SameSite=Strict;`,
+ Cookie: `webviewToken=${decryptedData}`,
+ },
+ request: {
+ headers,
+ },
}
)
} else if (loyaltyPagesWebviews.includes(nextUrl.pathname)) {
return NextResponse.rewrite(
- new URL(
- `/${lang}/webview/loyalty-page?${searchParams.toString()}`,
- nextUrl
- ),
+ new URL(`/${lang}/webview/loyalty-page`, nextUrl),
{
- headers,
+ headers: {
+ "Set-Cookie": `webviewToken=${decryptedData}; Secure; HttpOnly; Path=/; SameSite=Strict;`,
+ Cookie: `webviewToken=${decryptedData}`,
+ },
+ request: {
+ headers,
+ },
}
)
}
diff --git a/server/trpc.ts b/server/trpc.ts
index 17e82607b..65e49fff4 100644
--- a/server/trpc.ts
+++ b/server/trpc.ts
@@ -41,7 +41,7 @@ export const protectedProcedure = t.procedure.use(async function (opts) {
throw sessionExpiredError()
}
- if (!session?.user) {
+ if (!session?.user || !opts.ctx.webToken) {
throw unauthorizedError()
}
diff --git a/test.js b/test.js
new file mode 100644
index 000000000..2e6a6db89
--- /dev/null
+++ b/test.js
@@ -0,0 +1,82 @@
+function base64ToUint8Array(base64String) {
+ const binaryString = atob(base64String)
+ const byteArray = new Uint8Array(binaryString.length)
+ for (let i = 0; i < binaryString.length; i++) {
+ byteArray[i] = binaryString.charCodeAt(i)
+ }
+ return byteArray
+}
+
+function utf8ToUint8Array(utf8String) {
+ return new TextEncoder().encode(utf8String)
+}
+
+function uint8ArrayToBase64(uint8Array) {
+ let binaryString = ""
+ const len = uint8Array.byteLength
+ for (let i = 0; i < len; i++) {
+ binaryString += String.fromCharCode(uint8Array[i])
+ }
+ return btoa(binaryString)
+}
+async function encryptData(keyBase64, ivBase64, data) {
+ const keyBuffer = await crypto.subtle.importKey(
+ "raw",
+ base64ToUint8Array(keyBase64),
+ "AES-CBC",
+ false,
+ ["encrypt"]
+ )
+
+ const dataBuffer = utf8ToUint8Array(data)
+ const ivBuffer = base64ToUint8Array(ivBase64)
+ const encryptedDataBuffer = await crypto.subtle.encrypt(
+ { name: "AES-CBC", iv: ivBuffer },
+ keyBuffer,
+ dataBuffer
+ )
+
+ const encryptedData = uint8ArrayToBase64(new Uint8Array(encryptedDataBuffer))
+ return encryptedData
+}
+
+function uint8ArrayToUtf8(uint8Array) {
+ return new TextDecoder().decode(uint8Array)
+}
+
+async function decryptData(keyBase64, ivBase64, encryptedDataBase64) {
+ const keyBuffer = await crypto.subtle.importKey(
+ "raw",
+ base64ToUint8Array(keyBase64),
+ "AES-CBC",
+ false,
+ ["decrypt"]
+ )
+
+ const encryptedDataBuffer = base64ToUint8Array(encryptedDataBase64)
+ const ivBuffer = base64ToUint8Array(ivBase64)
+ const decryptedDataBuffer = await crypto.subtle.decrypt(
+ { name: "AES-CBC", iv: ivBuffer },
+ keyBuffer,
+ encryptedDataBuffer
+ )
+
+ const decryptedData = uint8ArrayToUtf8(new Uint8Array(decryptedDataBuffer))
+ return decryptedData
+}
+
+const data = "_0XBPWQQ_e81346b1-6e8f-44bf-ad9c-33fd2dcc1abd"
+const iv = btoa("abcdefghijklmnop")
+const tegwpjke = await encryptData(
+ "JYekSRT8YXWquXpxxukJR0GsELl5Nt4KdcCbaCvSzHE=",
+ iv,
+ data
+)
+
+const decrypttionData = await decryptData(
+ "JYekSRT8YXWquXpxxukJR0GsELl5Nt4KdcCbaCvSzHE=",
+ iv,
+ tegwpjke
+)
+
+console.log(tegwpjke, btoa("abcdefghijklmnop"), decrypttionData === data)