From 50e43bc0c312b749b416bb1cdc711c303b940bbc Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Sun, 8 Dec 2024 13:27:51 -0500 Subject: [PATCH] feat: refactor/reorganize auth routes --- app/components/Footer.tsx | 44 +++++++++++++++++++ .../_data.tsx => layouts/dashboard.tsx} | 44 +------------------ app/routes.ts | 36 ++++++++++++++- app/routes/{ => auth}/login.tsx | 2 - app/routes/{logout.tsx => auth/logout.ts} | 12 ++--- app/routes/auth/oidc-callback.ts | 17 +++++++ app/routes/oidc.callback.tsx | 13 ------ 7 files changed, 102 insertions(+), 66 deletions(-) create mode 100644 app/components/Footer.tsx rename app/{routes/_data.tsx => layouts/dashboard.tsx} (66%) rename app/routes/{ => auth}/login.tsx (96%) rename app/routes/{logout.tsx => auth/logout.ts} (52%) create mode 100644 app/routes/auth/oidc-callback.ts delete mode 100644 app/routes/oidc.callback.tsx diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx new file mode 100644 index 0000000..4a949b9 --- /dev/null +++ b/app/components/Footer.tsx @@ -0,0 +1,44 @@ +import { cn } from '~/utils/cn' +import Link from '~/components/Link' + +interface FooterProps { + url: string + debug: boolean +} + +export default function Footer({ url, debug, integration }: FooterProps) { + return ( + + ) +} + diff --git a/app/routes/_data.tsx b/app/layouts/dashboard.tsx similarity index 66% rename from app/routes/_data.tsx rename to app/layouts/dashboard.tsx index 31c0cd9..c855bb1 100644 --- a/app/routes/_data.tsx +++ b/app/layouts/dashboard.tsx @@ -4,6 +4,7 @@ import { ProgressBar } from 'react-aria-components' import { ErrorPopup } from '~/components/Error' import Header from '~/components/Header' +import Footer from '~/components/Footer' import Link from '~/components/Link' import { cn } from '~/utils/cn' import { loadContext } from '~/utils/config/headplane' @@ -17,14 +18,12 @@ export async function loader({ request }: LoaderFunctionArgs) { } try { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion await pull('v1/apikey', session.get('hsApiKey')!) } catch (error) { if (error instanceof HeadscaleError) { // Safest to just redirect to login if we can't pull return redirect('/login', { headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention 'Set-Cookie': await destroySession(session), }, }) @@ -43,47 +42,6 @@ export async function loader({ request }: LoaderFunctionArgs) { } } -interface FooterProps { - url: string - debug: boolean -} - -function Footer({ url, debug, integration }: FooterProps) { - return ( - - ) -} - export default function Layout() { const data = useLoaderData() const nav = useNavigation() diff --git a/app/routes.ts b/app/routes.ts index 1185cfe..98aa317 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -1,3 +1,35 @@ -import { flatRoutes } from '@remix-run/fs-routes' +//import { flatRoutes } from '@remix-run/fs-routes' +import { index, layout, prefix, route } from '@remix-run/route-config' + +export default [ + // Utility Routes + index('routes/_index.tsx'), + route('/healthz', 'routes/healthz.tsx'), + + // Authentication Routes + route('/login', 'routes/auth/login.tsx'), + route('/logout', 'routes/auth/logout.ts'), + route('/oidc/callback', 'routes/auth/oidc-callback.ts'), + + // All the main logged-in dashboard routes + layout('layouts/dashboard.tsx', [ + ...prefix('/machines', [ + index('routes/_data.machines._index/route.tsx'), + route('/:id', 'routes/_data.machines.$id/route.tsx'), + ]), + ...prefix('/users', [ + index('routes/_data.users._index/route.tsx'), + ]), + ...prefix('/dns', [ + index('routes/_data.dns._index/route.tsx'), + ]), + ...prefix('/acls', [ + index('routes/_data.acls._index/route.tsx'), + ]), + ...prefix('/settings', [ + index('routes/_data.settings._index/route.tsx'), + route('/auth-keys', 'routes/_data.settings.auth-keys._index/route.tsx'), + ]), + ]) +] -export default flatRoutes() diff --git a/app/routes/login.tsx b/app/routes/auth/login.tsx similarity index 96% rename from app/routes/login.tsx rename to app/routes/auth/login.tsx index 67a0e13..6eebd7f 100644 --- a/app/routes/login.tsx +++ b/app/routes/auth/login.tsx @@ -17,7 +17,6 @@ export async function loader({ request }: LoaderFunctionArgs) { if (session.has('hsApiKey')) { return redirect('/machines', { headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention 'Set-Cookie': await commitSession(session), }, }) @@ -74,7 +73,6 @@ export async function action({ request }: ActionFunctionArgs) { return redirect('/machines', { headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention 'Set-Cookie': await commitSession(session, { maxAge: expiresIn, }), diff --git a/app/routes/logout.tsx b/app/routes/auth/logout.ts similarity index 52% rename from app/routes/logout.tsx rename to app/routes/auth/logout.ts index 8539078..c5ddab2 100644 --- a/app/routes/logout.tsx +++ b/app/routes/auth/logout.ts @@ -1,14 +1,14 @@ -import { type ActionFunctionArgs, redirect } from '@remix-run/node' - +import { ActionFunctionArgs, redirect } from '@remix-run/node' import { destroySession, getSession } from '~/utils/sessions' +export async function loader() { + return redirect('/machines') +} + export async function action({ request }: ActionFunctionArgs) { const session = await getSession(request.headers.get('Cookie')) - const returnTo = new URL(request.url).pathname - - return redirect(`/login?returnTo=${returnTo}`, { + return redirect('/login', { headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention 'Set-Cookie': await destroySession(session) } }) diff --git a/app/routes/auth/oidc-callback.ts b/app/routes/auth/oidc-callback.ts new file mode 100644 index 0000000..e2a197b --- /dev/null +++ b/app/routes/auth/oidc-callback.ts @@ -0,0 +1,17 @@ +import { LoaderFunctionArgs, data } from '@remix-run/node' +import { loadContext } from '~/utils/config/headplane' +import { finishOidc } from '~/utils/oidc' + +export async function loader({ request }: LoaderFunctionArgs) { + try { + const context = await loadContext() + if (!context.oidc) { + throw new Error('An invalid OIDC configuration was provided') + } + + return finishOidc(context.oidc, request) + } catch (error) { + // Gracefully present OIDC errors + return data({ error }, { status: 500 }) + } +} diff --git a/app/routes/oidc.callback.tsx b/app/routes/oidc.callback.tsx deleted file mode 100644 index ed40b87..0000000 --- a/app/routes/oidc.callback.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { type LoaderFunctionArgs } from '@remix-run/node' - -import { loadContext } from '~/utils/config/headplane' -import { finishOidc } from '~/utils/oidc' - -export async function loader({ request }: LoaderFunctionArgs) { - const context = await loadContext() - if (!context.oidc) { - throw new Error('An invalid OIDC configuration was provided') - } - - return finishOidc(context.oidc, request) -}