Browse Source

Task/harden validation in Stripe checkout session endpoint (#7824)

* Harden validation

* Add rate limiting
pull/7827/head
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
3dfd3486fb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      apps/api/src/app/subscription/subscription.controller.ts
  2. 14
      apps/api/src/app/subscription/subscription.service.ts

5
apps/api/src/app/subscription/subscription.controller.ts

@ -1,4 +1,5 @@
import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator'; 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 { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service';
@ -46,7 +47,7 @@ export class SubscriptionController {
@Post('redeem-coupon') @Post('redeem-coupon')
@HttpCode(StatusCodes.OK) @HttpCode(StatusCodes.OK)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), CustomThrottlerGuard, HasPermissionGuard)
public async redeemCoupon(@Body() { couponCode }: { couponCode: string }) { public async redeemCoupon(@Body() { couponCode }: { couponCode: string }) {
if (!this.request.user) { if (!this.request.user) {
throw new HttpException( throw new HttpException(
@ -119,7 +120,7 @@ export class SubscriptionController {
} }
@Post('stripe/checkout-session') @Post('stripe/checkout-session')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), CustomThrottlerGuard, HasPermissionGuard)
public async createStripeCheckoutSession( public async createStripeCheckoutSession(
@Body() { couponId, priceId }: { couponId?: string; priceId: string } @Body() { couponId, priceId }: { couponId?: string; priceId: string }
): Promise<CreateStripeCheckoutSessionResponse> { ): Promise<CreateStripeCheckoutSessionResponse> {

14
apps/api/src/app/subscription/subscription.service.ts

@ -17,7 +17,7 @@ import {
UserWithSettings UserWithSettings
} from '@ghostfolio/common/types'; } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common'; import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { Prisma, Subscription } from '@prisma/client'; import { Prisma, Subscription } from '@prisma/client';
import { addMilliseconds, isBefore } from 'date-fns'; import { addMilliseconds, isBefore } from 'date-fns';
import ms, { StringValue } from 'ms'; 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 = const stripeCheckoutSessionCreateParams: Stripe.Checkout.SessionCreateParams =
{ {
cancel_url: `${this.configurationService.get('ROOT_URL')}/${ cancel_url: `${this.configurationService.get('ROOT_URL')}/${
@ -77,9 +85,7 @@ export class SubscriptionService {
} }
], ],
locale: this.getStripeLocale(user.settings?.settings?.language), locale: this.getStripeLocale(user.settings?.settings?.language),
metadata: subscriptionOffer metadata: { subscriptionOffer: JSON.stringify(subscriptionOffer) },
? { subscriptionOffer: JSON.stringify(subscriptionOffer) }
: {},
mode: 'payment', mode: 'payment',
payment_method_types: ['card'], payment_method_types: ['card'],
success_url: `${this.configurationService.get( success_url: `${this.configurationService.get(

Loading…
Cancel
Save