diff --git a/.env.local.example b/.env.local.example index f2128d1b8..231fff9dd 100644 --- a/.env.local.example +++ b/.env.local.example @@ -31,6 +31,8 @@ SEAMLESS_LOGOUT_FI="http://www.example.fi/updatelogout?newweb=1" SEAMLESS_LOGOUT_NO="http://www.example.no/updatelogout?newweb=1" SEAMLESS_LOGOUT_SV="http://www.example.sv/updatelogout?newweb=1" WEBVIEW_ENCRYPTION_KEY="MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=" +BOOKING_ENCRYPTION_KEY=za2paS0x +NODE_OPTIONS=--openssl-legacy-provider PUBLIC_URL="http://localhost:3000" AUTH_URL="$PUBLIC_URL/api/web/auth" diff --git a/components/MyPages/Blocks/Stays/StayCard/index.tsx b/components/MyPages/Blocks/Stays/StayCard/index.tsx index 0457a832a..3659bb2fc 100644 --- a/components/MyPages/Blocks/Stays/StayCard/index.tsx +++ b/components/MyPages/Blocks/Stays/StayCard/index.tsx @@ -3,6 +3,7 @@ import { dt } from "@/lib/dt" import { CalendarIcon } from "@/components/Icons" import Image from "@/components/Image" import Caption from "@/components/TempDesignSystem/Text/Caption" +import Link from "@/components/TempDesignSystem/Link" import Title from "@/components/TempDesignSystem/Text/Title" import styles from "./stay.module.css" @@ -10,7 +11,9 @@ import styles from "./stay.module.css" import type { StayCardProps } from "@/types/components/myPages/stays/stayCard" export default function StayCard({ stay, lang }: StayCardProps) { - const { checkinDate, checkoutDate, hotelInformation } = stay.attributes + const { checkinDate, checkoutDate, hotelInformation, bookingUrl } = + stay.attributes + const arrival = dt(checkinDate).locale(lang) const arrivalDate = arrival.format("DD MMM") const arrivalDateTime = arrival.format("YYYY-MM-DD") diff --git a/server/routers/user/output.ts b/server/routers/user/output.ts index dd75d2be5..dadbe5867 100644 --- a/server/routers/user/output.ts +++ b/server/routers/user/output.ts @@ -61,6 +61,7 @@ export const getStaysSchema = z.object({ checkinDate: z.string(), checkoutDate: z.string(), isWebAppOrigin: z.boolean(), + bookingUrl: z.string().optional(), }), relationships: z.object({ hotel: z.object({ diff --git a/server/routers/user/query.ts b/server/routers/user/query.ts index 30a77d9c4..f58589cb7 100644 --- a/server/routers/user/query.ts +++ b/server/routers/user/query.ts @@ -14,6 +14,7 @@ import { getUserInputSchema, staysInput, } from "./input" +import encryptValue from "../utils/encryptValue" import { getCreditCardsSchema, getFriendTransactionsSchema, @@ -212,6 +213,61 @@ export const userQueryRouter = router({ ? verifiedData.data.links.offset : undefined + // Tenporary till we have user name in ctx session data + // ---- + const apiResponseUser = await api.get(api.endpoints.v1.profile, { + cache: "no-store", + headers: { + Authorization: `Bearer ${ctx.session.token.access_token}`, + }, + }) + + if (!apiResponseUser.ok) { + // switch (apiResponseUser.status) { + // case 400: + // throw badRequestError(apiResponseUser) + // case 401: + // throw unauthorizedError(apiResponseUser) + // case 403: + // throw forbiddenError(apiResponseUser) + // default: + // throw internalServerError(apiResponseUser) + // } + console.info(`API Response Failed - Getting User`) + console.info(`User: (${JSON.stringify(ctx.session.user)})`) + console.error(apiResponse) + return null + } + + const apiJsonUser = await apiResponse.json() + if (!apiJson.data?.attributes) { + // throw notFound(apiJson) + console.error( + `User has no data - (user: ${JSON.stringify(ctx.session.user)})` + ) + return null + } + + const verifiedDataUser = getUserSchema.safeParse(apiJsonUser.data.attributes) + if (!verifiedDataUser.success) { + console.info( + `Failed to validate User - (User: ${JSON.stringify(ctx.session.user)})` + ) + console.error(verifiedDataUser.error) + return null + } + // ------------------ + + verifiedData.data.data.forEach((stay) => { + const originalString = + stay.attributes.confirmationNumber.toString() + + "," + + verifiedDataUser.data.lastName + let bookingUrl = encryptValue(originalString) + stay.attributes.bookingUrl = + "/hotelreservation/my-booking?RefId=" + bookingUrl + }) + return { data: verifiedData.data.data, nextCursor, @@ -272,6 +328,61 @@ export const userQueryRouter = router({ ? verifiedData.data.links.offset : undefined + // Tenporary till we have user name in ctx session data + // ---- + const apiResponseUser = await api.get(api.endpoints.v1.profile, { + cache: "no-store", + headers: { + Authorization: `Bearer ${ctx.session.token.access_token}`, + }, + }) + + if (!apiResponseUser.ok) { + // switch (apiResponseUser.status) { + // case 400: + // throw badRequestError(apiResponseUser) + // case 401: + // throw unauthorizedError(apiResponseUser) + // case 403: + // throw forbiddenError(apiResponseUser) + // default: + // throw internalServerError(apiResponseUser) + // } + console.info(`API Response Failed - Getting Upcoming Stays`) + console.info(`User: (${JSON.stringify(ctx.session.user)})`) + console.error(apiResponse) + return null + } + + const apiJsonUser = await apiResponse.json() + if (!apiJson.data?.attributes) { + // throw notFound(apiJson) + console.error( + `User has no data - (user: ${JSON.stringify(ctx.session.user)})` + ) + return null + } + + const verifiedDataUser = getUserSchema.safeParse(apiJsonUser.data.attributes) + if (!verifiedDataUser.success) { + console.info( + `Failed to validate User - (User: ${JSON.stringify(ctx.session.user)})` + ) + console.error(verifiedDataUser.error) + return null + } + // ------------------ + + verifiedData.data.data.forEach((stay) => { + const originalString = + stay.attributes.confirmationNumber.toString() + + "," + + verifiedDataUser.data.lastName + let bookingUrl = encryptValue(originalString) + stay.attributes.bookingUrl = + "/hotelreservation/my-booking?RefId=" + bookingUrl + }) + return { data: verifiedData.data.data, nextCursor, diff --git a/server/routers/utils/encryptValue.ts b/server/routers/utils/encryptValue.ts new file mode 100644 index 000000000..12caf6172 --- /dev/null +++ b/server/routers/utils/encryptValue.ts @@ -0,0 +1,18 @@ +import crypto from "crypto" + +export default function encryptValue(originalString: string) { + const encryptionKey = process.env.BOOKING_ENCRYPTION_KEY ?? "" + const bufferKey = Buffer.from(encryptionKey, "utf8") + let cipher = crypto.createCipheriv("DES-ECB", bufferKey, null) + cipher.setAutoPadding(false) + let bufferString = Buffer.from(originalString, "utf8") + let paddingSize = bufferKey.length - (bufferString.length % bufferKey.length) + let paddedStr = Buffer.concat([bufferString, Buffer.alloc(paddingSize, 0)]) + let encryptedValue = cipher + .update(paddedStr) + .toString("base64") + .replace(/\+/g, "-") + cipher.final() + + return encryptedValue +}