From 6155007303b2e2b0f3c3d3c314e78b228738dc6c Mon Sep 17 00:00:00 2001 From: Yachika Sharma Date: Fri, 19 Jun 2026 14:56:27 +0530 Subject: [PATCH] refactor(auth): replace any-cast authenticate fallback with typed preHandler - Remove (app as any).authenticate fallback chains in cards.ts, connect.ts, event.ts, nfc.ts - Use preHandler: [(req, reply) => app.authenticate(req, reply)] consistently - Fix TS generic types on route methods to resolve tsc errors Closes #554 --- apps/backend/src/routes/cards.ts | 17 ++++--------- apps/backend/src/routes/connect.ts | 36 ++++------------------------ apps/backend/src/routes/event.ts | 38 ++++++++++-------------------- apps/backend/src/routes/nfc.ts | 32 +++++-------------------- 4 files changed, 27 insertions(+), 96 deletions(-) diff --git a/apps/backend/src/routes/cards.ts b/apps/backend/src/routes/cards.ts index e5f98762..dff28789 100644 --- a/apps/backend/src/routes/cards.ts +++ b/apps/backend/src/routes/cards.ts @@ -49,16 +49,9 @@ interface _CardWithLinks { } export async function cardRoutes(app: FastifyInstance): Promise { - app.addHook('preHandler', async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } - if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } - try { await request.jwtVerify() } catch (_e) { reply.status(401).send({ error: 'Unauthorized' }) } - }); - // ─── List Cards ─── - app.get('/', async (request: FastifyRequest, reply: FastifyReply): Promise => { + app.get('/',{preHandler: [(req, reply) => app.authenticate(req, reply)] }, async (request: FastifyRequest, reply: FastifyReply): Promise => { const userId = (request.user as { id: string }).id; try { return await cardService.listCards(app, userId) @@ -69,7 +62,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Create Card ─── - app.post('/', async (request: FastifyRequest<{ Body: CreateCardBody }>, reply: FastifyReply): Promise => { + app.post<{ Body: CreateCardBody }>('/', { preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request, reply): Promise => { const userId = (request.user as { id: string }).id; const parsed = createCardSchema.safeParse(request.body); @@ -88,7 +81,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Update Card ─── - app.put('/:id', async (request: FastifyRequest<{ Params: CardParams; Body: UpdateCardBody }>, reply: FastifyReply): Promise => { + app.put<{ Params: CardParams; Body: UpdateCardBody }>('/:id', {preHandler: [(req, reply) => app.authenticate(req, reply)] }, async (request, reply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -106,7 +99,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Delete Card ─── - app.delete('/:id', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { + app.delete<{ Params: CardParams }>('/:id', { preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request, reply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; @@ -129,7 +122,7 @@ export async function cardRoutes(app: FastifyInstance): Promise { // ─── Set Default Card ─── - app.put('/:id/default', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise => { + app.put<{ Params: CardParams }>('/:id/default', {preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request, reply): Promise => { const userId = (request.user as { id: string }).id; const { id } = request.params; diff --git a/apps/backend/src/routes/connect.ts b/apps/backend/src/routes/connect.ts index e7e1a2be..6614b980 100644 --- a/apps/backend/src/routes/connect.ts +++ b/apps/backend/src/routes/connect.ts @@ -29,14 +29,7 @@ interface ParsedOAuthState { export async function connectRoutes(app: FastifyInstance): Promise { // ─── Status ─── - app.get('/status', { - preHandler: [async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } - if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } - try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) } - }], - }, async (request: FastifyRequest, _reply: FastifyReply) => { + app.get('/status',{preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request: FastifyRequest, _reply: FastifyReply) => { const userId = (request.user as any).id; const tokens = await app.prisma.oAuthToken.findMany({ @@ -49,14 +42,7 @@ export async function connectRoutes(app: FastifyInstance): Promise { // ─── GitHub Connect ─── - app.get('/github', { - preHandler: [async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } - if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } - try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) } - }], - }, async (request: FastifyRequest, reply: FastifyReply) => { + app.get('/github',{preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request: FastifyRequest, reply: FastifyReply) => { const userId = (request.user as any).id; const nonce = generateState(); @@ -173,14 +159,7 @@ export async function connectRoutes(app: FastifyInstance): Promise { } }); - app.get('/github/autodiscover', { - preHandler: [async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } - if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } - try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) } - }], - }, async (request: FastifyRequest, reply: FastifyReply) => { + app.get('/github/autodiscover',{preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request: FastifyRequest, reply: FastifyReply) => { const userId = (request.user as any).id; const cacheKey = `github:autodiscover:${userId}`; @@ -262,14 +241,7 @@ export async function connectRoutes(app: FastifyInstance): Promise { // ─── Disconnect ─── - app.delete('/:platform', { - preHandler: [async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } - if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } - try { await request.jwtVerify() } catch { reply.status(401).send({ error: 'Unauthorized' }) } - }], - }, async (request: FastifyRequest<{ Params: { platform: string } }>, reply: FastifyReply) => { + app.delete<{ Params: { platform: string } }>('/:platform', {preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request, reply) => { const userId = (request.user as any).id; const { platform } = request.params; diff --git a/apps/backend/src/routes/event.ts b/apps/backend/src/routes/event.ts index 4d4ee2d9..d058f131 100644 --- a/apps/backend/src/routes/event.ts +++ b/apps/backend/src/routes/event.ts @@ -1,8 +1,7 @@ -import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; -import { createEventSchema, joinEventSchema} from '../validations/event.validation'; - import {generateUniqueSlug} from '../utils/slug' +import { createEventSchema} from '../validations/event.validation'; +import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; type EventDetails = { id: string; @@ -57,21 +56,8 @@ type EventWithAttendees = { }[]; } -export async function eventRoutes(app:FastifyInstance) { - app.post('/', { preHandler: [async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } - if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } - try { await request.jwtVerify() } catch (e) { reply.status(401).send({ error: 'Unauthorized' }) } - }] }, async (request: FastifyRequest<{ - Body: { - name: string, - description?: string, - startDate: string, - location: string, - endDate: string, - isPublic?: boolean - }}>, reply: FastifyReply) => { +export async function eventRoutes(app:FastifyInstance): Promise { + app.post<{Body: { name: string; description?: string; startDate: string; location: string; endDate: string; isPublic?: boolean; }; }>('/', {preHandler: [(req, reply) => app.authenticate(req, reply)]}, async (request, reply) => { const userId = (request.user as any).id; const parsed = createEventSchema.safeParse(request.body); if(!parsed.success){ @@ -80,8 +66,8 @@ export async function eventRoutes(app:FastifyInstance) { const {name, description, startDate, endDate, isPublic ,location} = parsed.data - let finalSlug = await generateUniqueSlug(name, async(slug) => { - const existing = await app.prisma.event.findUnique({where: {slug : slug}}) + const finalSlug = await generateUniqueSlug(name, async(slug) => { + const existing = await app.prisma.event.findUnique({where: {slug}}) return !!existing }) @@ -95,7 +81,7 @@ export async function eventRoutes(app:FastifyInstance) { name, description, slug: finalSlug, - location: location, + location, startDate: startDateObj, endDate: endDateObj, isPublic: isPublic ?? true, @@ -104,7 +90,7 @@ export async function eventRoutes(app:FastifyInstance) { }) return reply.status(201).send(newEvent); - } catch (error) { + } catch (_error) { app.log.error('Failed to create event'); return reply.status(500).send({error: 'Failed to create event'}) } @@ -153,7 +139,7 @@ export async function eventRoutes(app:FastifyInstance) { return response; }) - app.post('/:slug/join', { preHandler: [async (request, reply) => { const server = request.server as any; if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } try { await request.jwtVerify() } catch (e) { reply.status(401).send({ error: 'Unauthorized' }) } }] }, async(request: FastifyRequest<{Params: {slug: string}}>, reply: FastifyReply) => { + app.post<{ Params: { slug: string } }>('/:slug/join', {preHandler: [(req, reply) => app.authenticate(req, reply)]}, async(request, reply) => { const userId = (request.user as any).id; const paramsSlug = request.params.slug; @@ -171,7 +157,7 @@ export async function eventRoutes(app:FastifyInstance) { await app.prisma.eventAttendee.create({ data: { eventId: event.id, - userId: userId, + userId, joinedAt: new Date() } }) @@ -187,7 +173,7 @@ export async function eventRoutes(app:FastifyInstance) { }) - app.delete('/:slug/leave', { preHandler: [async (request, reply) => { const server = request.server as any; if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return } if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return } try { await request.jwtVerify() } catch (e) { reply.status(401).send({ error: 'Unauthorized' }) } }] }, async(request: FastifyRequest<{Params: {slug: string}}>, reply: FastifyReply) => { + app.delete<{Params: {slug: string}}>('/:slug/leave',{preHandler: [(req, reply) => app.authenticate(req, reply)]}, async(request, reply) => { const userId = (request.user as any).id; const paramsSlug = request.params.slug; @@ -205,7 +191,7 @@ export async function eventRoutes(app:FastifyInstance) { await app.prisma.eventAttendee.delete({ where: { userId_eventId: { - userId: userId, + userId, eventId: event.id } } diff --git a/apps/backend/src/routes/nfc.ts b/apps/backend/src/routes/nfc.ts index 5cf13f0c..c182f3cd 100644 --- a/apps/backend/src/routes/nfc.ts +++ b/apps/backend/src/routes/nfc.ts @@ -1,6 +1,7 @@ -import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; import { z } from 'zod'; +import type { FastifyInstance } from 'fastify'; + type NfcPayloadResponse = { type: 'URI'; payload: string; @@ -10,33 +11,12 @@ const nfcQuerySchema = z.object({ card: z.string().uuid('Invalid card ID format').optional(), }); -export async function nfcRoutes(app: FastifyInstance) { - app.addHook('preHandler', async (request, reply) => { - const server = request.server as any; - if (typeof server?.authenticate === 'function') { - await server.authenticate(request, reply); - return; - } - if (typeof (app as any).authenticate === 'function') { - await (app as any).authenticate(request, reply); - return; - } - try { - await request.jwtVerify(); - } catch (e) { - reply.status(401).send({ error: 'Unauthorized' }); - } - }); - +export async function nfcRoutes(app: FastifyInstance) : Promise { // GET /api/nfc/payload — returns NDEF URI payload for user's default DevCard URL // GET /api/nfc/payload?card= — returns payload for a specific card - app.get( - '/payload', - async ( - request: FastifyRequest<{ Querystring: { card?: string } }>, - reply: FastifyReply - ) => { - const userId = (request.user as any).id; + app.get<{ Querystring: { card?: string } }>( + '/payload',{preHandler: [(req, reply) => app.authenticate(req, reply)]}, + async (request,reply ) => { const userId = (request.user as any).id; // Validate query params with Zod const parseResult = nfcQuerySchema.safeParse(request.query);