From 5a0ba1ee058cd6475ee4ca8ca1bb0696143661ce Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Sat, 17 Aug 2024 23:18:36 +0200 Subject: [PATCH 1/6] added base url --- src/components/adminPage/mail/mailForgotPasswordTemplate.tsx | 2 +- src/components/adminPage/mail/mailNotificationTemplate.tsx | 2 +- .../adminPage/mail/mailOrganizationInviteTemplate.tsx | 2 +- src/components/adminPage/mail/mailUserInviteTemplate.tsx | 2 +- src/components/networkByIdPage/networkMtu.tsx | 2 +- src/components/networkByIdPage/networkMulticast.tsx | 2 +- src/middleware.ts | 4 +++- src/pages/admin/mail/index.tsx | 2 +- src/pages/auth/login/index.tsx | 2 +- src/pages/organization/[orgid]/admin/network/index.tsx | 2 +- src/pages/user-settings/network/index.tsx | 2 +- 11 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/components/adminPage/mail/mailForgotPasswordTemplate.tsx b/src/components/adminPage/mail/mailForgotPasswordTemplate.tsx index 6017eade..be5c1e1b 100644 --- a/src/components/adminPage/mail/mailForgotPasswordTemplate.tsx +++ b/src/components/adminPage/mail/mailForgotPasswordTemplate.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from "react"; import { api } from "~/utils/api"; import { toast } from "react-hot-toast"; import cn from "classnames"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useTrpcApiErrorHandler, useTrpcApiSuccessHandler, diff --git a/src/components/adminPage/mail/mailNotificationTemplate.tsx b/src/components/adminPage/mail/mailNotificationTemplate.tsx index dece3461..bf89db1c 100644 --- a/src/components/adminPage/mail/mailNotificationTemplate.tsx +++ b/src/components/adminPage/mail/mailNotificationTemplate.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { api } from "~/utils/api"; import { toast } from "react-hot-toast"; import cn from "classnames"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useTrpcApiErrorHandler, useTrpcApiSuccessHandler, diff --git a/src/components/adminPage/mail/mailOrganizationInviteTemplate.tsx b/src/components/adminPage/mail/mailOrganizationInviteTemplate.tsx index d52843c6..a744513d 100644 --- a/src/components/adminPage/mail/mailOrganizationInviteTemplate.tsx +++ b/src/components/adminPage/mail/mailOrganizationInviteTemplate.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { api } from "~/utils/api"; import { toast } from "react-hot-toast"; import cn from "classnames"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useTrpcApiErrorHandler, useTrpcApiSuccessHandler, diff --git a/src/components/adminPage/mail/mailUserInviteTemplate.tsx b/src/components/adminPage/mail/mailUserInviteTemplate.tsx index 76484010..4f43cfd7 100644 --- a/src/components/adminPage/mail/mailUserInviteTemplate.tsx +++ b/src/components/adminPage/mail/mailUserInviteTemplate.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from "react"; import { api } from "~/utils/api"; import { toast } from "react-hot-toast"; import cn from "classnames"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useTrpcApiErrorHandler, useTrpcApiSuccessHandler, diff --git a/src/components/networkByIdPage/networkMtu.tsx b/src/components/networkByIdPage/networkMtu.tsx index 1764ec8e..cd4930c2 100644 --- a/src/components/networkByIdPage/networkMtu.tsx +++ b/src/components/networkByIdPage/networkMtu.tsx @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; import { useState, useEffect } from "react"; import { api } from "~/utils/api"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useTrpcApiErrorHandler, useTrpcApiSuccessHandler, diff --git a/src/components/networkByIdPage/networkMulticast.tsx b/src/components/networkByIdPage/networkMulticast.tsx index ef4ad1ac..52dc2fc5 100644 --- a/src/components/networkByIdPage/networkMulticast.tsx +++ b/src/components/networkByIdPage/networkMulticast.tsx @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; import { useState, useEffect } from "react"; import { api } from "~/utils/api"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useTrpcApiErrorHandler, useTrpcApiSuccessHandler, diff --git a/src/middleware.ts b/src/middleware.ts index d97f8c12..be3f1540 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -17,6 +17,8 @@ export const config = { const PUBLIC_FILE = /\.(.*)$/; export async function middleware(req: NextRequest) { + const baseUrl = process.env.NEXTAUTH_URL || "http://localhost:3000"; + if ( req.nextUrl.pathname.startsWith("/_next") || req.nextUrl.pathname.includes("/api/") || @@ -53,7 +55,7 @@ export async function middleware(req: NextRequest) { return NextResponse.redirect( new URL( `/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`, - req.url, + baseUrl, ), ); } diff --git a/src/pages/admin/mail/index.tsx b/src/pages/admin/mail/index.tsx index 3203ce00..92187ee2 100644 --- a/src/pages/admin/mail/index.tsx +++ b/src/pages/admin/mail/index.tsx @@ -6,7 +6,7 @@ import { type GlobalOptions } from "@prisma/client"; import MailUserInviteTemplate from "~/components/adminPage/mail/mailUserInviteTemplate"; import ForgotPasswordMailTemplate from "~/components/adminPage/mail/mailForgotPasswordTemplate"; import NotificationTemplate from "~/components/adminPage/mail/mailNotificationTemplate"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import OrganizationInviteTemplate from "~/components/adminPage/mail/mailOrganizationInviteTemplate"; import { useTrpcApiErrorHandler, diff --git a/src/pages/auth/login/index.tsx b/src/pages/auth/login/index.tsx index 780771e8..feeaffb7 100644 --- a/src/pages/auth/login/index.tsx +++ b/src/pages/auth/login/index.tsx @@ -11,7 +11,7 @@ import { api } from "~/utils/api"; import { useRouter } from "next/router"; import classNames from "classnames"; import { ErrorCode, getErrorMessage } from "~/utils/errorCode"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; const Login = ({ title, oauthExclusiveLogin, oauthEnabled }) => { const t = useTranslations(); diff --git a/src/pages/organization/[orgid]/admin/network/index.tsx b/src/pages/organization/[orgid]/admin/network/index.tsx index 34c7096a..467aa2c3 100644 --- a/src/pages/organization/[orgid]/admin/network/index.tsx +++ b/src/pages/organization/[orgid]/admin/network/index.tsx @@ -1,7 +1,7 @@ import { type ReactElement } from "react"; import { LayoutOrganizationAuthenticated } from "~/components/layouts/layout"; import { api } from "~/utils/api"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { useRouter } from "next/router"; import MenuSectionDividerWrapper from "~/components/shared/menuSectionDividerWrapper"; diff --git a/src/pages/user-settings/network/index.tsx b/src/pages/user-settings/network/index.tsx index f2e5dcfa..9e4036d2 100644 --- a/src/pages/user-settings/network/index.tsx +++ b/src/pages/user-settings/network/index.tsx @@ -1,7 +1,7 @@ import { type ReactElement } from "react"; import { LayoutAuthenticated } from "~/components/layouts/layout"; import { api } from "~/utils/api"; -import { useTranslations } from "use-intl"; +import { useTranslations } from "next-intl"; import { User, UserOptions } from "@prisma/client"; import MenuSectionDividerWrapper from "~/components/shared/menuSectionDividerWrapper"; From 11375c12541fa320e492382e23206f5b92bc1749 Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Sat, 17 Aug 2024 23:48:17 +0200 Subject: [PATCH 2/6] x-forwarded-host --- src/middleware.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/middleware.ts b/src/middleware.ts index be3f1540..ac4d8e2e 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -17,7 +17,25 @@ export const config = { const PUBLIC_FILE = /\.(.*)$/; export async function middleware(req: NextRequest) { - const baseUrl = process.env.NEXTAUTH_URL || "http://localhost:3000"; + // Dynamically determine the base URL from the X-Forwarded-Host and X-Forwarded-Proto headers + const forwardedHost = req.headers.get("x-forwarded-host"); + const forwardedProto = req.headers.get("x-forwarded-proto"); + + let protocol: string; + let host: string; + + if (forwardedHost && forwardedProto) { + // Use the forwarded headers if they exist + host = forwardedHost; + protocol = forwardedProto; + } else { + // Fallback to parsing the req.url + const url = new URL(req.url); + host = url.host; + protocol = url.protocol.slice(0, -1); // Remove the trailing colon from protocol + } + + const baseUrl = `${protocol}://${host}`; if ( req.nextUrl.pathname.startsWith("/_next") || From 728b39cc5ba8782d4a854d893c5f59be24a36f14 Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Sun, 18 Aug 2024 17:16:56 +0200 Subject: [PATCH 3/6] host --- package.json | 4 ++-- src/middleware.ts | 39 ++++++++++----------------------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index a5f473c7..7835fc92 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "build": "next build", - "dev": "WATCHPACK_POLLING=false next dev", + "dev": "WATCHPACK_POLLING=false next dev --hostname 127.0.0.1", "postinstall": "prisma generate", "lint": "biome check src", "lint:fix": "biome check src --apply", @@ -107,4 +107,4 @@ "prisma": { "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts" } -} +} \ No newline at end of file diff --git a/src/middleware.ts b/src/middleware.ts index ac4d8e2e..723fdd17 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -17,26 +17,6 @@ export const config = { const PUBLIC_FILE = /\.(.*)$/; export async function middleware(req: NextRequest) { - // Dynamically determine the base URL from the X-Forwarded-Host and X-Forwarded-Proto headers - const forwardedHost = req.headers.get("x-forwarded-host"); - const forwardedProto = req.headers.get("x-forwarded-proto"); - - let protocol: string; - let host: string; - - if (forwardedHost && forwardedProto) { - // Use the forwarded headers if they exist - host = forwardedHost; - protocol = forwardedProto; - } else { - // Fallback to parsing the req.url - const url = new URL(req.url); - host = url.host; - protocol = url.protocol.slice(0, -1); // Remove the trailing colon from protocol - } - - const baseUrl = `${protocol}://${host}`; - if ( req.nextUrl.pathname.startsWith("/_next") || req.nextUrl.pathname.includes("/api/") || @@ -44,6 +24,7 @@ export async function middleware(req: NextRequest) { ) { return; } + // Handle automatic locale detection if (req.nextUrl.locale === "default") { const fallbackLocale = "en"; @@ -51,7 +32,6 @@ export async function middleware(req: NextRequest) { let preferredLocale = fallbackLocale; if (acceptLanguageHeader) { - // Parse the Accept-Language header and sort by quality score const locales = acceptLanguageHeader .split(",") .map((lang) => { @@ -61,21 +41,22 @@ export async function middleware(req: NextRequest) { quality: qValue ? parseFloat(qValue) : 1, }; }) - .sort((a, b) => b.quality - a.quality); // Sort based on quality values - // Select the first supported locale with the highest quality score + .sort((a, b) => b.quality - a.quality); const matchedLocale = locales.find((l) => supportedLocales.includes(l.locale)); if (matchedLocale) { preferredLocale = matchedLocale.locale; } } - // Redirect to the preferred locale if it's different from the current one + + // Use the host from the request headers + const hostname = req.headers.get("host") || ""; + if (preferredLocale !== req.nextUrl.locale) { - return NextResponse.redirect( - new URL( - `/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`, - baseUrl, - ), + const newUrl = new URL( + `/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`, + `${req.nextUrl.protocol}//${hostname}`, ); + return NextResponse.redirect(newUrl); } } } From 18832002f0b5ef3b1a330a9c4bacee4fd3293434 Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Mon, 19 Aug 2024 06:09:26 +0000 Subject: [PATCH 4/6] middleware --- src/middleware.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index 723fdd17..ca2d7389 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -25,6 +25,9 @@ export async function middleware(req: NextRequest) { return; } + const baseUrl = + process.env.HOSTNAME === "127.0.0.1" ? process.env.NEXTAUTH_URL : req.url; + // Handle automatic locale detection if (req.nextUrl.locale === "default") { const fallbackLocale = "en"; @@ -32,6 +35,7 @@ export async function middleware(req: NextRequest) { let preferredLocale = fallbackLocale; if (acceptLanguageHeader) { + // Parse the Accept-Language header and sort by quality score const locales = acceptLanguageHeader .split(",") .map((lang) => { @@ -41,22 +45,22 @@ export async function middleware(req: NextRequest) { quality: qValue ? parseFloat(qValue) : 1, }; }) - .sort((a, b) => b.quality - a.quality); + .sort((a, b) => b.quality - a.quality); // Sort based on quality values + // Select the first supported locale with the highest quality score const matchedLocale = locales.find((l) => supportedLocales.includes(l.locale)); if (matchedLocale) { preferredLocale = matchedLocale.locale; } } - // Use the host from the request headers - const hostname = req.headers.get("host") || ""; - + // Redirect to the preferred locale if it's different from the current one if (preferredLocale !== req.nextUrl.locale) { - const newUrl = new URL( - `/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`, - `${req.nextUrl.protocol}//${hostname}`, + return NextResponse.redirect( + new URL( + `/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`, + baseUrl, + ), ); - return NextResponse.redirect(newUrl); } } } From 4d9408887c8b96a75ae647c63a68f6d4414f257a Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Mon, 19 Aug 2024 08:00:03 +0000 Subject: [PATCH 5/6] let nextjs handle locale redirects --- next.config.mjs | 14 ++++++++-- package.json | 2 +- src/middleware.ts | 66 --------------------------------------------- src/pages/index.tsx | 31 --------------------- 4 files changed, 13 insertions(+), 100 deletions(-) delete mode 100644 src/middleware.ts delete mode 100644 src/pages/index.tsx diff --git a/next.config.mjs b/next.config.mjs index 3aeeb123..12011193 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -27,12 +27,22 @@ const config = { * @see https://github.com/vercel/next.js/issues/41980 */ i18n: { - defaultLocale: "default", - locales: ["default", "en", "fr", "no", "pl", "zh-tw", "zh", "es"], + defaultLocale: "en", + // localeDetection: false, + locales: ["en", "fr", "no", "pl", "zh-tw", "zh", "es"], }, trailingSlash: true, eslint: { ignoreDuringBuilds: true, }, + async redirects() { + return [ + { + source: "/", + destination: "/auth/login", + permanent: true, + }, + ]; + }, }; export default config; diff --git a/package.json b/package.json index 7835fc92..5fe20f5c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "build": "next build", - "dev": "WATCHPACK_POLLING=false next dev --hostname 127.0.0.1", + "dev": "WATCHPACK_POLLING=false next dev", "postinstall": "prisma generate", "lint": "biome check src", "lint:fix": "biome check src --apply", diff --git a/src/middleware.ts b/src/middleware.ts deleted file mode 100644 index ca2d7389..00000000 --- a/src/middleware.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { supportedLocales } from "./locales/lang"; - -// run middleware on these paths -export const config = { - matcher: [ - "/dashboard/:path*", - "/organization/:path*", - "/network/:path*", - "/central/:path*", - "/user-settings/:path*", - "/auth/:path*", - "/admin/:path*", - ], -}; - -const PUBLIC_FILE = /\.(.*)$/; - -export async function middleware(req: NextRequest) { - if ( - req.nextUrl.pathname.startsWith("/_next") || - req.nextUrl.pathname.includes("/api/") || - PUBLIC_FILE.test(req.nextUrl.pathname) - ) { - return; - } - - const baseUrl = - process.env.HOSTNAME === "127.0.0.1" ? process.env.NEXTAUTH_URL : req.url; - - // Handle automatic locale detection - if (req.nextUrl.locale === "default") { - const fallbackLocale = "en"; - const acceptLanguageHeader = req.headers.get("accept-language"); - let preferredLocale = fallbackLocale; - - if (acceptLanguageHeader) { - // Parse the Accept-Language header and sort by quality score - const locales = acceptLanguageHeader - .split(",") - .map((lang) => { - const [locale, qValue] = lang.trim().split(";q="); - return { - locale: locale.split("-")[0], - quality: qValue ? parseFloat(qValue) : 1, - }; - }) - .sort((a, b) => b.quality - a.quality); // Sort based on quality values - // Select the first supported locale with the highest quality score - const matchedLocale = locales.find((l) => supportedLocales.includes(l.locale)); - if (matchedLocale) { - preferredLocale = matchedLocale.locale; - } - } - - // Redirect to the preferred locale if it's different from the current one - if (preferredLocale !== req.nextUrl.locale) { - return NextResponse.redirect( - new URL( - `/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`, - baseUrl, - ), - ); - } - } -} diff --git a/src/pages/index.tsx b/src/pages/index.tsx deleted file mode 100644 index c230780f..00000000 --- a/src/pages/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { type GetServerSideProps, type GetServerSidePropsContext } from "next"; -import { type Session } from "next-auth"; -import { getSession } from "next-auth/react"; -interface Props { - auth?: Session["user"]; -} - -export const getServerSideProps: GetServerSideProps = async ( - context: GetServerSidePropsContext, -) => { - const session = await getSession(context); - if (session && "user" in session && session?.user) { - return { - redirect: { - destination: "/network", - permanent: false, - }, - }; - } - - return { - redirect: { - destination: "/auth/login", - permanent: false, - }, - }; -}; -// No component is needed as we redirect -export default function LandingPage() { - return null; -} From 0b7051f8a034fef1c24ce3cfbf8d7d5aa2d53f2e Mon Sep 17 00:00:00 2001 From: Bernt Christian Egeland Date: Mon, 19 Aug 2024 08:40:35 +0000 Subject: [PATCH 6/6] locale --- src/pages/auth/mfaRecovery/reset/index.tsx | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/pages/auth/mfaRecovery/reset/index.tsx b/src/pages/auth/mfaRecovery/reset/index.tsx index d5595cec..823cbe60 100644 --- a/src/pages/auth/mfaRecovery/reset/index.tsx +++ b/src/pages/auth/mfaRecovery/reset/index.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { useRouter } from "next/router"; import { api } from "~/utils/api"; +import { Session } from "next-auth"; import { toast } from "react-hot-toast"; import { type ErrorData, type ZodErrorFieldErrors } from "~/types/errorHandling"; import Head from "next/head"; @@ -9,6 +10,8 @@ import FormInput from "~/components/auth/formInput"; import FormSubmitButtons from "~/components/auth/formSubmitButton"; import { ErrorCode } from "~/utils/errorCode"; import { useTranslations } from "next-intl"; +import { GetServerSideProps, GetServerSidePropsContext } from "next"; +import { getSession } from "next-auth/react"; const MfaRecoveryReset = () => { const t = useTranslations(); @@ -181,4 +184,33 @@ const MfaRecoveryReset = () => { ); }; +interface Props { + auth?: Session["user"]; +} +export const getServerSideProps: GetServerSideProps = async ( + context: GetServerSidePropsContext, +) => { + const session = await getSession(context); + if (!session || !("user" in session) || !session.user) { + return { + props: { + messages: (await import(`~/locales/${context.locale}/common.json`)).default, + }, + }; + } + + if (session.user) { + return { + redirect: { + destination: "/network", + permanent: false, + }, + }; + } + + return { + props: { auth: session.user }, + }; +}; + export default MfaRecoveryReset;