From 33eed5bb316b2fc80ce14185499d211efb0c1978 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Fri, 12 Jul 2024 09:22:58 +0200 Subject: [PATCH] refactor(api): encapsulate auth/csrf hooks (#55481) --- api/src/app.ts | 42 +++++++++++++++++++++++++++++------ api/src/routes/certificate.ts | 5 ----- api/src/routes/challenge.ts | 5 ----- api/src/routes/donate.ts | 6 ----- api/src/routes/settings.ts | 9 -------- api/src/routes/user.ts | 7 ------ 6 files changed, 35 insertions(+), 39 deletions(-) diff --git a/api/src/app.ts b/api/src/app.ts index 3a35946f413..dab88d3c1cd 100644 --- a/api/src/app.ts +++ b/api/src/app.ts @@ -184,20 +184,48 @@ export const build = async ( void fastify.register(codeFlowAuth); void fastify.register(notFound); void fastify.register(prismaPlugin); + + // Routes requiring authentication and CSRF protection + void fastify.register(function (fastify, _opts, done) { + // The order matters here, since we want to reject invalid cross site requests + // before checking if the user is authenticated. + // @ts-expect-error - @fastify/csrf-protection needs to update their types + // eslint-disable-next-line @typescript-eslint/unbound-method + fastify.addHook('onRequest', fastify.csrfProtection); + fastify.addHook('onRequest', fastify.authorize); + + void fastify.register(challengeRoutes); + void fastify.register(donateRoutes); + void fastify.register(protectedCertificateRoutes); + void fastify.register(settingRoutes); + void fastify.register(userRoutes); + done(); + }); + + // Routes requiring authentication and NOT CSRF protection + void fastify.register(function (fastify, _opts, done) { + fastify.addHook('onRequest', fastify.authorize); + + void fastify.register(userGetRoutes); + done(); + }); + + // Routes requiring authentication that redirect on failure + void fastify.register(function (fastify, _opts, done) { + fastify.addHook('onRequest', fastify.authorizeOrRedirect); + + void fastify.register(settingRedirectRoutes); + done(); + }); + + // Routes not requiring authentication void fastify.register(mobileAuth0Routes); if (FCC_ENABLE_DEV_LOGIN_MODE) { void fastify.register(devAuthRoutes); } - void fastify.register(challengeRoutes); - void fastify.register(settingRoutes); - void fastify.register(settingRedirectRoutes); - void fastify.register(donateRoutes); void fastify.register(emailSubscribtionRoutes); - void fastify.register(userRoutes); void fastify.register(userPublicGetRoutes); - void fastify.register(protectedCertificateRoutes); void fastify.register(unprotectedCertificateRoutes); - void fastify.register(userGetRoutes); void fastify.register(deprecatedEndpoints); void fastify.register(statusRoute); void fastify.register(unsubscribeDeprecated); diff --git a/api/src/routes/certificate.ts b/api/src/routes/certificate.ts index ee98119a5b9..3afb7fd9ab6 100644 --- a/api/src/routes/certificate.ts +++ b/api/src/routes/certificate.ts @@ -58,11 +58,6 @@ export const protectedCertificateRoutes: FastifyPluginCallbackTypebox = ( const challenges = getChallenges(); const certTypeIds = createCertTypeIds(challenges); - // @ts-expect-error - @fastify/csrf-protection needs to update their types - // eslint-disable-next-line @typescript-eslint/unbound-method - fastify.addHook('onRequest', fastify.csrfProtection); - fastify.addHook('onRequest', fastify.authorize); - // TODO(POST_MVP): Response should not include updated user. If a client wants the updated user, it should make a separate request // OR: Always respond with current user - full user object - not random pieces. fastify.put( diff --git a/api/src/routes/challenge.ts b/api/src/routes/challenge.ts index b29fcfc7b2a..de4ae019f02 100644 --- a/api/src/routes/challenge.ts +++ b/api/src/routes/challenge.ts @@ -63,11 +63,6 @@ export const challengeRoutes: FastifyPluginCallbackTypebox = ( ) => { const challenges = getChallenges(); - // @ts-expect-error - @fastify/csrf-protection needs to update their types - // eslint-disable-next-line @typescript-eslint/unbound-method - fastify.addHook('onRequest', fastify.csrfProtection); - fastify.addHook('onRequest', fastify.authorize); - fastify.post( '/coderoad-challenge-completed', { diff --git a/api/src/routes/donate.ts b/api/src/routes/donate.ts index 51533542211..72c85c79066 100644 --- a/api/src/routes/donate.ts +++ b/api/src/routes/donate.ts @@ -26,12 +26,6 @@ export const donateRoutes: FastifyPluginCallbackTypebox = ( typescript: true }); - // The order matters here, since we want to reject invalid cross site requests - // before checking if the user is authenticated. - // @ts-expect-error - @fastify/csrf-protection needs to update their types - // eslint-disable-next-line @typescript-eslint/unbound-method - fastify.addHook('onRequest', fastify.csrfProtection); - fastify.addHook('onRequest', fastify.authorize); fastify.post( '/donate/add-donation', { diff --git a/api/src/routes/settings.ts b/api/src/routes/settings.ts index 3cb5505bead..fd663e434ee 100644 --- a/api/src/routes/settings.ts +++ b/api/src/routes/settings.ts @@ -81,13 +81,6 @@ export const settingRoutes: FastifyPluginCallbackTypebox = ( _options, done ) => { - // The order matters here, since we want to reject invalid cross site requests - // before checking if the user is authenticated. - // @ts-expect-error - @fastify/csrf-protection needs to update their types - // eslint-disable-next-line @typescript-eslint/unbound-method - fastify.addHook('onRequest', fastify.csrfProtection); - fastify.addHook('onRequest', fastify.authorize); - type CommonResponseSchema = { response: { 400: (typeof schemas.updateMyProfileUI.response)[400] }; }; @@ -681,8 +674,6 @@ export const settingRedirectRoutes: FastifyPluginCallbackTypebox = ( _options, done ) => { - fastify.addHook('onRequest', fastify.authorizeOrRedirect); - const redirectMessage = { type: 'danger', content: diff --git a/api/src/routes/user.ts b/api/src/routes/user.ts index 86bc7fc3e3d..3111cc5cb79 100644 --- a/api/src/routes/user.ts +++ b/api/src/routes/user.ts @@ -96,11 +96,6 @@ export const userRoutes: FastifyPluginCallbackTypebox = ( _options, done ) => { - // @ts-expect-error - @fastify/csrf-protection needs to update their types - // eslint-disable-next-line @typescript-eslint/unbound-method - fastify.addHook('onRequest', fastify.csrfProtection); - fastify.addHook('onRequest', fastify.authorize); - fastify.post( '/account/delete', { @@ -422,8 +417,6 @@ export const userGetRoutes: FastifyPluginCallbackTypebox = ( _options, done ) => { - fastify.addHook('onRequest', fastify.authorize); - fastify.get( '/user/get-session-user', {