From f9c972a96c027412d30c63404139adc63cdb7697 Mon Sep 17 00:00:00 2001 From: Will H Date: Sun, 7 Jul 2024 09:13:43 +1200 Subject: [PATCH] Use helmet to set security headers and restrict information sent to the frontend --- .../src/features/user/types/user.types.ts | 9 --- .../workspace/types/workspace.types.ts | 9 +-- apps/server/package.json | 2 +- .../src/core/user/dto/current-user.dto.ts | 20 +++++++ apps/server/src/core/user/user.controller.ts | 27 ++++++++- apps/server/src/main.ts | 7 ++- pnpm-lock.yaml | 57 ++++++++----------- 7 files changed, 77 insertions(+), 54 deletions(-) create mode 100644 apps/server/src/core/user/dto/current-user.dto.ts diff --git a/apps/client/src/features/user/types/user.types.ts b/apps/client/src/features/user/types/user.types.ts index a729073d..7d9b151c 100644 --- a/apps/client/src/features/user/types/user.types.ts +++ b/apps/client/src/features/user/types/user.types.ts @@ -4,19 +4,10 @@ export interface IUser { id: string; name: string; email: string; - emailVerifiedAt: Date; avatarUrl: string; timezone: string; - settings: IUserSettings; - invitedById: string; - lastLoginAt: string; - lastActiveAt: Date; - createdAt: Date; - updatedAt: Date; role: string; workspaceId: string; - deactivatedAt: Date; - deletedAt: Date; fullPageWidth: boolean; // used for update } diff --git a/apps/client/src/features/workspace/types/workspace.types.ts b/apps/client/src/features/workspace/types/workspace.types.ts index 5f424be5..51e8d1ab 100644 --- a/apps/client/src/features/workspace/types/workspace.types.ts +++ b/apps/client/src/features/workspace/types/workspace.types.ts @@ -3,14 +3,9 @@ export interface IWorkspace { name: string; description: string; logo: string; - hostname: string; - defaultSpaceId: string; - customDomain: string; - enableInvite: boolean; inviteCode: string; - settings: any; - createdAt: Date; - updatedAt: Date; + oidcEnabled: boolean; + oidcButtonName: string; } export interface ICreateInvite { diff --git a/apps/server/package.json b/apps/server/package.json index 2ca40c80..d78d3cb4 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -33,6 +33,7 @@ "@casl/ability": "^6.7.1", "@docmost/editor-ext": "workspace:*", "@fastify/cookie": "^9.3.1", + "@fastify/helmet": "^11.1.1", "@fastify/multipart": "^8.3.0", "@fastify/static": "^7.0.4", "@nestjs/bullmq": "^10.1.1", @@ -56,7 +57,6 @@ "bytes": "^3.1.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", - "fastify": "^4.28.0", "fix-esm": "^1.0.1", "fs-extra": "^11.2.0", "kysely": "^0.27.3", diff --git a/apps/server/src/core/user/dto/current-user.dto.ts b/apps/server/src/core/user/dto/current-user.dto.ts new file mode 100644 index 00000000..2cf6b5d2 --- /dev/null +++ b/apps/server/src/core/user/dto/current-user.dto.ts @@ -0,0 +1,20 @@ +export interface CurrentUserDto { + user: { + id: string; + name: string; + email: string; + role: string; + timezone: string; + avatarUrl: string; + workspaceId: string; + }; + + workspace: { + id: string; + name: string; + description: string; + logo: string; + oidcEnabled: boolean; + oidcButtonName: string; + }; +} diff --git a/apps/server/src/core/user/user.controller.ts b/apps/server/src/core/user/user.controller.ts index 6f1c934a..8bf0c8cd 100644 --- a/apps/server/src/core/user/user.controller.ts +++ b/apps/server/src/core/user/user.controller.ts @@ -13,6 +13,7 @@ import { AuthUser } from '../../common/decorators/auth-user.decorator'; import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'; import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator'; import { User, Workspace } from '@docmost/db/types/entity.types'; +import { CurrentUserDto } from './dto/current-user.dto'; @UseGuards(JwtAuthGuard) @Controller('users') @@ -24,8 +25,30 @@ export class UserController { async getUserIno( @AuthUser() authUser: User, @AuthWorkspace() workspace: Workspace, - ) { - return { user: authUser, workspace }; + ): Promise { + // Whenever we are sending user or workspace information to the frontend, + // we should only send the necessary information and not the entire object. + // This mitigates the risk of exposing sensitive information. + + return { + user: { + id: authUser.id, + name: authUser.name, + email: authUser.email, + role: authUser.role, + timezone: authUser.timezone, + avatarUrl: authUser.avatarUrl, + workspaceId: authUser.workspaceId, + }, + workspace: { + id: workspace.id, + name: workspace.name, + description: workspace.description, + logo: workspace.logo, + oidcEnabled: workspace.oidcEnabled, + oidcButtonName: workspace.oidcButtonName, + }, + }; } @HttpCode(HttpStatus.OK) diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts index 89830d58..144f6deb 100644 --- a/apps/server/src/main.ts +++ b/apps/server/src/main.ts @@ -10,6 +10,7 @@ import fastifyMultipart from '@fastify/multipart'; import { WsRedisIoAdapter } from './ws/adapter/ws-redis.adapter'; import { InternalLogFilter } from './common/logger/internal-log-filter'; import fastifyCookie from '@fastify/cookie'; +import helmet from '@fastify/helmet'; async function bootstrap() { const app = await NestFactory.create( @@ -31,8 +32,8 @@ async function bootstrap() { app.useWebSocketAdapter(redisIoAdapter); - await app.register(fastifyMultipart as any); - await app.register(fastifyCookie as any); + await app.register(fastifyMultipart); + await app.register(fastifyCookie); app .getHttpAdapter() @@ -65,6 +66,8 @@ async function bootstrap() { app.useGlobalInterceptors(new TransformHttpResponseInterceptor()); app.enableShutdownHooks(); + app.register(helmet, { global: true }); + await app.listen(process.env.PORT || 3000, '0.0.0.0'); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb7ebffb..0e2cc047 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -343,6 +343,9 @@ importers: '@fastify/cookie': specifier: ^9.3.1 version: 9.3.1 + '@fastify/helmet': + specifier: ^11.1.1 + version: 11.1.1 '@fastify/multipart': specifier: ^8.3.0 version: 8.3.0 @@ -412,9 +415,6 @@ importers: class-validator: specifier: ^0.14.1 version: 0.14.1 - fastify: - specifier: ^4.28.0 - version: 4.28.0 fix-esm: specifier: ^1.0.1 version: 1.0.1 @@ -1914,6 +1914,9 @@ packages: '@fastify/formbody@7.4.0': resolution: {integrity: sha512-H3C6h1GN56/SMrZS8N2vCT2cZr7mIHzBHzOBa5OPpjfB/D6FzP9mMpE02ZzrFX0ANeh0BAJdoXKOF2e7IbV+Og==} + '@fastify/helmet@11.1.1': + resolution: {integrity: sha512-pjJxjk6SLEimITWadtYIXt6wBMfFC1I6OQyH/jYVCqSAn36sgAIFjeNiibHtifjCd+e25442pObis3Rjtame6A==} + '@fastify/merge-json-schemas@0.1.1': resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} @@ -5214,9 +5217,6 @@ packages: fastify@4.27.0: resolution: {integrity: sha512-ci9IXzbigB8dyi0mSy3faa3Bsj0xWAPb9JeT4KRzubdSb6pNhcADRUaXCBml6V1Ss/a05kbtQls5LBmhHydoTA==} - fastify@4.28.0: - resolution: {integrity: sha512-HhW7UHW07YlqH5qpS0af8d2Gl/o98DhJ8ZDQWHRNDnzeOhZvtreWsX8xanjGgXmkYerGbo8ax/n40Dpwqkot8Q==} - fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -5472,6 +5472,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + helmet@7.1.0: + resolution: {integrity: sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==} + engines: {node: '>=16.0.0'} + hexoid@1.0.0: resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} engines: {node: '>=8'} @@ -9936,6 +9940,11 @@ snapshots: fast-querystring: 1.1.2 fastify-plugin: 4.5.1 + '@fastify/helmet@11.1.1': + dependencies: + fastify-plugin: 4.5.1 + helmet: 7.1.0 + '@fastify/merge-json-schemas@0.1.1': dependencies: fast-deep-equal: 3.1.3 @@ -13704,27 +13713,6 @@ snapshots: transitivePeerDependencies: - supports-color - fastify@4.28.0: - dependencies: - '@fastify/ajv-compiler': 3.5.0 - '@fastify/error': 3.4.1 - '@fastify/fast-json-stringify-compiler': 4.3.0 - abstract-logging: 2.0.1 - avvio: 8.3.0 - fast-content-type-parse: 1.1.0 - fast-json-stringify: 5.13.0 - find-my-way: 8.1.0 - light-my-request: 5.13.0 - pino: 9.1.0 - process-warning: 3.0.0 - proxy-addr: 2.0.7 - rfdc: 1.3.1 - secure-json-parse: 2.7.0 - semver: 7.6.2 - toad-cache: 3.7.0 - transitivePeerDependencies: - - supports-color - fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -14002,6 +13990,8 @@ snapshots: dependencies: function-bind: 1.1.2 + helmet@7.1.0: {} + hexoid@1.0.0: {} highlight.js@11.9.0: {} @@ -16433,25 +16423,26 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - terser-webpack-plugin@5.3.10(@swc/core@1.5.25(@swc/helpers@0.5.11))(webpack@5.90.1(@swc/core@1.5.25(@swc/helpers@0.5.11))): + terser-webpack-plugin@5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)(webpack@5.91.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.90.1(@swc/core@1.5.25(@swc/helpers@0.5.11)) + webpack: 5.91.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) optionalDependencies: - '@swc/core': 1.5.25(@swc/helpers@0.5.11) + '@swc/core': 1.3.101(@swc/helpers@0.5.11) + esbuild: 0.19.11 - terser-webpack-plugin@5.3.10(@swc/core@1.5.25(@swc/helpers@0.5.11))(webpack@5.91.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)): + terser-webpack-plugin@5.3.10(@swc/core@1.5.25(@swc/helpers@0.5.11))(webpack@5.90.1(@swc/core@1.5.25(@swc/helpers@0.5.11))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.91.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) + webpack: 5.90.1(@swc/core@1.5.25(@swc/helpers@0.5.11)) optionalDependencies: '@swc/core': 1.5.25(@swc/helpers@0.5.11) @@ -16817,7 +16808,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.25(@swc/helpers@0.5.11))(webpack@5.91.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)(webpack@5.91.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: