diff --git a/lib/authenticate.ts b/lib/authenticate.ts index 0880755..8f451f4 100644 --- a/lib/authenticate.ts +++ b/lib/authenticate.ts @@ -1,28 +1,18 @@ -import { IncomingMessage, ServerResponse } from 'http' - -export default function authenticate( - req: IncomingMessage, - res: ServerResponse -) { - const authHeader = req.headers.authorization - - if (!authHeader) { - res.setHeader('WWW-Authenticate', 'Basic') - res.statusCode = 401 - return null +export function authenticateAdmin({ + username, + password, +}: { + username: string + password: string +}) { + if (username !== 'admin') { + return false } - const [username, password] = Buffer.from(authHeader.split(' ')[1], 'base64') - .toString() - .split(':') - - // FIXME: pull admin password from env - if (username === 'admin' || password === 'secret') { - return { username: 'admin', role: 'admin' } + // FIXME: move at least to env variable + if (password !== 'secret') { + return false } - res.setHeader('WWW-Authenticate', 'Basic') - res.statusCode = 401 - res.end() - return null + return true } diff --git a/lib/session.ts b/lib/session.ts index eb5942c..916b380 100644 --- a/lib/session.ts +++ b/lib/session.ts @@ -1,4 +1,5 @@ import { withIronSession, Handler } from 'next-iron-session' +import { getBaseURL } from '../helpers/url' const SESSION_SECRET = process.env.SESSION_SECRET || 'dev-env-default-secret-991823723' @@ -19,8 +20,17 @@ export default function withSession(handler: Handler) { export const isAdminSession = function (req: any, res: any) { const user = req?.session.get('user') if (user && user.role === 'admin') { - return true + return user } - res.status(401).end('Your are unauthorized. Best to move along...') + + const redirectTargetUrl = `${getBaseURL()}/admin/login?redirect=${encodeURIComponent( + req.url + )}` + + res.writeHead(303, { + Location: redirectTargetUrl, + }) + res.end() + return false } diff --git a/pages/admin/booking/[uuid]/bill.tsx b/pages/admin/booking/[uuid]/bill.tsx index eac6bef..f2dd88d 100644 --- a/pages/admin/booking/[uuid]/bill.tsx +++ b/pages/admin/booking/[uuid]/bill.tsx @@ -1,5 +1,5 @@ -import { GetServerSideProps } from 'next' import React, { useEffect, useState } from 'react' +import { GetServerSideProps } from 'next' import Footer from '../../../../components/footer' import Header from '../../../../components/header' import Input from '../../../../components/input' @@ -11,31 +11,26 @@ import { getMilageMax } from '../../../../db/index' import { dateFormatFrontend } from '../../../../helpers/date' import { getBillTotal } from '../../../../helpers/bill' import { getBookingStatus } from '../../../../helpers/booking' -import authenticate from '../../../../lib/authenticate' -import withSession from '../../../../lib/session' +import withSession, { isAdminSession } from '../../../../lib/session' import { getServerSideBooking } from '../../../../lib/getServerSideProps' export const getServerSideProps: GetServerSideProps = withSession( async (context) => { const { req, res } = context - const authenticatedUser = authenticate(req, res) - if (!authenticatedUser) { - // TODO: not sure if needed - req?.session.destroy() + const adminUser = isAdminSession(req, res) + + if (!adminUser) { return { props: {} } } - req.session.set('user', authenticatedUser) - await req.session.save() - const milageMax = await getMilageMax() const result = await getServerSideBooking(context) return { ...result, // TODO: have a closer look at this type issue. Seems like a bug // @ts-ignore - props: { ...result.props, milageMax }, + props: { ...result.props, milageMax, user: adminUser }, } } ) @@ -107,7 +102,7 @@ async function saveBill( return response.json() } -export default function BillPage({ +export default function BookingBillPage({ booking: bookingProp, milageMax, }: { diff --git a/pages/admin/booking/[uuid]/index.tsx b/pages/admin/booking/[uuid]/index.tsx index 7ac9bea..4a8fa52 100644 --- a/pages/admin/booking/[uuid]/index.tsx +++ b/pages/admin/booking/[uuid]/index.tsx @@ -1,14 +1,35 @@ import React, { useEffect, useState } from 'react' +import { GetServerSideProps } from 'next' import Footer from '../../../../components/footer' import Header from '../../../../components/header' import Calendar from '../../../../components/calendar' +import withSession, { isAdminSession } from '../../../../lib/session' import { getServerSideBooking } from '../../../../lib/getServerSideProps' import { BookingDocument } from '../../../../db/booking' import { getBookingStatus } from '../../../../helpers/booking' import { dateFormatFrontend } from '../../../../helpers/date' import { BOOKING_STATUS } from '../../../../db/enums' -export const getServerSideProps = getServerSideBooking +export const getServerSideProps: GetServerSideProps = withSession( + async (context) => { + const { req, res } = context + + console.error('here') + const adminUser = isAdminSession(req, res) + + if (!adminUser) { + return { props: {} } + } + + const result = await getServerSideBooking(context) + return { + ...result, + // TODO: have a closer look at this type issue. Seems like a bug + // @ts-ignore + props: { ...result.props, user: adminUser }, + } + } +) async function patchBooking(uuid: string, bookingData: any) { const response = await fetch(`/api/admin/booking/${uuid}`, { diff --git a/pages/admin/login.tsx b/pages/admin/login.tsx new file mode 100644 index 0000000..cf1c6f6 --- /dev/null +++ b/pages/admin/login.tsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react' +import { useRouter } from 'next/router' +import Head from 'next/head' +import Footer from '../../components/footer' +import Header from '../../components/header' +import Input from '../../components/input' +import { getBaseURL } from '../../helpers/url' + +export default function Home() { + const router = useRouter() + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + + const isValid = !!username.length && !!password.length + + async function onSubmit(event: React.FormEvent) { + event.preventDefault() + + try { + await fetch('/api/admin/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username, + password, + }), + }).then((response) => { + if (!response.ok) { + console.error('Unable to login', response.status, response.statusText) + return + } + const redirect = Array.isArray(router.query?.redirect) + ? router.query.redirect[0] + : router.query?.redirect + + router.push(redirect || getBaseURL()) + }) + } catch (error) { + console.error('Unable to login', error) + } + } + + return ( + <> + + Pfadi Bussle Admin + + + +
+
+
+ ) => + setUsername(event.target.value) + } + /> + ) => + setPassword(event.target.value) + } + /> + +
+
+