From 21352c52f5bcf709d55d0ba1a7fae91cf545d5d7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 27 May 2026 20:33:27 +0200 Subject: [PATCH] Add HTTP fetch service --- apps/api/src/services/fetch/fetch.service.ts | 32 ++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/apps/api/src/services/fetch/fetch.service.ts b/apps/api/src/services/fetch/fetch.service.ts index 8a06d3470..b3bd022d9 100644 --- a/apps/api/src/services/fetch/fetch.service.ts +++ b/apps/api/src/services/fetch/fetch.service.ts @@ -1,7 +1,11 @@ +import { redactPaths } from '@ghostfolio/api/helper/object.helper'; + import { Injectable, Logger } from '@nestjs/common'; @Injectable() export class FetchService { + private static readonly REDACTED_QUERY_PARAM_NAMES = ['apikey', 'api_token']; + public async fetch( input: RequestInfo | URL, init?: RequestInit @@ -13,20 +17,21 @@ export class FetchService { ).toUpperCase(); const url = input instanceof Request ? input.url : input.toString(); + const urlRedacted = this.redactUrl(url); - Logger.debug(`${method} ${url}`, 'FetchService'); + Logger.debug(`${method} ${urlRedacted}`, 'FetchService'); try { return await globalThis.fetch(input, init); } catch (error) { if (error instanceof Error) { Logger.error( - `${method} ${url} failed: [${error.name}] ${error.message}`, + `${method} ${urlRedacted} failed: [${error.name}] ${error.message}`, 'FetchService' ); } else { Logger.error( - `${method} ${url} failed: ${String(error)}`, + `${method} ${urlRedacted} failed: ${String(error)}`, 'FetchService' ); } @@ -34,4 +39,25 @@ export class FetchService { throw error; } } + + private redactUrl(rawUrl: string): string { + try { + const url = new URL(rawUrl); + + const redacted = redactPaths({ + object: Object.fromEntries(url.searchParams), + paths: FetchService.REDACTED_QUERY_PARAM_NAMES + }); + + for (const [key, value] of Object.entries(redacted)) { + if (value === null) { + url.searchParams.set(key, '*******'); + } + } + + return url.toString(); + } catch { + return rawUrl; + } + } }