From c5732a4360e42c3dde242baabab11a10577202d0 Mon Sep 17 00:00:00 2001 From: Aashish Dhakal <85501584+dhakalaashish@users.noreply.github.com> Date: Thu, 17 Aug 2023 20:38:34 +0545 Subject: [PATCH] corrections in create siteAlert and protections from XSS --- apps/server/src/server/api/routers/alert.ts | 5 +++-- .../server/src/server/api/routers/geoEvent.ts | 12 +++--------- .../src/server/api/zodSchemas/alert.schema.ts | 15 ++++++++++++--- .../api/zodSchemas/geoEventProvider.schema.ts | 19 ++++++++++++++----- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/apps/server/src/server/api/routers/alert.ts b/apps/server/src/server/api/routers/alert.ts index c283ecbbd..3f58ce5dd 100644 --- a/apps/server/src/server/api/routers/alert.ts +++ b/apps/server/src/server/api/routers/alert.ts @@ -236,11 +236,12 @@ export const alertRouter = createTRPCRouter({ // Create checksum const hasher = await createXXHash3(); hasher.init(); // Reset the hasher - const eventDate = inputEventDate ? inputEventDate : new Date() + const eventDate = inputEventDate ? inputEventDate : new Date(); + const eventDayIsoString = eventDate.toISOString().split('T')[0]; // Extracting the date portion (YYYY-MM-DD); const checksum = hasher.update( latitude.toString() + longitude.toString() + - eventDate.toISOString() + + eventDayIsoString + type + geoEventProviderClientId ).digest('hex'); diff --git a/apps/server/src/server/api/routers/geoEvent.ts b/apps/server/src/server/api/routers/geoEvent.ts index 006a367c8..aafa33386 100644 --- a/apps/server/src/server/api/routers/geoEvent.ts +++ b/apps/server/src/server/api/routers/geoEvent.ts @@ -55,13 +55,6 @@ export const geoEventRouter = createTRPCRouter({ clientApiKey: geoEventProviderClientApiKey, }, }); - // If provider exists, and provider's clientApiKey is not equal to the apiKey from headers - if (provider && provider.clientApiKey !== geoEventProviderClientApiKey) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "Client API Key does not match", - }); - } } else if (ctx.user?.id) { // Find provider where clientId and userId provider = await ctx.prisma.geoEventProvider.findFirst({ @@ -87,11 +80,12 @@ export const geoEventRouter = createTRPCRouter({ // Create checksum const hasher = await createXXHash3(); hasher.init(); // Reset the hasher - const eventDate = inputEventDate ? inputEventDate : new Date() + const eventDate = inputEventDate ? inputEventDate : new Date(); + const eventDayIsoString = eventDate.toISOString().split('T')[0]; // Extracting the date portion (YYYY-MM-DD); const checksum = hasher.update( latitude.toString() + longitude.toString() + - eventDate.toISOString() + + eventDayIsoString + type + geoEventProviderClientId ).digest('hex'); diff --git a/apps/server/src/server/api/zodSchemas/alert.schema.ts b/apps/server/src/server/api/zodSchemas/alert.schema.ts index 96816cb6a..ed19c9f4d 100644 --- a/apps/server/src/server/api/zodSchemas/alert.schema.ts +++ b/apps/server/src/server/api/zodSchemas/alert.schema.ts @@ -1,19 +1,28 @@ import {z} from 'zod'; +import validator from 'validator'; + +export const detectedBySchema = z.string().min(5, { message: "DetectedBy must be 5 or more characters long" }).max(100, { message: "DetectedBy be 100 or less characters long" }).refine(value => { + const sanitized = validator.escape(value); + return sanitized === value; +}, { + message: 'DetectedBy contains invalid characters', +}); export const queryAlertSchema = z.object({ id: z.string().cuid({ message: "Invalid CUID" }), }) export const createAlertSchema = z.object({ - siteId: z.string(), + siteId: z.string().cuid({ message: "Invalid CUID" }), type: z.enum(["fire"]), latitude: z.number(), longitude: z.number(), eventDate: z.date().optional(), - detectedBy: z.string(), + detectedBy: detectedBySchema, confidence: z.enum(["medium", "low", "high"]), distance: z.number().optional(), - data: z.record(z.unknown()).optional(), + // TODO: Do we need the data field here? This could lead to security vulnerabilities + // data: z.record(z.unknown()).optional(), }); diff --git a/apps/server/src/server/api/zodSchemas/geoEventProvider.schema.ts b/apps/server/src/server/api/zodSchemas/geoEventProvider.schema.ts index 4caef46fb..22f3af6fc 100644 --- a/apps/server/src/server/api/zodSchemas/geoEventProvider.schema.ts +++ b/apps/server/src/server/api/zodSchemas/geoEventProvider.schema.ts @@ -1,22 +1,31 @@ import { z } from "zod"; +import { nameSchema } from "./user.schema"; +import validator from 'validator'; + +export const descriptionSchema = z.string().min(5, { message: "Description must be 5 or more characters long" }).max(1000, { message: "Description be 1000 or less characters long" }).refine(value => { + const sanitized = validator.escape(value); + return sanitized === value; +}, { +message: 'Description contains invalid characters', +}); // Zod Schema for createGeoEventProvider export const createGeoEventProviderSchema = z.object({ isActive: z.boolean().optional(), - name: z.string(), - description: z.string().optional(), + name: nameSchema, + description: descriptionSchema.optional(), }); // Zod Schema for updateGeoEventProvider body const UpdateGeoEventProviderBodySchema = z.object({ isActive: z.boolean(), - name: z.string(), - description: z.string(), + name: nameSchema, + description: descriptionSchema, }).partial(); // Zod Schema for updateGeoEventProvider params export const geoEventProviderParamsSchema = z.object({ - id: z.string(), + id: z.string().cuid({ message: "Invalid CUID" }), }); // Zod Schema for updateGeoEventProvider