mirror of
https://github.com/ToolJet/ToolJet
synced 2026-04-21 21:47:17 +00:00
reverted helmet interceptor
This commit is contained in:
parent
394be5ff34
commit
8d9d86cf2c
6 changed files with 122 additions and 107 deletions
22
CODEOWNERS
Normal file
22
CODEOWNERS
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Code owners for specific package.json and package-lock.json files
|
||||||
|
/server/package.json @shah21 @gsmithun4 @adishm98
|
||||||
|
/server/package-lock.json @shah21 @gsmithun4 @adishm98
|
||||||
|
|
||||||
|
/frontend/package.json @shah21 @gsmithun4 @adishm98
|
||||||
|
/frontend/package-lock.json @shah21 @gsmithun4 @adishm98
|
||||||
|
|
||||||
|
/marketplace/package.json @shah21 @gsmithun4 @adishm98
|
||||||
|
/marketplace/package-lock.json @shah21 @gsmithun4 @adishm98
|
||||||
|
|
||||||
|
/cypress/package.json @shah21 @gsmithun4 @adishm98
|
||||||
|
/cypress/package-lock.json @shah21 @gsmithun4 @adishm98
|
||||||
|
|
||||||
|
/plugins/package.json @shah21 @gsmithun4 @adishm98
|
||||||
|
/plugins/package-lock.json @shah21 @gsmithun4 @adishm98
|
||||||
|
|
||||||
|
/package.json @shah21 @gsmithun4 @adishm98
|
||||||
|
/package-lock.json @shah21 @gsmithun4 @adishm98
|
||||||
|
|
||||||
|
# Server service files
|
||||||
|
/server/src/services/email.service.ts @shah21 @gsmithun4
|
||||||
|
/server/src/mails @shah21 @gsmithun4
|
||||||
|
|
@ -45,10 +45,8 @@ import { ImportExportResourcesModule } from './modules/import_export_resources/i
|
||||||
import { UserResourcePermissionsModule } from '@module/user_resource_permissions/user_resource_permissions.module';
|
import { UserResourcePermissionsModule } from '@module/user_resource_permissions/user_resource_permissions.module';
|
||||||
import { PermissionsModule } from '@module/permissions/permissions.module';
|
import { PermissionsModule } from '@module/permissions/permissions.module';
|
||||||
import { GetConnection } from './helpers/getconnection';
|
import { GetConnection } from './helpers/getconnection';
|
||||||
import { APP_INTERCEPTOR } from '@nestjs/core/constants';
|
|
||||||
import { HelmetInterceptor } from './interceptors/helmet.interceptor';
|
|
||||||
import { CustomHeadersInterceptor } from './interceptors/custom-headers.interceptors';
|
|
||||||
import { InstanceSettingsModule } from '@instance-settings/module';
|
import { InstanceSettingsModule } from '@instance-settings/module';
|
||||||
|
import { StaticFileServerModule } from '@module/static_file_server/static_file_server.module';
|
||||||
|
|
||||||
const imports = [
|
const imports = [
|
||||||
ScheduleModule.forRoot(),
|
ScheduleModule.forRoot(),
|
||||||
|
|
@ -109,6 +107,7 @@ const imports = [
|
||||||
CopilotModule,
|
CopilotModule,
|
||||||
OrganizationConstantModule,
|
OrganizationConstantModule,
|
||||||
TooljetDbModule,
|
TooljetDbModule,
|
||||||
|
StaticFileServerModule
|
||||||
];
|
];
|
||||||
|
|
||||||
if (process.env.SERVE_CLIENT !== 'false' && process.env.NODE_ENV === 'production') {
|
if (process.env.SERVE_CLIENT !== 'false' && process.env.NODE_ENV === 'production') {
|
||||||
|
|
@ -146,14 +145,6 @@ if (process.env.ENABLE_TOOLJET_DB === 'true') {
|
||||||
EmailService,
|
EmailService,
|
||||||
SeedsService,
|
SeedsService,
|
||||||
GetConnection,
|
GetConnection,
|
||||||
{
|
|
||||||
provide: APP_INTERCEPTOR,
|
|
||||||
useClass: HelmetInterceptor,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: APP_INTERCEPTOR,
|
|
||||||
useClass: CustomHeadersInterceptor,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule implements OnModuleInit {
|
export class AppModule implements OnModuleInit {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CustomHeadersInterceptor implements NestInterceptor {
|
|
||||||
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
||||||
return next.handle().pipe(
|
|
||||||
map((data) => {
|
|
||||||
const response = context.switchToHttp().getResponse();
|
|
||||||
response.setHeader('Permissions-Policy', 'geolocation=(self), camera=(), microphone=()');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
||||||
return data;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import * as helmet from 'helmet';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class HelmetInterceptor implements NestInterceptor {
|
|
||||||
private readonly helmet: ReturnType<typeof helmet>;
|
|
||||||
|
|
||||||
constructor(private configService: ConfigService) {
|
|
||||||
const host = new URL(this.configService.get('TOOLJET_HOST'));
|
|
||||||
const domain = host.hostname;
|
|
||||||
this.helmet = helmet({
|
|
||||||
contentSecurityPolicy: {
|
|
||||||
useDefaults: true,
|
|
||||||
directives: {
|
|
||||||
upgradeInsecureRequests: null,
|
|
||||||
'img-src': ['*', 'data:', 'blob:'],
|
|
||||||
'script-src': [
|
|
||||||
'maps.googleapis.com',
|
|
||||||
'storage.googleapis.com',
|
|
||||||
'apis.google.com',
|
|
||||||
'accounts.google.com',
|
|
||||||
"'self'",
|
|
||||||
"'unsafe-inline'",
|
|
||||||
"'unsafe-eval'",
|
|
||||||
'blob:',
|
|
||||||
'https://unpkg.com/@babel/standalone@7.17.9/babel.min.js',
|
|
||||||
'https://unpkg.com/react@16.7.0/umd/react.production.min.js',
|
|
||||||
'https://unpkg.com/react-dom@16.7.0/umd/react-dom.production.min.js',
|
|
||||||
'cdn.skypack.dev',
|
|
||||||
'cdn.jsdelivr.net',
|
|
||||||
'https://esm.sh',
|
|
||||||
'www.googletagmanager.com',
|
|
||||||
],
|
|
||||||
'default-src': [
|
|
||||||
'maps.googleapis.com',
|
|
||||||
'storage.googleapis.com',
|
|
||||||
'apis.google.com',
|
|
||||||
'accounts.google.com',
|
|
||||||
'*.sentry.io',
|
|
||||||
"'self'",
|
|
||||||
'blob:',
|
|
||||||
'www.googletagmanager.com',
|
|
||||||
],
|
|
||||||
'connect-src': ['ws://' + domain, "'self'", '*'],
|
|
||||||
'frame-ancestors': ['*'],
|
|
||||||
'frame-src': ['*'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
frameguard:
|
|
||||||
this.configService.get('DISABLE_APP_EMBED') !== 'true' ||
|
|
||||||
this.configService.get('ENABLE_PRIVATE_APP_EMBED') === 'true'
|
|
||||||
? false
|
|
||||||
: { action: 'deny' },
|
|
||||||
hidePoweredBy: true,
|
|
||||||
referrerPolicy: {
|
|
||||||
policy: 'no-referrer',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
||||||
const httpContext = context.switchToHttp();
|
|
||||||
const request = httpContext.getRequest();
|
|
||||||
const response = httpContext.getResponse();
|
|
||||||
|
|
||||||
return new Observable((subscriber) => {
|
|
||||||
this.helmet(request, response, () => {
|
|
||||||
next.handle().subscribe(subscriber);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { RequestMethod, ValidationPipe, VersioningType, VERSION_NEUTRAL } from '
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { bootstrap as globalAgentBootstrap } from 'global-agent';
|
import { bootstrap as globalAgentBootstrap } from 'global-agent';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import * as helmet from 'helmet';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
|
|
@ -39,6 +40,72 @@ function replaceSubpathPlaceHoldersInStaticAssets() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setSecurityHeaders(app, configService) {
|
||||||
|
const tooljetHost = configService.get('TOOLJET_HOST');
|
||||||
|
const host = new URL(tooljetHost);
|
||||||
|
const domain = host.hostname;
|
||||||
|
|
||||||
|
app.enableCors({
|
||||||
|
origin: configService.get('ENABLE_CORS') === 'true' || tooljetHost,
|
||||||
|
credentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(helmet({
|
||||||
|
contentSecurityPolicy: {
|
||||||
|
useDefaults: true,
|
||||||
|
directives: {
|
||||||
|
upgradeInsecureRequests: null,
|
||||||
|
'img-src': ['*', 'data:', 'blob:'],
|
||||||
|
'script-src': [
|
||||||
|
'maps.googleapis.com',
|
||||||
|
'storage.googleapis.com',
|
||||||
|
'apis.google.com',
|
||||||
|
'accounts.google.com',
|
||||||
|
"'self'",
|
||||||
|
"'unsafe-inline'",
|
||||||
|
"'unsafe-eval'",
|
||||||
|
'blob:',
|
||||||
|
'https://unpkg.com/@babel/standalone@7.17.9/babel.min.js',
|
||||||
|
'https://unpkg.com/react@16.7.0/umd/react.production.min.js',
|
||||||
|
'https://unpkg.com/react-dom@16.7.0/umd/react-dom.production.min.js',
|
||||||
|
'cdn.skypack.dev',
|
||||||
|
'cdn.jsdelivr.net',
|
||||||
|
'https://esm.sh',
|
||||||
|
'www.googletagmanager.com',
|
||||||
|
],
|
||||||
|
'default-src': [
|
||||||
|
'maps.googleapis.com',
|
||||||
|
'storage.googleapis.com',
|
||||||
|
'apis.google.com',
|
||||||
|
'accounts.google.com',
|
||||||
|
'*.sentry.io',
|
||||||
|
"'self'",
|
||||||
|
'blob:',
|
||||||
|
'www.googletagmanager.com',
|
||||||
|
],
|
||||||
|
'connect-src': ['ws://' + domain, "'self'", '*'],
|
||||||
|
'frame-ancestors': ['*'],
|
||||||
|
'frame-src': ['*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
frameguard:
|
||||||
|
configService.get('DISABLE_APP_EMBED') !== 'true' ||
|
||||||
|
configService.get('ENABLE_PRIVATE_APP_EMBED') === 'true'
|
||||||
|
? false
|
||||||
|
: { action: 'deny' },
|
||||||
|
hidePoweredBy: true,
|
||||||
|
referrerPolicy: {
|
||||||
|
policy: 'no-referrer',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.setHeader('Permissions-Policy', 'geolocation=(self), camera=(), microphone=()');
|
||||||
|
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
||||||
bufferLogs: true,
|
bufferLogs: true,
|
||||||
|
|
@ -64,20 +131,17 @@ async function bootstrap() {
|
||||||
app.setGlobalPrefix(UrlPrefix + 'api', {
|
app.setGlobalPrefix(UrlPrefix + 'api', {
|
||||||
exclude: pathsToExclude,
|
exclude: pathsToExclude,
|
||||||
});
|
});
|
||||||
app.enableCors({
|
|
||||||
origin: process.env.ENABLE_CORS === 'true' || process.env.TOOLJET_HOST,
|
|
||||||
credentials: true,
|
|
||||||
});
|
|
||||||
app.use(compression());
|
app.use(compression());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(json({ limit: '50mb' }));
|
app.use(json({ limit: '50mb' }));
|
||||||
app.use(urlencoded({ extended: true, limit: '50mb', parameterLimit: 1000000 }));
|
app.use(urlencoded({ extended: true, limit: '50mb', parameterLimit: 1000000 }));
|
||||||
app.useStaticAssets(join(__dirname, 'assets'), { prefix: (UrlPrefix ? UrlPrefix : '/') + 'assets' });
|
|
||||||
app.enableVersioning({
|
app.enableVersioning({
|
||||||
type: VersioningType.URI,
|
type: VersioningType.URI,
|
||||||
defaultVersion: VERSION_NEUTRAL,
|
defaultVersion: VERSION_NEUTRAL,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setSecurityHeaders(app, configService);
|
||||||
|
|
||||||
const listen_addr = process.env.LISTEN_ADDR || '::';
|
const listen_addr = process.env.LISTEN_ADDR || '::';
|
||||||
const port = parseInt(process.env.PORT) || 3000;
|
const port = parseInt(process.env.PORT) || 3000;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
const hasSubPath = process.env.SUB_PATH !== undefined;
|
||||||
|
const UrlPrefix = hasSubPath ? process.env.SUB_PATH : '';
|
||||||
|
|
||||||
|
const imports = [
|
||||||
|
ServeStaticModule.forRoot({
|
||||||
|
rootPath: join(__dirname, 'assets'),
|
||||||
|
serveRoot: (UrlPrefix ? UrlPrefix : '/../../../') + 'assets',
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
if (process.env.SERVE_CLIENT !== 'false' && process.env.NODE_ENV === 'production') {
|
||||||
|
imports.unshift(
|
||||||
|
ServeStaticModule.forRoot({
|
||||||
|
// Have to remove trailing slash of SUB_PATH.
|
||||||
|
serveRoot: process.env.SUB_PATH === undefined ? '' : process.env.SUB_PATH.replace(/\/$/, ''),
|
||||||
|
rootPath: join(__dirname, '../../../../../', 'frontend/build'),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports
|
||||||
|
})
|
||||||
|
|
||||||
|
export class StaticFileServerModule {}
|
||||||
Loading…
Reference in a new issue