From 5907644f1e09793eedf57deabb060e160c36d3cd Mon Sep 17 00:00:00 2001 From: Aftab3008 Date: Sun, 5 Jul 2026 18:39:50 +0530 Subject: [PATCH] Task: Validate Key parameter at runtime in admin --- apps/api/src/app/admin/admin.controller.ts | 9 +++++-- apps/api/src/app/admin/admin.service.ts | 6 ++--- .../src/app/admin/pipes/property-key.pipe.ts | 25 +++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 apps/api/src/app/admin/pipes/property-key.pipe.ts diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 019468dfd..26e0de0ac 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -29,7 +29,11 @@ import { ScraperConfiguration } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; -import type { DateRange, RequestWithUser } from '@ghostfolio/common/types'; +import type { + DateRange, + PropertyKey, + RequestWithUser +} from '@ghostfolio/common/types'; import { Body, @@ -55,6 +59,7 @@ import { isDate, parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { AdminService } from './admin.service'; +import { PropertyKeyPipe } from './pipes/property-key.pipe'; @Controller('admin') export class AdminController { @@ -310,7 +315,7 @@ export class AdminController { @Put('settings/:key') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async updateProperty( - @Param('key') key: string, + @Param('key', PropertyKeyPipe) key: PropertyKey, @Body() data: UpdatePropertyDto ) { return this.adminService.putSetting(key, data.value); diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index e6f5fd700..5e9b1a882 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -344,17 +344,17 @@ export class AdminService { } } - public async putSetting(key: string, value: string) { + public async putSetting(key: PropertyKey, value: string) { let response: Property; if (value) { response = await this.propertyService.put({ value, - key: key as PropertyKey + key }); } else { response = await this.propertyService.delete({ - key: key as PropertyKey + key }); } diff --git a/apps/api/src/app/admin/pipes/property-key.pipe.ts b/apps/api/src/app/admin/pipes/property-key.pipe.ts new file mode 100644 index 000000000..fca4c9049 --- /dev/null +++ b/apps/api/src/app/admin/pipes/property-key.pipe.ts @@ -0,0 +1,25 @@ +import * as config from '@ghostfolio/common/config'; +import type { PropertyKey } from '@ghostfolio/common/types'; + +import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common'; + +@Injectable() +export class PropertyKeyPipe implements PipeTransform { + private readonly allowedKeys: Set; + + public constructor() { + this.allowedKeys = new Set( + Object.entries(config) + .filter(([key]) => key.startsWith('PROPERTY_')) + .map(([, value]) => value as string) + ); + } + + public transform(value: string): PropertyKey { + if (!this.allowedKeys.has(value)) { + throw new BadRequestException(`Invalid property key: ${value}`); + } + + return value as PropertyKey; + } +}