Add 401 page (#1508)

This commit is contained in:
Manuel
2023-10-27 23:10:42 +02:00
committed by GitHub
parent 4072ebc5a5
commit 5b3a236194
11 changed files with 107 additions and 46 deletions

View File

@@ -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"
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

55
src/pages/401.tsx Normal file
View File

@@ -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 (
<MainLayout>
<Center h="100dvh" w="100dvw">
<Head>
<title>Access denied Homarr</title>
</Head>
<Stack maw={500} p="xl">
<Image className={classes.image} src={imageAccessDenied} width={200} height={200} alt="" />
<Title>{t('title')}</Title>
<Text>{t('text')}</Text>
<Button component={Link} variant="light" href="/auth/login">
{t('switchAccount')}
</Button>
</Stack>
</Center>
</MainLayout>
)
}
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',
},
}));

View File

@@ -44,6 +44,7 @@ import { MainLayout } from '~/components/layout/Templates/MainLayout';
import { createTrpcServersideHelpers } from '~/server/api/helper'; import { createTrpcServersideHelpers } from '~/server/api/helper';
import { getServerAuthSession } from '~/server/auth'; import { getServerAuthSession } from '~/server/auth';
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder';
import { firstUpperCase } from '~/tools/shared/strings'; import { firstUpperCase } from '~/tools/shared/strings';
import { api } from '~/utils/api'; import { api } from '~/utils/api';
import { useI18nZodResolver } from '~/utils/i18n-zod-resolver'; import { useI18nZodResolver } from '~/utils/i18n-zod-resolver';
@@ -275,22 +276,22 @@ const routeParamsSchema = z.object({
slug: z.string(), slug: z.string(),
}); });
export const getServerSideProps: GetServerSideProps = async ({ req, res, locale, params }) => { export const getServerSideProps: GetServerSideProps = async (context) => {
const routeParams = routeParamsSchema.safeParse(params); const routeParams = routeParamsSchema.safeParse(context.params);
if (!routeParams.success) { if (!routeParams.success) {
return { return {
notFound: true, notFound: true,
}; };
} }
const session = await getServerAuthSession({ req, res }); const session = await getServerAuthSession({ req: context.req, res: context.res });
if (!session?.user.isAdmin) {
return { const result = checkForSessionOrAskForLogin(context, session, () => session?.user.isAdmin == true);
notFound: 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 }); 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/gridstack',
'settings/customization/access', 'settings/customization/access',
], ],
locale, context.locale,
req, context.req,
res context.res
); );
return { return {

View File

@@ -11,6 +11,7 @@ import { getDefaultBoardAsync } from '~/server/db/queries/userSettings';
import { userSettings } from '~/server/db/schema'; import { userSettings } from '~/server/db/schema';
import { getFrontendConfig } from '~/tools/config/getFrontendConfig'; import { getFrontendConfig } from '~/tools/config/getFrontendConfig';
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder';
import { boardNamespaces } from '~/tools/server/translation-namespaces'; import { boardNamespaces } from '~/tools/server/translation-namespaces';
import { ConfigType } from '~/types/config'; import { ConfigType } from '~/types/config';
@@ -45,15 +46,9 @@ export const getServerSideProps: GetServerSideProps<BoardGetServerSideProps> = a
); );
const config = await getFrontendConfig(boardName); const config = await getFrontendConfig(boardName);
if (!config?.settings?.access?.allowGuests && !session?.user) { const result = checkForSessionOrAskForLogin(ctx, session, () => true);
return { if (result) {
notFound: true, return result;
props: {
primaryColor: config.settings.customization.colors.primary,
secondaryColor: config.settings.customization.colors.secondary,
primaryShade: config.settings.customization.colors.shade,
},
};
} }
return { return {

View File

@@ -23,6 +23,7 @@ import { getServerSideTranslations } from '~/tools/server/getServerSideTranslati
import { OnlyKeysWithStructure } from '~/types/helpers'; import { OnlyKeysWithStructure } from '~/types/helpers';
import { type quickActions } from '../../../public/locales/en/manage/index.json'; import { type quickActions } from '../../../public/locales/en/manage/index.json';
import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder';
const ManagementPage = () => { const ManagementPage = () => {
const { t } = useTranslation('manage/index'); const { t } = useTranslation('manage/index');
@@ -118,10 +119,9 @@ const QuickActionCard = ({ type, href }: QuickActionCardProps) => {
export const getServerSideProps: GetServerSideProps = async (ctx) => { export const getServerSideProps: GetServerSideProps = async (ctx) => {
const session = await getServerAuthSession(ctx); const session = await getServerAuthSession(ctx);
if (!session?.user) { const result = checkForSessionOrAskForLogin(ctx, session, () => true);
return { if (result) {
notFound: true, return result;
};
} }
const translations = await getServerSideTranslations( const translations = await getServerSideTranslations(

View File

@@ -11,6 +11,7 @@ import { ManageLayout } from '~/components/layout/Templates/ManageLayout';
import { dockerRouter } from '~/server/api/routers/docker/router'; import { dockerRouter } from '~/server/api/routers/docker/router';
import { getServerAuthSession } from '~/server/auth'; import { getServerAuthSession } from '~/server/auth';
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder';
import { boardNamespaces } from '~/tools/server/translation-namespaces'; import { boardNamespaces } from '~/tools/server/translation-namespaces';
import { api } from '~/utils/api'; import { api } from '~/utils/api';
@@ -54,24 +55,23 @@ export default function DockerPage({
); );
} }
export const getServerSideProps: GetServerSideProps = async ({ locale, req, res }) => { export const getServerSideProps: GetServerSideProps = async (context) => {
const session = await getServerAuthSession({ req, res }); const session = await getServerAuthSession({ req: context.req, res: context.res });
if (!session?.user.isAdmin) { const result = checkForSessionOrAskForLogin(context, session, () => session?.user.isAdmin == true);
return { if (result) {
notFound: true, return result;
};
} }
const caller = dockerRouter.createCaller({ const caller = dockerRouter.createCaller({
session: session, session: session,
cookies: req.cookies, cookies: context.req.cookies,
}); });
const translations = await getServerSideTranslations( const translations = await getServerSideTranslations(
[...boardNamespaces, 'layout/manage', 'tools/docker'], [...boardNamespaces, 'layout/manage', 'tools/docker'],
locale, context.locale,
req, context.req,
res context.res
); );
let containers = []; let containers = [];

View File

@@ -26,6 +26,7 @@ import { openDeleteUserModal } from '~/components/Manage/User/delete-user.modal'
import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { ManageLayout } from '~/components/layout/Templates/ManageLayout';
import { getServerAuthSession } from '~/server/auth'; import { getServerAuthSession } from '~/server/auth';
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder';
import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { manageNamespaces } from '~/tools/server/translation-namespaces';
import { api } from '~/utils/api'; import { api } from '~/utils/api';
@@ -180,11 +181,9 @@ const ManageUsersPage = () => {
export const getServerSideProps: GetServerSideProps = async (ctx) => { export const getServerSideProps: GetServerSideProps = async (ctx) => {
const session = await getServerAuthSession(ctx); const session = await getServerAuthSession(ctx);
const result = checkForSessionOrAskForLogin(ctx, session, () => session?.user.isAdmin == true);
if (!session?.user.isAdmin) { if (result) {
return { return result;
notFound: true,
};
} }
const translations = await getServerSideTranslations( const translations = await getServerSideTranslations(

View File

@@ -20,6 +20,7 @@ import { openCreateInviteModal } from '~/components/Manage/User/Invite/create-in
import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { ManageLayout } from '~/components/layout/Templates/ManageLayout';
import { getServerAuthSession } from '~/server/auth'; import { getServerAuthSession } from '~/server/auth';
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder';
import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { manageNamespaces } from '~/tools/server/translation-namespaces';
import { api } from '~/utils/api'; import { api } from '~/utils/api';
@@ -152,11 +153,9 @@ const useStyles = createStyles(() => ({
export const getServerSideProps: GetServerSideProps = async (ctx) => { export const getServerSideProps: GetServerSideProps = async (ctx) => {
const session = await getServerAuthSession(ctx); const session = await getServerAuthSession(ctx);
const result = checkForSessionOrAskForLogin(ctx, session, () => session?.user.isAdmin == true);
if (!session?.user.isAdmin) { if (result) {
return { return result;
notFound: true,
};
} }
const translations = await getServerSideTranslations( const translations = await getServerSideTranslations(

View File

@@ -4,7 +4,9 @@ import {
GetServerSidePropsResult, GetServerSidePropsResult,
PreviewData, PreviewData,
} from 'next'; } from 'next';
import { Session } from 'next-auth'; import { Session } from 'next-auth';
import { ParsedUrlQuery } from 'querystring'; import { ParsedUrlQuery } from 'querystring';
export const checkForSessionOrAskForLogin = ( export const checkForSessionOrAskForLogin = (
@@ -13,7 +15,6 @@ export const checkForSessionOrAskForLogin = (
accessCallback: () => boolean accessCallback: () => boolean
): GetServerSidePropsResult<any> | undefined => { ): GetServerSidePropsResult<any> | undefined => {
if (!session?.user) { if (!session?.user) {
console.log('detected logged out user!');
return { return {
props: {}, props: {},
redirect: { redirect: {
@@ -26,7 +27,10 @@ export const checkForSessionOrAskForLogin = (
if (!accessCallback()) { if (!accessCallback()) {
return { return {
props: {}, props: {},
notFound: true, redirect: {
destination: '/401',
permanent: false
}
}; };
} }

View File

@@ -51,3 +51,5 @@ export const manageNamespaces = [
export const loginNamespaces = ['authentication/login']; export const loginNamespaces = ['authentication/login'];
export const pageNotFoundNamespaces = ['layout/errors/not-found']; export const pageNotFoundNamespaces = ['layout/errors/not-found'];
export const pageAccessDeniedNamespaces = ['layout/errors/access-denied'];