diff --git a/src/pages/[slug].tsx b/src/pages/[slug].tsx
index d2577e01a..3417ea0f6 100644
--- a/src/pages/[slug].tsx
+++ b/src/pages/[slug].tsx
@@ -6,6 +6,7 @@ import AppShelf from '../components/AppShelf/AppShelf';
import LoadConfigComponent from '../components/Config/LoadConfig';
import { Config } from '../tools/types';
import { useConfig } from '../tools/state';
+import Layout from '../components/layout/Layout';
export async function getServerSideProps(
context: GetServerSidePropsContext
@@ -46,9 +47,9 @@ export default function HomePage(props: any) {
setConfig(initialConfig);
}, [initialConfig]);
return (
- <>
+
- >
+
);
}
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 5cbf81843..ca0346781 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -44,9 +44,7 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) {
>
-
-
-
+
diff --git a/src/pages/_middleware.ts b/src/pages/_middleware.ts
new file mode 100644
index 000000000..0975e7c9e
--- /dev/null
+++ b/src/pages/_middleware.ts
@@ -0,0 +1,15 @@
+import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';
+
+export function middleware(req: NextRequest, ev: NextFetchEvent) {
+ const ok = req.cookies.password === process.env.PASSWORD;
+ const url = req.nextUrl.clone();
+ if (
+ !ok &&
+ url.pathname !== '/login' &&
+ process.env.PASSWORD &&
+ url.pathname !== '/api/configs/tryPassword'
+ ) {
+ url.pathname = '/login';
+ }
+ return NextResponse.rewrite(url);
+}
diff --git a/src/pages/api/configs/tryPassword.tsx b/src/pages/api/configs/tryPassword.tsx
new file mode 100644
index 000000000..18432739b
--- /dev/null
+++ b/src/pages/api/configs/tryPassword.tsx
@@ -0,0 +1,25 @@
+import { NextApiRequest, NextApiResponse } from 'next';
+
+function Post(req: NextApiRequest, res: NextApiResponse) {
+ const { tried } = req.body;
+ // Try to match the password with the PASSWORD env variable
+ if (tried === process.env.PASSWORD) {
+ return res.status(200).json({
+ success: true,
+ });
+ }
+ return res.status(200).json({
+ success: false,
+ });
+}
+
+export default async (req: NextApiRequest, res: NextApiResponse) => {
+ // Filter out if the reuqest is a POST or a GET
+ if (req.method === 'POST') {
+ return Post(req, res);
+ }
+ return res.status(405).json({
+ statusCode: 405,
+ message: 'Method not allowed',
+ });
+};
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 9ae8c33ff..c982f3940 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -7,6 +7,7 @@ import { Config } from '../tools/types';
import { useConfig } from '../tools/state';
import { migrateToIdConfig } from '../tools/migrate';
import { getConfig } from '../tools/getConfig';
+import Layout from '../components/layout/Layout';
export async function getServerSideProps({
req,
@@ -33,9 +34,9 @@ export default function HomePage(props: any) {
setConfig(migratedConfig);
}, [initialConfig]);
return (
- <>
+
- >
+
);
}
diff --git a/src/pages/login.tsx b/src/pages/login.tsx
new file mode 100644
index 000000000..b6042106b
--- /dev/null
+++ b/src/pages/login.tsx
@@ -0,0 +1,111 @@
+import React from 'react';
+import { PasswordInput, Anchor, Paper, Title, Text, Container, Group, Button } from '@mantine/core';
+import { setCookies } from 'cookies-next';
+import { useForm } from '@mantine/hooks';
+import { showNotification, updateNotification } from '@mantine/notifications';
+import axios from 'axios';
+import { IconCheck, IconX } from '@tabler/icons';
+
+// TODO: Add links to the wiki articles about the login process.
+export default function AuthenticationTitle() {
+ const form = useForm({
+ initialValues: {
+ password: '',
+ },
+ });
+ return (
+
+ ({ fontFamily: `Greycliff CF, ${theme.fontFamily}`, fontWeight: 900 })}
+ >
+ Welcome back!
+
+
+ Please enter the{' '}
+ href="#" size="sm" onClick={(event) => event.preventDefault()}>
+ password
+
+
+
+
+
+
+
+ );
+}