From cae1e10769faa4eacf1be5970c35b27b9219790a Mon Sep 17 00:00:00 2001 From: Shaik Aftab Date: Thu, 9 Jul 2026 01:00:40 +0530 Subject: [PATCH] Task/validate property key in admin settings endpoint (#7247) * Validate property key * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.controller.ts | 9 ++++-- apps/api/src/app/admin/admin.service.ts | 8 ++--- .../src/app/admin/pipes/property-key.pipe.ts | 29 +++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 apps/api/src/app/admin/pipes/property-key.pipe.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d27847a94..d547ab964 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Set the change detection strategy to `OnPush` in the activities page - Set the change detection strategy to `OnPush` in the _FIRE_ page - Set the change detection strategy to `OnPush` in the users section of the admin control panel +- Hardened the endpoint to update a property of the admin control panel by validating the `key` path parameter - Renamed the `SymbolProfileOverrides` _Prisma_ data model to `AssetProfileOverrides` while keeping the database table name - Improved the language localization for Dutch (`nl`) - Improved the language localization for French (`fr`) 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 81a48aff2..8325fa90e 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, + value }); } 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..a980b552b --- /dev/null +++ b/apps/api/src/app/admin/pipes/property-key.pipe.ts @@ -0,0 +1,29 @@ +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]) => { + return key.startsWith('PROPERTY_'); + }) + .map(([, value]) => { + return value as string; + }) + ); + } + + public transform(value: string): PropertyKey { + if (!this.allowedKeys.has(value)) { + throw new BadRequestException(`Invalid property key: ${value}`); + } + + return value as PropertyKey; + } +}