@hmcts/opal-frontend-common-node 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.editorconfig +16 -0
  2. package/.github/renovate.json +11 -0
  3. package/.github/workflows/npm_build.yml +67 -0
  4. package/.prettierignore +12 -0
  5. package/.prettierrc +7 -0
  6. package/.vscode/settings.json +6 -0
  7. package/LICENSE +21 -0
  8. package/README.md +109 -0
  9. package/eslint.config.js +22 -0
  10. package/package.json +117 -0
  11. package/sonar-project.properties +9 -0
  12. package/src/app-insights/app-insights-configuration.ts +18 -0
  13. package/src/app-insights/index.ts +39 -0
  14. package/src/csrf-token/index.ts +36 -0
  15. package/src/global.d.ts +2 -0
  16. package/src/health/index.ts +32 -0
  17. package/src/helmet/index.ts +60 -0
  18. package/src/index.ts +10 -0
  19. package/src/interfaces/app-insights-config.ts +7 -0
  20. package/src/interfaces/index.ts +23 -0
  21. package/src/interfaces/launch-darkly-config.ts +7 -0
  22. package/src/interfaces/routes-config.ts +8 -0
  23. package/src/interfaces/securityToken.ts +8 -0
  24. package/src/interfaces/session-config.ts +5 -0
  25. package/src/interfaces/session-expiry-config.ts +7 -0
  26. package/src/interfaces/session-storage-config.ts +12 -0
  27. package/src/interfaces/sso-config.ts +9 -0
  28. package/src/interfaces/transfer-server-state.ts +10 -0
  29. package/src/interfaces/userState.ts +18 -0
  30. package/src/launch-darkly/index.ts +17 -0
  31. package/src/properties-volume/index.ts +12 -0
  32. package/src/proxy/index.ts +1 -0
  33. package/src/proxy/opal-api-proxy/index.ts +19 -0
  34. package/src/routes/index.ts +91 -0
  35. package/src/session/index.ts +5 -0
  36. package/src/session/session-expiry/index.ts +31 -0
  37. package/src/session/session-storage/index.ts +68 -0
  38. package/src/session/session-user-state/index.ts +24 -0
  39. package/src/session.d.ts +10 -0
  40. package/src/sso/index.ts +7 -0
  41. package/src/sso/sso-authenticated.ts +15 -0
  42. package/src/sso/sso-login-callback.ts +30 -0
  43. package/src/sso/sso-login.ts +31 -0
  44. package/src/sso/sso-logout-callback.ts +17 -0
  45. package/src/sso/sso-logout.ts +41 -0
  46. package/src/stubs/sso/index.ts +7 -0
  47. package/src/stubs/sso/sso-authenticated.stub.ts +16 -0
  48. package/src/stubs/sso/sso-login-callback.stub.ts +29 -0
  49. package/src/stubs/sso/sso-login.stub.ts +16 -0
  50. package/src/stubs/sso/sso-logout-callback.stub.ts +16 -0
  51. package/src/stubs/sso/sso-logout.stub.ts +6 -0
  52. package/src/type.d.ts +7 -0
  53. package/src/utils/base64.ts +7 -0
  54. package/src/utils/index.ts +3 -0
  55. package/src/utils/jwt.ts +35 -0
  56. package/tsconfig.json +72 -0
package/.editorconfig ADDED
@@ -0,0 +1,16 @@
1
+ # Editor configuration, see https://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ charset = utf-8
6
+ indent_style = space
7
+ indent_size = 2
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.ts]
12
+ quote_type = single
13
+
14
+ [*.md]
15
+ max_line_length = off
16
+ trim_trailing_whitespace = false
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": ["github>hmcts/.github//renovate/automerge-all", "local>hmcts/.github:renovate-config"],
4
+ "packageRules": [
5
+ {
6
+ "matchPackageNames": ["copy-webpack-plugin"],
7
+ "allowedVersions": "<=10",
8
+ "description": "https://canary.discord.com/channels/226791405589233664/1019534554073157642 and https://github.com/webpack-contrib/copy-webpack-plugin/issues/643 doesn't work even though issue closed"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,67 @@
1
+ name: Angular Library CI Pipeline
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ release:
9
+ types: [created]
10
+
11
+ jobs:
12
+ ci:
13
+ name: Build, Test, and Analyse
14
+ if: github.event_name != 'release'
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Install dependencies
21
+ run: yarn install --frozen-lockfile
22
+
23
+ - name: Lint code
24
+ run: yarn lint
25
+
26
+ - name: Audit vulnerabilities
27
+ run: yarn audit --production
28
+
29
+ - name: Analyze with SonarCloud
30
+ uses: SonarSource/sonarqube-scan-action@v5.1.0
31
+ env:
32
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
33
+
34
+ - name: Build library
35
+ run: yarn build
36
+
37
+ release:
38
+ name: Release and Publish
39
+ if: github.event_name == 'release'
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - name: Checkout repository (Release)
43
+ uses: actions/checkout@v4
44
+ with:
45
+ ref: ${{ github.event.release.target_commitish }}
46
+
47
+ - name: Validate and extract release information
48
+ id: release
49
+ uses: manovotny/github-releases-for-automated-package-publishing-action@v2.0.1
50
+
51
+ - name: Setup Node.js (Release)
52
+ uses: actions/setup-node@v4
53
+ with:
54
+ node-version: '22.x'
55
+ registry-url: 'https://registry.npmjs.org'
56
+ always-auth: true
57
+
58
+ - name: Install dependencies (Release)
59
+ run: yarn install --frozen-lockfile
60
+
61
+ - name: Build library (Release)
62
+ run: yarn build
63
+
64
+ - name: Publish version
65
+ run: yarn publish --new-version ${{ steps.release.outputs.version }} --access public
66
+ env:
67
+ NODE_AUTH_TOKEN: ${{ secrets.npm_api_token }}
@@ -0,0 +1,12 @@
1
+ # third party
2
+ dist
3
+ .angular
4
+ yarn.lock
5
+ .yarn/
6
+
7
+ .vscode
8
+ coverage
9
+ charts
10
+
11
+ server/assets/*
12
+ server/views/azuread-b2c-login.html
package/.prettierrc ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "tabWidth": 2,
3
+ "useTabs": false,
4
+ "singleQuote": true,
5
+ "printWidth": 120,
6
+ "semi" : true
7
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sonarlint.connectedMode.project": {
3
+ "connectionId": "HMCTS",
4
+ "projectKey": "hmcts_opal-frontend-common-node-lib"
5
+ }
6
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 HM Courts & Tribunals Service
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # OPAL Frontend Common Node Library
2
+ [![npm version](https://img.shields.io/npm/v/@hmcts/opal-frontend-common-node)](https://www.npmjs.com/package/@hmcts/opal-frontend-common-node)
3
+ [![License](https://img.shields.io/npm/l/@hmcts/opal-frontend-common-node)](https://github.com/hmcts/opal-frontend-common-node-lib/blob/main/LICENSE)
4
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=hmcts_opal-frontend-common-node-lib&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=hmcts_opal-frontend-common-node-lib)
5
+
6
+ This is a shared Node.js library containing common middleware, configurations, and utilities used across OPAL backend services.
7
+
8
+ ## Table of Contents
9
+
10
+ - [Getting Started](#getting-started)
11
+ - [Scripts](#scripts)
12
+ - [Build Process](#build-process)
13
+ - [Linting and Formatting](#linting-and-formatting)
14
+ - [Exports](#exports)
15
+ - [Using This Library in a Node.js Application](#using-this-library-in-a-nodejs-application)
16
+
17
+ ## Getting Started
18
+
19
+ ### Prerequisites
20
+
21
+ Ensure you have the following installed:
22
+
23
+ - [Node.js](https://nodejs.org/) v18 or later
24
+ - [Yarn](https://classic.yarnpkg.com/) v1.22.22 or later
25
+
26
+ ### Install Dependencies
27
+
28
+ ```bash
29
+ yarn
30
+ ```
31
+
32
+ ## Scripts
33
+
34
+ The following commands are available in the `package.json`:
35
+
36
+ - `yarn build`
37
+ Cleans the `dist/` folder, compiles TypeScript, and copies relevant files to `dist/`.
38
+
39
+ - `yarn clean`
40
+ Removes the `dist/` directory.
41
+
42
+ - `yarn lint`
43
+ Runs ESLint across the `src/` directory and checks formatting using Prettier.
44
+
45
+ - `yarn prettier`
46
+ Checks if files are formatted correctly.
47
+
48
+ - `yarn prettier:fix`
49
+ Automatically formats the codebase.
50
+
51
+ ## Build Process
52
+
53
+ Run the following to build the project:
54
+
55
+ ```bash
56
+ yarn build
57
+ ```
58
+
59
+ The compiled output will be available in the `dist/` folder. It includes `index.js`, type declarations, and any exported modules listed in the `exports` field.
60
+
61
+ ## Linting and Formatting
62
+
63
+ To lint and check formatting:
64
+
65
+ ```bash
66
+ yarn lint
67
+ ```
68
+
69
+ To fix formatting issues automatically:
70
+
71
+ ```bash
72
+ yarn prettier:fix
73
+ ```
74
+
75
+ ## Exports
76
+
77
+ This library exposes multiple entry points under the `exports` field of `package.json`. Example usage:
78
+
79
+ ```ts
80
+ import { CSRFToken } from '@hmcts/opal-frontend-common-node/csrf-token';
81
+ import { AppInsights } from '@hmcts/opal-frontend-common-node/app-insights';
82
+ import { Helmet } from '@hmcts/opal-frontend-common-node/helmet';
83
+ import { LaunchDarkly } from '@hmcts/opal-frontend-common-node/launch-darkly';
84
+ import {
85
+ ExpiryConfiguration,
86
+ RoutesConfiguration,
87
+ SessionStorageConfiguration,
88
+ TransferServerState,
89
+ } from '@hmcts/opal-frontend-common-node/interfaces';
90
+ ```
91
+
92
+ Refer to the `exports` block in `package.json` for the full list of available modules.
93
+
94
+ ## Using This Library in a Node.js Application
95
+
96
+ Install the published package using:
97
+
98
+ ```bash
99
+ yarn add @hmcts/opal-frontend-common-node
100
+ ```
101
+
102
+ If consuming from a local build:
103
+
104
+ ```bash
105
+ yarn remove @hmcts/opal-frontend-common-node
106
+ yarn add @hmcts/opal-frontend-common-node@file:../opal-frontend-common-node-lib/dist
107
+ ```
108
+
109
+ Ensure paths reflect your actual local setup when using the `file:` specifier.
@@ -0,0 +1,22 @@
1
+ // eslint.config.js
2
+ import tseslint from 'typescript-eslint';
3
+ import prettierPlugin from 'eslint-plugin-prettier';
4
+
5
+ /** @type {import("eslint").Linter.FlatConfig[]} */
6
+ export default [
7
+ // Recommended base config (no type-checking rules)
8
+ ...tseslint.configs.recommended,
9
+
10
+ // You can add stricter type-checking rules later:
11
+ // ...tseslint.configs['recommended-requiring-type-checking'],
12
+
13
+ {
14
+ files: ['**/*.ts'],
15
+ plugins: {
16
+ prettier: prettierPlugin,
17
+ },
18
+ rules: {
19
+ 'prettier/prettier': 'error',
20
+ },
21
+ },
22
+ ];
package/package.json ADDED
@@ -0,0 +1,117 @@
1
+ {
2
+ "name": "@hmcts/opal-frontend-common-node",
3
+ "type": "module",
4
+ "version": "0.0.2",
5
+ "description": "Common nodejs library components for opal",
6
+ "main": "dist/index",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": " yarn clean && tsc && cp package.json dist/ && cp src/*.d.ts dist/",
10
+ "clean": "rm -rf dist",
11
+ "lint": "eslint ./src --ext .ts && yarn prettier",
12
+ "prettier": "prettier --check \"./src/**/*.{ts,js,json}\"",
13
+ "prettier:fix": "prettier --write \"./src/**/*.{ts,js,json}\""
14
+ },
15
+ "dependencies": {
16
+ "@hmcts/info-provider": "^1.1.0",
17
+ "@hmcts/nodejs-healthcheck": "^1.8.5",
18
+ "@hmcts/nodejs-logging": "^4.0.4",
19
+ "@hmcts/properties-volume": "^1.1.0",
20
+ "applicationinsights": "~2.9.6",
21
+ "axios": "^1.6.2",
22
+ "body-parser": "^2.0.0",
23
+ "config": "^3.3.9",
24
+ "connect-redis": "^8.0.0",
25
+ "cookie-parser": "^1.4.6",
26
+ "csrf-csrf": "^3.0.6",
27
+ "express": "^4.15.2",
28
+ "express-session": "^1.17.3",
29
+ "helmet": "^8.0.0",
30
+ "http-proxy-middleware": "^3.0.0",
31
+ "luxon": "^3.4.3",
32
+ "prettier": "^3.0.3",
33
+ "redis": "^4.6.11",
34
+ "session-file-store": "^1.5.0",
35
+ "xml2js": "^0.6.2"
36
+ },
37
+ "devDependencies": {
38
+ "@types/config": "^3.3.3",
39
+ "@types/cookie-parser": "^1.4.6",
40
+ "@types/express": "^5.0.0",
41
+ "@types/luxon": "^3.4.2",
42
+ "@types/node": "^22.0.0",
43
+ "@types/session-file-store": "^1.2.5",
44
+ "@typescript-eslint/eslint-plugin": "8.29.1",
45
+ "@typescript-eslint/parser": "8.29.1",
46
+ "eslint": "^9.0.0",
47
+ "eslint-plugin-prettier": "^5.2.6",
48
+ "typescript": "~5.8.0",
49
+ "typescript-eslint": "^8.30.1"
50
+ },
51
+ "packageManager": "yarn@1.22.22",
52
+ "exports": {
53
+ ".": {
54
+ "import": "./index.js",
55
+ "types": "./index.d.ts"
56
+ },
57
+ "./app-insights": {
58
+ "import": "./app-insights/index.js",
59
+ "types": "./app-insights/index.d.ts"
60
+ },
61
+ "./health": {
62
+ "import": "./health/index.js",
63
+ "types": "./health/index.d.ts"
64
+ },
65
+ "./helmet": {
66
+ "import": "./helmet/index.js",
67
+ "types": "./helmet/index.d.ts"
68
+ },
69
+ "./launch-darkly": {
70
+ "import": "./launch-darkly/index.js",
71
+ "types": "./launch-darkly/index.d.ts"
72
+ },
73
+ "./properties-volume": {
74
+ "import": "./properties-volume/index.js",
75
+ "types": "./properties-volume/index.d.ts"
76
+ },
77
+ "./csrf-token": {
78
+ "import": "./csrf-token/index.js",
79
+ "types": "./csrf-token/index.d.ts"
80
+ },
81
+ "./routes": {
82
+ "import": "./routes/index.js",
83
+ "types": "./routes/index.d.ts"
84
+ },
85
+ "./interfaces": {
86
+ "import": "./interfaces/index.js",
87
+ "types": "./interfaces/index.d.ts"
88
+ },
89
+ "./session": {
90
+ "import": "./session/index.js",
91
+ "types": "./session/index.d.ts"
92
+ },
93
+ "./session/session-storage": {
94
+ "import": "./session/session-storage/index.js",
95
+ "types": "./session/session-storage/index.d.ts"
96
+ },
97
+ "./session/session-expiry": {
98
+ "import": "./session/session-expiry/index.js",
99
+ "types": "./session/session-expiry/index.d.ts"
100
+ },
101
+ "./session/session-user-state": {
102
+ "import": "./session/session-user-state/index.js",
103
+ "types": "./session/session-user-state/index.d.ts"
104
+ },
105
+ "./proxy": {
106
+ "import": "./proxy/index.js",
107
+ "types": "./proxy/index.d.ts"
108
+ },
109
+ "./proxy/opal-api-proxy": {
110
+ "import": "./proxy/opal-api-proxy/index.js",
111
+ "types": "./proxy/opal-api-proxy/index.d.ts"
112
+ },
113
+ "./types": {
114
+ "types": "./global.d.ts"
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,9 @@
1
+ sonar.organization=hmcts
2
+ sonar.projectKey=hmcts_opal-frontend-common-node-lib
3
+ sonar.projectName=opal-frontend-common-node-lib
4
+ sonar.projectVersion=0.0.1
5
+
6
+ sonar.sources=src
7
+
8
+ # Skip code coverage reporting
9
+ sonar.coverage.exclusions=**/*
@@ -0,0 +1,18 @@
1
+ import AppInsightConfig from '../interfaces/app-insights-config';
2
+
3
+ export default class AppInsightsConfiguration {
4
+ public enableFor(enabled: boolean, connectionString: string | null, cloudRoleName: string | null): AppInsightConfig {
5
+ const appInsightsConfig: AppInsightConfig = {
6
+ enabled: enabled,
7
+ connectionString: null,
8
+ cloudRoleName: null,
9
+ };
10
+
11
+ if (enabled && connectionString && cloudRoleName) {
12
+ appInsightsConfig.connectionString = connectionString;
13
+ appInsightsConfig.cloudRoleName = cloudRoleName;
14
+ }
15
+
16
+ return appInsightsConfig;
17
+ }
18
+ }
@@ -0,0 +1,39 @@
1
+ process.env['APPLICATIONINSIGHTS_CONFIGURATION_CONTENT'] = '{}';
2
+ import * as appInsights from 'applicationinsights';
3
+ import AppInsightConfig from '../interfaces/app-insights-config';
4
+ import AppInsightsConfiguration from './app-insights-configuration';
5
+
6
+ // As of 2.9.0 issue reading bundled applicationinsights.json
7
+ // https://github.com/microsoft/ApplicationInsights-node.js/issues/1226
8
+ // Define config below...
9
+
10
+ export class AppInsights {
11
+ enable(enabled: boolean, connectionString: string | null, cloudRoleName: string | null): AppInsightConfig {
12
+ const appInsightsConfigInstance = new AppInsightsConfiguration();
13
+ const appInsightsConfig = appInsightsConfigInstance.enableFor(enabled, connectionString, cloudRoleName);
14
+
15
+ if (enabled && connectionString) {
16
+ appInsights
17
+ .setup(connectionString)
18
+ .setAutoCollectRequests(true)
19
+ .setAutoCollectPerformance(true, true)
20
+ .setAutoCollectExceptions(true)
21
+ .setAutoCollectDependencies(true)
22
+ .setAutoCollectConsole(true, false)
23
+ .setAutoCollectPreAggregatedMetrics(true)
24
+ .setSendLiveMetrics(true)
25
+ .setInternalLogging(false, true)
26
+ .enableWebInstrumentation(false)
27
+ .start();
28
+
29
+ if (cloudRoleName) {
30
+ appInsights.defaultClient.context.tags[appInsights.defaultClient.context.keys.cloudRole] = cloudRoleName;
31
+ }
32
+ appInsights.defaultClient.trackTrace({
33
+ message: 'App insights activated',
34
+ });
35
+ }
36
+
37
+ return appInsightsConfig;
38
+ }
39
+ }
@@ -0,0 +1,36 @@
1
+ import { doubleCsrf } from 'csrf-csrf';
2
+ import { Application, Request } from 'express';
3
+
4
+ export class CSRFToken {
5
+ public enableFor(app: Application, secret: string, cookieName: string, sameSite: boolean, secure: boolean): void {
6
+ const ignore = ['/sso/login-callback'];
7
+
8
+ const { doubleCsrfProtection } = doubleCsrf({
9
+ getSecret: () => secret,
10
+ cookieName: cookieName,
11
+ cookieOptions: {
12
+ sameSite: sameSite,
13
+ secure: secure,
14
+ path: '/',
15
+ },
16
+ getTokenFromRequest: (req) => {
17
+ return req.cookies[cookieName].split('|')[0] ?? null;
18
+ },
19
+ });
20
+
21
+ app.use((req, res, next) => {
22
+ if (ignore.includes(req.url)) {
23
+ next();
24
+ } else {
25
+ doubleCsrfProtection(req, res, next);
26
+ }
27
+ });
28
+
29
+ app.use((req: Request, res, next) => {
30
+ if (req.csrfToken) {
31
+ req.csrfToken(true);
32
+ }
33
+ next();
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,2 @@
1
+ declare module '@hmcts/nodejs-logging';
2
+ declare module '@hmcts/nodejs-healthcheck';
@@ -0,0 +1,32 @@
1
+ import os from 'os';
2
+ import healthcheck from '@hmcts/nodejs-healthcheck';
3
+ import { Application } from 'express';
4
+
5
+ /**
6
+ * Sets up the HMCTS info and health endpoints
7
+ */
8
+ export class HealthCheck {
9
+ public enableFor(app: Application, buildInfoName: string): void {
10
+ const redis = app.locals['redisClient']
11
+ ? healthcheck.raw(() => app.locals['redisClient'].ping().then(healthcheck.up).catch(healthcheck.down))
12
+ : null;
13
+
14
+ healthcheck.addTo(app, {
15
+ checks: {
16
+ ...(redis ? { redis } : {}),
17
+ },
18
+ ...(redis
19
+ ? {
20
+ readinessChecks: {
21
+ redis,
22
+ },
23
+ }
24
+ : {}),
25
+ buildInfo: {
26
+ name: buildInfoName,
27
+ host: os.hostname(),
28
+ uptime: process.uptime(),
29
+ },
30
+ });
31
+ }
32
+ }
@@ -0,0 +1,60 @@
1
+ import * as express from 'express';
2
+ import helmet from 'helmet';
3
+ import { Logger } from '@hmcts/nodejs-logging';
4
+
5
+ const logger = Logger.getLogger('helmet');
6
+ const googleAnalyticsDomain = '*.google-analytics.com';
7
+ const self = "'self'";
8
+ const dynatraceDomain = '*.dynatrace.com';
9
+ const LaunchDarklyDomain = '*.launchdarkly.com';
10
+ const azureDomain = '*.azure.com';
11
+ const applicationInsightsDomain = '*.applicationinsights.azure.com';
12
+ /**
13
+ * Module that enables helmet in the application
14
+ */
15
+ export class Helmet {
16
+ private readonly developmentMode: boolean;
17
+ constructor(developmentMode: boolean) {
18
+ this.developmentMode = developmentMode;
19
+ }
20
+
21
+ public enableFor(app: express.Express, enabled: boolean): void {
22
+ if (enabled) {
23
+ logger.info('Helmet enabled');
24
+ // include default helmet functions
25
+ const scriptSrc = [
26
+ self,
27
+ googleAnalyticsDomain,
28
+ dynatraceDomain,
29
+ "'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU='",
30
+ "'unsafe-inline'",
31
+ ];
32
+
33
+ if (this.developmentMode) {
34
+ // Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval'
35
+ // is not an allowed source of script in the following Content Security Policy directive:
36
+ // "script-src 'self' *.google-analytics.com 'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU='".
37
+ // seems to be related to webpack
38
+ scriptSrc.push("'unsafe-eval'");
39
+ }
40
+
41
+ app.use(
42
+ helmet({
43
+ contentSecurityPolicy: {
44
+ directives: {
45
+ connectSrc: [self, dynatraceDomain, LaunchDarklyDomain, azureDomain, applicationInsightsDomain],
46
+ defaultSrc: ["'none'"],
47
+ fontSrc: [self, 'data:', 'https://fonts.gstatic.com'],
48
+ imgSrc: [self, googleAnalyticsDomain],
49
+ objectSrc: [self],
50
+ scriptSrc,
51
+ styleSrc: [self, "'unsafe-inline'", 'https://fonts.googleapis.com'],
52
+ scriptSrcAttr: ["'unsafe-inline'"],
53
+ },
54
+ },
55
+ referrerPolicy: { policy: 'origin' },
56
+ }),
57
+ );
58
+ }
59
+ }
60
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './launch-darkly';
2
+ export * from './app-insights';
3
+ export * from './health';
4
+ export * from './helmet';
5
+ export * from './properties-volume';
6
+ export * from './csrf-token';
7
+ export * from './routes';
8
+
9
+ // INTERFACES
10
+ export * from './interfaces';
@@ -0,0 +1,7 @@
1
+ class AppInsightsConfig {
2
+ enabled!: boolean;
3
+ connectionString!: string | null;
4
+ cloudRoleName!: string | null;
5
+ }
6
+
7
+ export default AppInsightsConfig;
@@ -0,0 +1,23 @@
1
+ import UserState from './userState';
2
+ import SecurityToken from './securityToken';
3
+ import launchDarklyConfig from './launch-darkly-config';
4
+ import appInsightsConfig from './app-insights-config';
5
+ import TransferServerState from './transfer-server-state';
6
+ import ExpiryConfiguration from './session-expiry-config';
7
+ import SessionStorageConfiguration from './session-storage-config';
8
+ import RoutesConfiguration from './routes-config';
9
+ import SsoConfiguration from './sso-config';
10
+ import SessionConfiguration from './session-config';
11
+
12
+ export {
13
+ UserState,
14
+ SecurityToken,
15
+ launchDarklyConfig,
16
+ appInsightsConfig,
17
+ TransferServerState,
18
+ ExpiryConfiguration,
19
+ SessionStorageConfiguration,
20
+ RoutesConfiguration,
21
+ SsoConfiguration,
22
+ SessionConfiguration,
23
+ };
@@ -0,0 +1,7 @@
1
+ class LaunchDarklyConfig {
2
+ enabled!: boolean;
3
+ clientId!: string | null;
4
+ stream!: boolean;
5
+ }
6
+
7
+ export default LaunchDarklyConfig;
@@ -0,0 +1,8 @@
1
+ class RoutesConfiguration {
2
+ opalApiTarget!: string;
3
+ opalFinesServiceTarget!: string;
4
+ frontendHostname!: string;
5
+ prefix!: string;
6
+ }
7
+
8
+ export default RoutesConfiguration;
@@ -0,0 +1,8 @@
1
+ import UserState from './userState';
2
+
3
+ class SecurityToken {
4
+ user_state: UserState | undefined;
5
+ access_token!: string;
6
+ }
7
+
8
+ export default SecurityToken;