From 3dfd3486fb4924d71f0e3b8f01d2690b1c972667 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 5 Sep 2026 15:03:25 +0200 Subject: [PATCH 1/4] Task/harden validation in Stripe checkout session endpoint (#7824) * Harden validation * Add rate limiting --- .../app/subscription/subscription.controller.ts | 5 +++-- .../src/app/subscription/subscription.service.ts | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/api/src/app/subscription/subscription.controller.ts b/apps/api/src/app/subscription/subscription.controller.ts index 0cfc4d90e..778e32243 100644 --- a/apps/api/src/app/subscription/subscription.controller.ts +++ b/apps/api/src/app/subscription/subscription.controller.ts @@ -1,4 +1,5 @@ import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator'; +import { CustomThrottlerGuard } from '@ghostfolio/api/guards/custom-throttler.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; @@ -46,7 +47,7 @@ export class SubscriptionController { @Post('redeem-coupon') @HttpCode(StatusCodes.OK) - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseGuards(AuthGuard('jwt'), CustomThrottlerGuard, HasPermissionGuard) public async redeemCoupon(@Body() { couponCode }: { couponCode: string }) { if (!this.request.user) { throw new HttpException( @@ -119,7 +120,7 @@ export class SubscriptionController { } @Post('stripe/checkout-session') - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseGuards(AuthGuard('jwt'), CustomThrottlerGuard, HasPermissionGuard) public async createStripeCheckoutSession( @Body() { couponId, priceId }: { couponId?: string; priceId: string } ): Promise { diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index aaa4deb5a..312b8c3ae 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -17,7 +17,7 @@ import { UserWithSettings } from '@ghostfolio/common/types'; -import { Injectable, Logger } from '@nestjs/common'; +import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { Prisma, Subscription } from '@prisma/client'; import { addMilliseconds, isBefore } from 'date-fns'; import ms, { StringValue } from 'ms'; @@ -64,6 +64,14 @@ export class SubscriptionService { } ); + if (!subscriptionOffer) { + throw new BadRequestException('Invalid priceId'); + } + + if (couponId && couponId !== subscriptionOffer.couponId) { + throw new BadRequestException('Invalid couponId'); + } + const stripeCheckoutSessionCreateParams: Stripe.Checkout.SessionCreateParams = { cancel_url: `${this.configurationService.get('ROOT_URL')}/${ @@ -77,9 +85,7 @@ export class SubscriptionService { } ], locale: this.getStripeLocale(user.settings?.settings?.language), - metadata: subscriptionOffer - ? { subscriptionOffer: JSON.stringify(subscriptionOffer) } - : {}, + metadata: { subscriptionOffer: JSON.stringify(subscriptionOffer) }, mode: 'payment', payment_method_types: ['card'], success_url: `${this.configurationService.get( From 3d9018a6a77407ae7a4ee86ef296a181b61c5942 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 5 Sep 2026 15:22:50 +0200 Subject: [PATCH 2/4] Task/improve data provider credits component (#7826) Improve data provider credits --- .../transform-data-source-in-response.interceptor.ts | 2 ++ .../data-provider-credits.component.html | 9 +++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index cbe5b4363..3b9addf76 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -94,6 +94,8 @@ export class TransformDataSourceInResponseInterceptor< 'watchlist[*].dataSource' ] }); + + data.dataProviderInfo = undefined; } return data; diff --git a/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html b/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html index 921433620..fb72e72cd 100644 --- a/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html +++ b/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html @@ -1,5 +1,5 @@ - Market data provided by  + Market data provided by{{ ' ' }} @for ( dataProviderInfo of dataProviderInfos; track dataProviderInfo; @@ -7,10 +7,7 @@ ) { {{ dataProviderInfo.name - }} - @if (!last) { - ,  - } + }}{{ last ? '.' : ', ' }} } - . From ad9a1d526b394c2460ae628fb60bbdd22b0bb25b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 5 Sep 2026 15:27:40 +0200 Subject: [PATCH 3/4] Release 3.67.1 (#7827) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 723e84a23..22ec996da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 3.67.0 - 2026-09-05 +## 3.67.1 - 2026-09-05 ### Added diff --git a/package-lock.json b/package-lock.json index 39a02c7ad..2b7b58fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.67.0", + "version": "3.67.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.67.0", + "version": "3.67.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index c0439aefb..9ee6a75be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.67.0", + "version": "3.67.1", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 57c4f5cb223d8020126e91cd1c6852f2daf8fd54 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 6 Sep 2026 09:41:47 +0200 Subject: [PATCH 4/4] Task/improve data provider credits component (part 2) (#7831) Improve data provider credits --- .../transform-data-source-in-response.interceptor.ts | 4 ++-- .../holding-detail-dialog/holding-detail-dialog.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index 3b9addf76..31bfb620e 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -70,6 +70,8 @@ export class TransformDataSourceInResponseInterceptor< } } + data.dataProviderInfo = undefined; + if (Object.keys(valueMap).length === 0) { return data; } @@ -94,8 +96,6 @@ export class TransformDataSourceInResponseInterceptor< 'watchlist[*].dataSource' ] }); - - data.dataProviderInfo = undefined; } return data; diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index 51a0783fc..dff4c2a1d 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -358,7 +358,7 @@ - @if (dataProviderInfo) { + @if (dataProviderInfo?.name) {