@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.
- package/.editorconfig +16 -0
- package/.github/renovate.json +11 -0
- package/.github/workflows/npm_build.yml +67 -0
- package/.prettierignore +12 -0
- package/.prettierrc +7 -0
- package/.vscode/settings.json +6 -0
- package/LICENSE +21 -0
- package/README.md +109 -0
- package/eslint.config.js +22 -0
- package/package.json +117 -0
- package/sonar-project.properties +9 -0
- package/src/app-insights/app-insights-configuration.ts +18 -0
- package/src/app-insights/index.ts +39 -0
- package/src/csrf-token/index.ts +36 -0
- package/src/global.d.ts +2 -0
- package/src/health/index.ts +32 -0
- package/src/helmet/index.ts +60 -0
- package/src/index.ts +10 -0
- package/src/interfaces/app-insights-config.ts +7 -0
- package/src/interfaces/index.ts +23 -0
- package/src/interfaces/launch-darkly-config.ts +7 -0
- package/src/interfaces/routes-config.ts +8 -0
- package/src/interfaces/securityToken.ts +8 -0
- package/src/interfaces/session-config.ts +5 -0
- package/src/interfaces/session-expiry-config.ts +7 -0
- package/src/interfaces/session-storage-config.ts +12 -0
- package/src/interfaces/sso-config.ts +9 -0
- package/src/interfaces/transfer-server-state.ts +10 -0
- package/src/interfaces/userState.ts +18 -0
- package/src/launch-darkly/index.ts +17 -0
- package/src/properties-volume/index.ts +12 -0
- package/src/proxy/index.ts +1 -0
- package/src/proxy/opal-api-proxy/index.ts +19 -0
- package/src/routes/index.ts +91 -0
- package/src/session/index.ts +5 -0
- package/src/session/session-expiry/index.ts +31 -0
- package/src/session/session-storage/index.ts +68 -0
- package/src/session/session-user-state/index.ts +24 -0
- package/src/session.d.ts +10 -0
- package/src/sso/index.ts +7 -0
- package/src/sso/sso-authenticated.ts +15 -0
- package/src/sso/sso-login-callback.ts +30 -0
- package/src/sso/sso-login.ts +31 -0
- package/src/sso/sso-logout-callback.ts +17 -0
- package/src/sso/sso-logout.ts +41 -0
- package/src/stubs/sso/index.ts +7 -0
- package/src/stubs/sso/sso-authenticated.stub.ts +16 -0
- package/src/stubs/sso/sso-login-callback.stub.ts +29 -0
- package/src/stubs/sso/sso-login.stub.ts +16 -0
- package/src/stubs/sso/sso-logout-callback.stub.ts +16 -0
- package/src/stubs/sso/sso-logout.stub.ts +6 -0
- package/src/type.d.ts +7 -0
- package/src/utils/base64.ts +7 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/jwt.ts +35 -0
- 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 }}
|
package/.prettierignore
ADDED
package/.prettierrc
ADDED
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
|
+
[](https://www.npmjs.com/package/@hmcts/opal-frontend-common-node)
|
|
3
|
+
[](https://github.com/hmcts/opal-frontend-common-node-lib/blob/main/LICENSE)
|
|
4
|
+
[](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.
|
package/eslint.config.js
ADDED
|
@@ -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,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
|
+
}
|
package/src/global.d.ts
ADDED
|
@@ -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,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
|
+
};
|