From 5b3a236194884243038cb0479c4f1dff770c5133 Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Fri, 27 Oct 2023 23:10:42 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20401=20page=20(#1508)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../en/layout/errors/access-denied.json | 5 ++ src/images/undraw_secure_login_pdn4.svg | 1 + src/pages/401.tsx | 55 +++++++++++++++++++ src/pages/board/[slug]/customize.tsx | 23 ++++---- src/pages/board/index.tsx | 13 ++--- src/pages/manage/index.tsx | 8 +-- src/pages/manage/tools/docker.tsx | 20 +++---- src/pages/manage/users/index.tsx | 9 ++- src/pages/manage/users/invites.tsx | 9 ++- src/tools/server/loginBuilder.ts | 8 ++- src/tools/server/translation-namespaces.ts | 2 + 11 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 public/locales/en/layout/errors/access-denied.json create mode 100644 src/images/undraw_secure_login_pdn4.svg create mode 100644 src/pages/401.tsx diff --git a/public/locales/en/layout/errors/access-denied.json b/public/locales/en/layout/errors/access-denied.json new file mode 100644 index 000000000..d1132e481 --- /dev/null +++ b/public/locales/en/layout/errors/access-denied.json @@ -0,0 +1,5 @@ +{ + "title": "Access denied", + "text": "You do not have sufficient permissions to access this page. If you believe, that this is not intentional, please contact your administrator.", + "switchAccount": "Switch to a different account" +} \ No newline at end of file diff --git a/src/images/undraw_secure_login_pdn4.svg b/src/images/undraw_secure_login_pdn4.svg new file mode 100644 index 000000000..97c35f957 --- /dev/null +++ b/src/images/undraw_secure_login_pdn4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pages/401.tsx b/src/pages/401.tsx new file mode 100644 index 000000000..e9bf268bb --- /dev/null +++ b/src/pages/401.tsx @@ -0,0 +1,55 @@ +import { Button, Center, Stack, Title, Text, createStyles } from "@mantine/core"; +import { useTranslation } from "next-i18next"; +import Image from "next/image"; +import Head from "next/head"; +import { MainLayout } from "~/components/layout/Templates/MainLayout"; +import Link from "next/link"; + +import imageAccessDenied from '~/images/undraw_secure_login_pdn4.svg'; +import { pageAccessDeniedNamespaces } from "~/tools/server/translation-namespaces"; +import { getServerSideTranslations } from "~/tools/server/getServerSideTranslations"; +import { GetServerSidePropsContext } from "next"; + +export default function Custom401() { + const { classes } = useStyles(); + const { t } = useTranslation('layout/errors/access-denied'); + return ( + +
+ + Access denied • Homarr + + + + {t('title')} + {t('text')} + + + +
+
+ ) +} + +export async function getStaticProps({ req, res, locale }: GetServerSidePropsContext) { + const translations = await getServerSideTranslations( + [...pageAccessDeniedNamespaces, 'common'], + locale, + req, + res + ); + return { + props: { + ...translations, + }, + }; +} + +const useStyles = createStyles(() => ({ + image: { + margin: '0 auto', + display: 'block', + }, +})); \ No newline at end of file diff --git a/src/pages/board/[slug]/customize.tsx b/src/pages/board/[slug]/customize.tsx index bb78e96ff..45d465b54 100644 --- a/src/pages/board/[slug]/customize.tsx +++ b/src/pages/board/[slug]/customize.tsx @@ -44,6 +44,7 @@ import { MainLayout } from '~/components/layout/Templates/MainLayout'; import { createTrpcServersideHelpers } from '~/server/api/helper'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { firstUpperCase } from '~/tools/shared/strings'; import { api } from '~/utils/api'; import { useI18nZodResolver } from '~/utils/i18n-zod-resolver'; @@ -275,22 +276,22 @@ const routeParamsSchema = z.object({ slug: z.string(), }); -export const getServerSideProps: GetServerSideProps = async ({ req, res, locale, params }) => { - const routeParams = routeParamsSchema.safeParse(params); +export const getServerSideProps: GetServerSideProps = async (context) => { + const routeParams = routeParamsSchema.safeParse(context.params); if (!routeParams.success) { return { notFound: true, }; } - const session = await getServerAuthSession({ req, res }); - if (!session?.user.isAdmin) { - return { - notFound: true, - }; + const session = await getServerAuthSession({ req: context.req, res: context.res }); + + const result = checkForSessionOrAskForLogin(context, session, () => session?.user.isAdmin == true); + if (result) { + return result; } - const helpers = await createTrpcServersideHelpers({ req, res }); + const helpers = await createTrpcServersideHelpers({ req: context.req, res: context.res }); const config = await helpers.config.byName.fetch({ name: routeParams.data.slug }); @@ -305,9 +306,9 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, locale, 'settings/customization/gridstack', 'settings/customization/access', ], - locale, - req, - res + context.locale, + context.req, + context.res ); return { diff --git a/src/pages/board/index.tsx b/src/pages/board/index.tsx index 6a283e919..95f100d33 100644 --- a/src/pages/board/index.tsx +++ b/src/pages/board/index.tsx @@ -11,6 +11,7 @@ import { getDefaultBoardAsync } from '~/server/db/queries/userSettings'; import { userSettings } from '~/server/db/schema'; import { getFrontendConfig } from '~/tools/config/getFrontendConfig'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { boardNamespaces } from '~/tools/server/translation-namespaces'; import { ConfigType } from '~/types/config'; @@ -45,15 +46,9 @@ export const getServerSideProps: GetServerSideProps = a ); const config = await getFrontendConfig(boardName); - if (!config?.settings?.access?.allowGuests && !session?.user) { - return { - notFound: true, - props: { - primaryColor: config.settings.customization.colors.primary, - secondaryColor: config.settings.customization.colors.secondary, - primaryShade: config.settings.customization.colors.shade, - }, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => true); + if (result) { + return result; } return { diff --git a/src/pages/manage/index.tsx b/src/pages/manage/index.tsx index 0386a274b..281a7ef8d 100644 --- a/src/pages/manage/index.tsx +++ b/src/pages/manage/index.tsx @@ -23,6 +23,7 @@ import { getServerSideTranslations } from '~/tools/server/getServerSideTranslati import { OnlyKeysWithStructure } from '~/types/helpers'; import { type quickActions } from '../../../public/locales/en/manage/index.json'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; const ManagementPage = () => { const { t } = useTranslation('manage/index'); @@ -118,10 +119,9 @@ const QuickActionCard = ({ type, href }: QuickActionCardProps) => { export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); - if (!session?.user) { - return { - notFound: true, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => true); + if (result) { + return result; } const translations = await getServerSideTranslations( diff --git a/src/pages/manage/tools/docker.tsx b/src/pages/manage/tools/docker.tsx index 90793a973..f0cc714d4 100644 --- a/src/pages/manage/tools/docker.tsx +++ b/src/pages/manage/tools/docker.tsx @@ -11,6 +11,7 @@ import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { dockerRouter } from '~/server/api/routers/docker/router'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { boardNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; @@ -54,24 +55,23 @@ export default function DockerPage({ ); } -export const getServerSideProps: GetServerSideProps = async ({ locale, req, res }) => { - const session = await getServerAuthSession({ req, res }); - if (!session?.user.isAdmin) { - return { - notFound: true, - }; +export const getServerSideProps: GetServerSideProps = async (context) => { + const session = await getServerAuthSession({ req: context.req, res: context.res }); + const result = checkForSessionOrAskForLogin(context, session, () => session?.user.isAdmin == true); + if (result) { + return result; } const caller = dockerRouter.createCaller({ session: session, - cookies: req.cookies, + cookies: context.req.cookies, }); const translations = await getServerSideTranslations( [...boardNamespaces, 'layout/manage', 'tools/docker'], - locale, - req, - res + context.locale, + context.req, + context.res ); let containers = []; diff --git a/src/pages/manage/users/index.tsx b/src/pages/manage/users/index.tsx index fcf32d686..4a3b3176b 100644 --- a/src/pages/manage/users/index.tsx +++ b/src/pages/manage/users/index.tsx @@ -26,6 +26,7 @@ import { openDeleteUserModal } from '~/components/Manage/User/delete-user.modal' import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; @@ -180,11 +181,9 @@ const ManageUsersPage = () => { export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); - - if (!session?.user.isAdmin) { - return { - notFound: true, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => session?.user.isAdmin == true); + if (result) { + return result; } const translations = await getServerSideTranslations( diff --git a/src/pages/manage/users/invites.tsx b/src/pages/manage/users/invites.tsx index 5d491337f..526524633 100644 --- a/src/pages/manage/users/invites.tsx +++ b/src/pages/manage/users/invites.tsx @@ -20,6 +20,7 @@ import { openCreateInviteModal } from '~/components/Manage/User/Invite/create-in import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; +import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; @@ -152,11 +153,9 @@ const useStyles = createStyles(() => ({ export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); - - if (!session?.user.isAdmin) { - return { - notFound: true, - }; + const result = checkForSessionOrAskForLogin(ctx, session, () => session?.user.isAdmin == true); + if (result) { + return result; } const translations = await getServerSideTranslations( diff --git a/src/tools/server/loginBuilder.ts b/src/tools/server/loginBuilder.ts index 3f84f2b7e..297076c47 100644 --- a/src/tools/server/loginBuilder.ts +++ b/src/tools/server/loginBuilder.ts @@ -4,7 +4,9 @@ import { GetServerSidePropsResult, PreviewData, } from 'next'; + import { Session } from 'next-auth'; + import { ParsedUrlQuery } from 'querystring'; export const checkForSessionOrAskForLogin = ( @@ -13,7 +15,6 @@ export const checkForSessionOrAskForLogin = ( accessCallback: () => boolean ): GetServerSidePropsResult | undefined => { if (!session?.user) { - console.log('detected logged out user!'); return { props: {}, redirect: { @@ -26,7 +27,10 @@ export const checkForSessionOrAskForLogin = ( if (!accessCallback()) { return { props: {}, - notFound: true, + redirect: { + destination: '/401', + permanent: false + } }; } diff --git a/src/tools/server/translation-namespaces.ts b/src/tools/server/translation-namespaces.ts index 695edcb2d..138a0a962 100644 --- a/src/tools/server/translation-namespaces.ts +++ b/src/tools/server/translation-namespaces.ts @@ -51,3 +51,5 @@ export const manageNamespaces = [ export const loginNamespaces = ['authentication/login']; export const pageNotFoundNamespaces = ['layout/errors/not-found']; + +export const pageAccessDeniedNamespaces = ['layout/errors/access-denied'];