Browse Source

Bugfix/fix issue with serving Storybook related to contentSecurityPolicy (#4437)

* Fix issue with serving Storybook related to contentSecurityPolicy

* Update changelog
pull/4438/head
Ken Tandrian 6 days ago
committed by GitHub
parent
commit
1917c17cf9
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 35
      apps/api/src/main.ts
  3. 3
      apps/api/src/middlewares/html-template.middleware.ts
  4. 2
      libs/common/src/lib/config.ts

4
CHANGELOG.md

@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Upgraded `angular` from version `19.0.5` to `19.2.1`
- Upgraded `Nx` from version `20.3.2` to `20.5.0`
### Fixed
- Fixed an issue with serving _Storybook_ related to the `contentSecurityPolicy`
## 2.145.1 - 2025-03-10
### Added

35
apps/api/src/main.ts

@ -1,3 +1,5 @@
import { STORYBOOK_PATH } from '@ghostfolio/common/config';
import {
Logger,
LogLevel,
@ -7,6 +9,7 @@ import {
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';
import { NextFunction, Request, Response } from 'express';
import helmet from 'helmet';
import { AppModule } from './app/app.module';
@ -50,20 +53,24 @@ async function bootstrap() {
app.useBodyParser('json', { limit: '10mb' });
if (configService.get<string>('ENABLE_FEATURE_SUBSCRIPTION') === 'true') {
app.use(
helmet({
contentSecurityPolicy: {
directives: {
connectSrc: ["'self'", 'https://js.stripe.com'], // Allow connections to Stripe
frameSrc: ["'self'", 'https://js.stripe.com'], // Allow loading frames from Stripe
scriptSrc: ["'self'", "'unsafe-inline'", 'https://js.stripe.com'], // Allow inline scripts and scripts from Stripe
scriptSrcAttr: ["'self'", "'unsafe-inline'"], // Allow inline event handlers
styleSrc: ["'self'", "'unsafe-inline'"] // Allow inline styles
}
},
crossOriginOpenerPolicy: false // Disable Cross-Origin-Opener-Policy header (for Internet Identity)
})
);
app.use((req: Request, res: Response, next: NextFunction) => {
if (req.path.startsWith(STORYBOOK_PATH)) {
next();
} else {
helmet({
contentSecurityPolicy: {
directives: {
connectSrc: ["'self'", 'https://js.stripe.com'], // Allow connections to Stripe
frameSrc: ["'self'", 'https://js.stripe.com'], // Allow loading frames from Stripe
scriptSrc: ["'self'", "'unsafe-inline'", 'https://js.stripe.com'], // Allow inline scripts and scripts from Stripe
scriptSrcAttr: ["'self'", "'unsafe-inline'"], // Allow inline event handlers
styleSrc: ["'self'", "'unsafe-inline'"] // Allow inline styles
}
},
crossOriginOpenerPolicy: false // Disable Cross-Origin-Opener-Policy header (for Internet Identity)
})(req, res, next);
}
});
}
app.use(HtmlTemplateMiddleware);

3
apps/api/src/middlewares/html-template.middleware.ts

@ -3,6 +3,7 @@ import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service';
import {
DEFAULT_LANGUAGE_CODE,
DEFAULT_ROOT_URL,
STORYBOOK_PATH,
SUPPORTED_LANGUAGE_CODES
} from '@ghostfolio/common/config';
import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper';
@ -129,7 +130,7 @@ export const HtmlTemplateMiddleware = async (
if (
path.startsWith('/api/') ||
path.startsWith('/development/storybook') ||
path.startsWith(STORYBOOK_PATH) ||
isFileRequest(path) ||
!environment.production
) {

2
libs/common/src/lib/config.ts

@ -153,6 +153,8 @@ export const REPLACE_NAME_PARTS = [
'Xtrackers (IE) Plc -'
];
export const STORYBOOK_PATH = '/development/storybook';
export const SUPPORTED_LANGUAGE_CODES = [
'ca',
'de',

Loading…
Cancel
Save