diff --git a/website/.env.example b/website/.env.example index 47be83b..4dba723 100644 --- a/website/.env.example +++ b/website/.env.example @@ -22,6 +22,11 @@ SMTP_PORT=1025 # Rate limiting LIMITER_STORE=memory +# Redis +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD= + # Ally GITHUB_CLIENT_ID=******** GITHUB_CLIENT_SECRET=******** @@ -34,6 +39,4 @@ LINKEDIN_CLIENT_SECRET=******** INERTIA_PUBLIC_TZ=Europe/Lisbon INERTIA_PUBLIC_EVENT_COUNTDOWN_DATE=2025-04-11 INERTIA_PUBLIC_APP_URL=http://127.0.0.1:3333 -REDIS_HOST=127.0.0.1 -REDIS_PORT=6379 -REDIS_PASSWORD= \ No newline at end of file +INERTIA_PUBLIC_AUTH_ENABLED=true \ No newline at end of file diff --git a/website/app/controllers/authentication_controller.ts b/website/app/controllers/authentication_controller.ts index acdfb07..0f57b10 100644 --- a/website/app/controllers/authentication_controller.ts +++ b/website/app/controllers/authentication_controller.ts @@ -62,9 +62,7 @@ export default class AuthenticationController { return response.redirect().toRoute('pages:auth.verify') } - async callbackForEmailVerification({ request, view, response }: HttpContext) { - if (request.method() !== 'POST') return view.render('automatic_submit') - + async callbackForEmailVerification({ request, response }: HttpContext) { const { email } = await request.validateUsing(emailVerificationCallbackValidator) await this.userService.verifyEmail(email) diff --git a/website/app/exceptions/handler.ts b/website/app/exceptions/handler.ts index 0ab9d3b..0c1f0e6 100644 --- a/website/app/exceptions/handler.ts +++ b/website/app/exceptions/handler.ts @@ -16,11 +16,16 @@ export default class HttpExceptionHandler extends ExceptionHandler { */ protected renderStatusPages = app.inProduction + protected ignoreCodes = [] + protected ignoreStatuses = [] + protected ignoreExceptions = [] + /** * Status pages is a collection of error code range and a callback * to return the HTML contents to send as a response. */ protected statusPages: Record = { + '401': (_error, { response }) => response.status(200).send("Yikes, you're not allowed to do that"), '404': (error, { inertia }) => inertia.render('errors/not_found', { error }), '500..599': (error, { inertia }) => inertia.render('errors/server_error', { error }), } @@ -30,6 +35,7 @@ export default class HttpExceptionHandler extends ExceptionHandler { * response to the client */ async handle(error: unknown, ctx: HttpContext) { + console.log("handling", error) return super.handle(error, ctx) } diff --git a/website/app/mails/email_verification_notification.ts b/website/app/mails/email_verification_notification.ts index fe82ad7..1352e86 100644 --- a/website/app/mails/email_verification_notification.ts +++ b/website/app/mails/email_verification_notification.ts @@ -1,5 +1,5 @@ import { ReactNotification } from './base/react_notification.js' -import type { EmailVerificationProps } from '#resources/emails/authentication/email_verification' +import type { EmailVerificationProps } from '#resources/emails/auth/email_verification' export default class EmailVerificationNotification extends ReactNotification { constructor(private props: EmailVerificationProps) { @@ -9,6 +9,6 @@ export default class EmailVerificationNotification extends ReactNotification { async prepare() { this.message.to(this.props.email).subject('Confirma o teu e-mail!') - await this.jsx(() => import('#resources/emails/authentication/email_verification'), this.props) + await this.jsx(() => import('#resources/emails/auth/email_verification'), this.props) } } diff --git a/website/app/middleware/automatic_submit_middleware.ts b/website/app/middleware/automatic_submit_middleware.ts index d04afac..6b7d0df 100644 --- a/website/app/middleware/automatic_submit_middleware.ts +++ b/website/app/middleware/automatic_submit_middleware.ts @@ -2,10 +2,11 @@ import type { HttpContext } from '@adonisjs/core/http' import type { NextFn } from '@adonisjs/core/types/http' export default class AutomaticSubmitMiddleware { - async handle(_ctx: HttpContext, next: NextFn) { - // const method = request.method() - // if (method === "POST") return next() - return next() - // return view.render('automatic_submit') + async handle({ request, response, view }: HttpContext, next: NextFn) { + const method = request.method() + if (method === "POST") return next() + + // Clever hack by virk to render Edge.js templates in middlewares + return response.status(200).send(await view.render('automatic_submit')) } } \ No newline at end of file diff --git a/website/app/middleware/logout_if_authentication_disabled_middleware.ts b/website/app/middleware/logout_if_authentication_disabled_middleware.ts new file mode 100644 index 0000000..e4f9ba5 --- /dev/null +++ b/website/app/middleware/logout_if_authentication_disabled_middleware.ts @@ -0,0 +1,13 @@ +import env from '#start/env' +import type { HttpContext } from '@adonisjs/core/http' +import type { NextFn } from '@adonisjs/core/types/http' + +export default class LogoutIfAuthenticationDisabledMiddleware { + async handle(ctx: HttpContext, next: NextFn) { + if (!env.get('INERTIA_PUBLIC_AUTHENTICATION_ENABLED')) { + await ctx.auth.use('web').logout() + } + + return next() + } +} diff --git a/website/app/middleware/require_authentication_enabled_middleware.ts b/website/app/middleware/require_authentication_enabled_middleware.ts new file mode 100644 index 0000000..3b47882 --- /dev/null +++ b/website/app/middleware/require_authentication_enabled_middleware.ts @@ -0,0 +1,13 @@ +import env from '#start/env' +import type { HttpContext } from '@adonisjs/core/http' +import type { NextFn } from '@adonisjs/core/types/http' + +export default class RequireAuthEnabledMiddleware { + async handle({ response }: HttpContext, next: NextFn) { + if (env.get("INERTIA_PUBLIC_AUTHENTICATION_ENABLED")) { + return next() + } + + return response.unauthorized() + } +} \ No newline at end of file diff --git a/website/inertia/css/app.css b/website/inertia/css/app.css index 83880d1..75968ab 100644 --- a/website/inertia/css/app.css +++ b/website/inertia/css/app.css @@ -9,8 +9,7 @@ --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; - /* --card: 0 0% 100%; */ - --card: var(--enei-beige); + --card: 0 0% 100%; /* --card-foreground: 222.2 84% 4.9%; */ --card-foreground: var(--enei-blue); --popover: 0 0% 100%; diff --git a/website/inertia/pages/errors/unauthorized.tsx b/website/inertia/pages/errors/unauthorized.tsx new file mode 100644 index 0000000..f258c7c --- /dev/null +++ b/website/inertia/pages/errors/unauthorized.tsx @@ -0,0 +1,3 @@ +export default function Unauthorized({ error }: { error: any }) { + return (JSON.stringify(error)) +} \ No newline at end of file diff --git a/website/resources/emails/authentication/email_verification.tsx b/website/resources/emails/auth/email_verification.tsx similarity index 100% rename from website/resources/emails/authentication/email_verification.tsx rename to website/resources/emails/auth/email_verification.tsx diff --git a/website/resources/emails/common/layouts/base.tsx b/website/resources/emails/common/layouts/base.tsx index c46c9f0..4ec60df 100644 --- a/website/resources/emails/common/layouts/base.tsx +++ b/website/resources/emails/common/layouts/base.tsx @@ -11,7 +11,7 @@ export const BaseLayout = ({ }) => { return ( - {children} + {children} ) } diff --git a/website/start/env.ts b/website/start/env.ts index 712c9d8..57b7112 100644 --- a/website/start/env.ts +++ b/website/start/env.ts @@ -32,7 +32,7 @@ const env = await defineEnv(new URL('../', import.meta.url), 'INERTIA_PUBLIC_', */ FROM_EMAIL: vine.string(), REPLY_TO_EMAIL: vine.string().optional(), - + SMTP_HOST: vine.string(), SMTP_PORT: vine.string(), //AWS_ACCESS_KEY_ID: vine.string(), @@ -82,6 +82,10 @@ const env = await defineEnv(new URL('../', import.meta.url), 'INERTIA_PUBLIC_', INERTIA_PUBLIC_TZ: vine.string(), INERTIA_PUBLIC_EVENT_COUNTDOWN_DATE: vine.string(), INERTIA_PUBLIC_APP_URL: vine.string(), + INERTIA_PUBLIC_AUTHENTICATION_ENABLED: vine + .boolean({ strict: false }) + .optional() + .transform((val) => val ?? false), }) }) diff --git a/website/start/kernel.ts b/website/start/kernel.ts index f8cf6d9..81a0a43 100644 --- a/website/start/kernel.ts +++ b/website/start/kernel.ts @@ -39,6 +39,7 @@ router.use([ () => import('@adonisjs/session/session_middleware'), () => import('@adonisjs/shield/shield_middleware'), () => import('@adonisjs/auth/initialize_auth_middleware'), + () => import('#middleware/logout_if_authentication_disabled_middleware'), ]) /** @@ -46,6 +47,7 @@ router.use([ * the routes or the routes group. */ export const middleware = router.named({ + requireAuthenticationEnabled: () => import('#middleware/require_authentication_enabled_middleware'), verifyUrlSignature: () => import('#middleware/verify_url_signature_middleware'), automaticSubmit: () => import('#middleware/automatic_submit_middleware'), redirectIfAuthenticated: () => import('#middleware/redirect_if_authenticated_middleware'), diff --git a/website/start/routes.ts b/website/start/routes.ts index 7eb15a5..667be5c 100644 --- a/website/start/routes.ts +++ b/website/start/routes.ts @@ -98,4 +98,5 @@ router // .middleware(middleware.verifySocialCallback({ provider: 'linkedin' })) // .as('actions:auth.linkedin.callback') }) + .middleware(middleware.requireAuthenticationEnabled()) .prefix('/auth')