├── .gitignore
├── GeoPol.xml
├── README.md
├── SECURITY.md
├── Web.config
├── azuredeploy.json
├── dockerfile
├── package-lock.json
├── package.json
├── public
├── index.html
├── index.js
└── stylesheets
│ └── style.css
├── secrets.png
└── server.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea
3 | .env
4 | .deployment
5 | .vscode
--------------------------------------------------------------------------------
/GeoPol.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | ]>
7 |
8 |
9 |
10 | &GitReposFolder;\AInR_NExT\&GitRepoName;
11 | &GitRepoName;
12 |
13 |
14 | .
15 |
16 |
17 | .gitignore
18 | GeoPol.xml
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Health Bot Container
2 |
3 | A simple web page that allows users to communicate with the [Azure Health Bot](https://azure.microsoft.com/en-us/services/bot-services/health-bot/) through a WebChat.
4 |
5 | **Note:** In order to use this Web Chat with the Health Bot service, you will need to obtain your Web Chat secret by going to `Integration/Secrets` on the navigation panel.
6 |
7 | 
8 |
9 | 1.Deploy the website:
10 |
11 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2FHealthBotContainerSample%2Fmaster%2Fazuredeploy.json)
12 |
13 | 2.Set the following environment variables:
14 |
15 | `APP_SECRET`
16 |
17 | `WEBCHAT_SECRET`
18 |
19 | 3.Configure scenario invocation (optional):
20 |
21 | The Health Bot service uses [language models](https://docs.microsoft.com/HealthBot/language_model_howto) to interpret end user utterances and trigger the relevant scenario logic in response.
22 |
23 | Alternatively, you can programmaticaly invoke a scenario before the end user provides any input.
24 |
25 | To implement this behavior, uncomment the following code from the `function initBotConversation()` in the `/public/index.js` file:
26 | ```javascript
27 | triggeredScenario: {
28 | trigger: "{scenario_id}",
29 | args: {
30 | myVar1: "{custom_arg_1}",
31 | myVar2: "{custom_arg_2}"
32 | }
33 | }
34 | ```
35 | Replace {scenario_id} with the scenario ID of the scenario you would like to invoke.
36 | You can also pass different values through the "args" object.
37 |
38 | You can read more about programmatic client side scenario invocation [here](https://docs.microsoft.com/HealthBot/integrations/programmatic_invocation)
39 |
40 |
41 | 4.Set the Bot service direct line channel endpoint (optional)
42 |
43 | In some cases it is required to set the endpoint URI so that it points to a specific geography. The geographies supported by the bot service each have a unique direct line endpoint URI:
44 |
45 | - `directline.botframework.com` routes your client to the nearest datacenter. This is the best option if you do not know where your client is located.
46 | - `asia.directline.botframework.com` routes only to Direct Line servers in Eastern Asia.
47 | - `europe.directline.botframework.com` routes only to Direct Line servers in Europe.
48 | - `northamerica.directline.botframework.com` routes only to Direct Line servers in North America.
49 |
50 | Pass your preferred geographic endpoint URI by setting the environment variable: `DIRECTLINE_ENDPOINT_URI` in your deployment. If no variable is found it will default to `directline.botframework.com`
51 |
52 | **Note:** If you are deploying the code sample using the "Deploy to Azure" option, you should add the above secrets to the application settings for your App Service.
53 |
54 | ## Agent webchat
55 | If the agent webchat sample is also required, [switch to the live agent handoff branch](https://github.com/Microsoft/HealthBotContainerSample/tree/live_agent_handoff)
56 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/azuredeploy.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "siteName": {
6 | "type": "string",
7 | "defaultValue": "[concat('healthcare-bot-', uniqueString(utcNow('F')))]",
8 | "metadata":{
9 | "description": "Web site name. Has to be unique."
10 |
11 | }
12 | },
13 | "operatingSystem": {
14 | "type": "string",
15 | "defaultValue": "windows",
16 | "allowedValues": [
17 | "windows",
18 | "linux"
19 | ],
20 | "metadata": {
21 | "description": "Host type: Windows or Linux. (Windows is recommended)"
22 | }
23 | },
24 | "skuName": {
25 | "type": "string",
26 | "defaultValue": "P1V2",
27 | "allowedValues": [
28 | "B1",
29 | "S1",
30 | "P1V2"
31 | ],
32 | "metadata": {
33 | "description": "Describes plan's pricing tier and instance size. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
34 | }
35 | },
36 | "numberOfInstances": {
37 | "type": "int",
38 | "defaultValue": 2,
39 | "metadata":{
40 | "description": "Number of instances the app service is scaled to. Check the maximum instances your plan can host at https://azure.microsoft.com/en-us/pricing/details/app-service"
41 | }
42 | },
43 | "siteLocation": {
44 | "type": "string",
45 | "defaultValue": "[resourceGroup().location]",
46 | "metadata":{
47 | "description": "Location for all resources."
48 | }
49 | },
50 | "appSecret": {
51 | "type": "securestring",
52 | "metadata":{
53 | "description": "Healthbot application secret."
54 | }
55 | },
56 | "webchatSecret": {
57 | "type": "securestring",
58 | "metadata":{
59 | "description": "Healthbot webchat secret."
60 | }
61 | },
62 | "repoUrl": {
63 | "type": "string",
64 | "defaultValue": "https://github.com/microsoft/HealthBotContainerSample.git",
65 | "metadata": {
66 | "description": "The URL for the GitHub repository that contains the project to deploy."
67 | }
68 | },
69 | "branch": {
70 | "type": "string",
71 | "defaultValue": "master",
72 | "metadata": {
73 | "description": "The branch of the GitHub repository to use."
74 | }
75 | }
76 | },
77 | "variables":{
78 | "alwaysOn": true,
79 | "skuCode": "[parameters('skuName')]",
80 | "numberOfWorkers": "[parameters('numberOfInstances')]",
81 | "linuxFxVersion": "NODE|lts",
82 | "hostingPlanNameLinux": "[concat('plan-linux-', parameters('siteName'))]",
83 | "hostingPlanNameWin": "[concat('plan-win-', parameters('siteName'))]",
84 | "kind": "[if(equals(parameters('operatingSystem'), 'windows'), 'app', 'linux')]",
85 | "linuxSiteName": "[if(equals(parameters('operatingSystem'), 'linux'), parameters('siteName'), 'app-na')]",
86 | "windowsSiteName": "[if(equals(parameters('operatingSystem'), 'windows'), parameters('siteName'), 'app-na')]",
87 | "WinSkuCode": "[parameters('skuName')]",
88 | "WinSku": "Standard",
89 | "workerSize": "0",
90 | "workerSizeId": "0",
91 | "hostingEnvironment": "",
92 | "nodeVersion": "~16",
93 | "currentStack": "node"
94 | },
95 | "resources": [
96 | {
97 | "apiVersion": "2018-02-01",
98 | "name": "[variables('linuxSiteName')]",
99 | "condition": "[equals(parameters('operatingSystem'),'linux')]",
100 | "type": "Microsoft.Web/sites",
101 | "location": "[parameters('siteLocation')]",
102 | "dependsOn": [
103 | "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanNameLinux'))]"
104 | ],
105 | "properties": {
106 | "name": "[variables('linuxSiteName')]",
107 | "siteConfig": {
108 | "linuxFxVersion": "[variables('linuxFxVersion')]",
109 | "alwaysOn": "[variables('alwaysOn')]",
110 | "appSettings": [
111 | {
112 | "name": "APP_SECRET",
113 | "value": "[parameters('appSecret')]"
114 | },
115 | {
116 | "name": "WEBCHAT_SECRET",
117 | "value": "[parameters('webchatSecret')]"
118 | }
119 | ]
120 | },
121 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanNameLinux'))]",
122 | "clientAffinityEnabled": false
123 | },
124 | "resources": [
125 | {
126 | "type": "sourcecontrols",
127 | "condition": "[equals(parameters('operatingSystem'),'linux')]",
128 | "apiVersion": "2018-02-01",
129 | "name": "web",
130 | "location": "[parameters('siteLocation')]",
131 | "dependsOn": [
132 | "[resourceId('Microsoft.Web/sites', variables('linuxSiteName'))]"
133 | ],
134 | "properties": {
135 | "repoUrl": "[parameters('repoURL')]",
136 | "branch": "[parameters('branch')]",
137 | "isManualIntegration": true
138 | }
139 | }
140 | ]
141 | },
142 | {
143 | "apiVersion": "2018-02-01",
144 | "condition": "[equals(parameters('operatingSystem'),'linux')]",
145 | "name": "[variables('hostingPlanNameLinux')]",
146 | "type": "Microsoft.Web/serverfarms",
147 | "location": "[parameters('siteLocation')]",
148 | "kind": "linux",
149 | "sku": {
150 | "Name": "[variables('skuCode')]"
151 | },
152 | "properties": {
153 | "name": "[variables('hostingPlanNameLinux')]",
154 | "numberOfWorkers": "[variables('numberOfWorkers')]",
155 | "reserved": true
156 | }
157 | },
158 | {
159 | "apiVersion": "2018-11-01",
160 | "condition": "[equals(parameters('operatingSystem'),'windows')]",
161 | "name": "[variables('windowsSiteName')]",
162 | "type": "Microsoft.Web/sites",
163 | "location": "[parameters('siteLocation')]",
164 | "tags": null,
165 | "dependsOn": [
166 | "[concat('Microsoft.Web/serverfarms/', variables('hostingPlanNameWin'))]"
167 | ],
168 | "properties": {
169 | "name": "[variables('windowsSiteName')]",
170 | "siteConfig": {
171 | "appSettings": [
172 | {
173 | "name": "APP_SECRET",
174 | "value": "[parameters('appSecret')]"
175 | },
176 | {
177 | "name": "WEBCHAT_SECRET",
178 | "value": "[parameters('webchatSecret')]"
179 | },
180 | {
181 | "name": "WEBSITE_NODE_DEFAULT_VERSION",
182 | "value": "[variables('nodeVersion')]"
183 | }
184 | ],
185 | "metadata": [
186 | {
187 | "name": "CURRENT_STACK",
188 | "value": "[variables('currentStack')]"
189 | }
190 | ],
191 | "nodeVersion": "[variables('nodeVersion')]",
192 | "alwaysOn": "[variables('alwaysOn')]"
193 | },
194 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanNameWin'))]",
195 | "hostingEnvironment": "[variables('hostingEnvironment')]",
196 | "clientAffinityEnabled": true
197 | },
198 | "resources": [
199 | {
200 | "type": "sourcecontrols",
201 | "condition": "[equals(parameters('operatingSystem'),'windows')]",
202 | "apiVersion": "2018-11-01",
203 | "name": "web",
204 | "location": "[parameters('siteLocation')]",
205 | "dependsOn": [
206 | "[resourceId('Microsoft.Web/sites', variables('windowsSiteName'))]"
207 | ],
208 | "properties": {
209 | "repoUrl": "[parameters('repoURL')]",
210 | "branch": "[parameters('branch')]",
211 | "isManualIntegration": true
212 | }
213 | }
214 | ]
215 | },
216 | {
217 | "apiVersion": "2018-11-01",
218 | "name": "[variables('hostingPlanNameWin')]",
219 | "condition": "[equals(parameters('operatingSystem'),'windows')]",
220 | "type": "Microsoft.Web/serverfarms",
221 | "location": "[parameters('siteLocation')]",
222 | "kind": "",
223 | "tags": null,
224 | "dependsOn": [],
225 | "properties": {
226 | "name": "[variables('hostingPlanNameWin')]",
227 | "workerSize": "[variables('workerSize')]",
228 | "workerSizeId": "[variables('workerSizeId')]",
229 | "numberOfWorkers": "[variables('numberOfWorkers')]",
230 | "hostingEnvironment": "[variables('hostingEnvironment')]"
231 | },
232 | "sku": {
233 | "Tier": "[variables('WinSku')]",
234 | "Name": "[variables('WinSkuCode')]"
235 | }
236 | }
237 | ]
238 | }
239 |
--------------------------------------------------------------------------------
/dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:latest
2 |
3 | # Create app directory
4 | WORKDIR /usr/src/app
5 |
6 | # Install app dependencies
7 | # A wildcard is used to ensure both package.json AND package-lock.json are copied
8 | # where available (npm@5+)
9 | COPY package*.json ./
10 |
11 | RUN npm install
12 | # If you are building your code for production
13 | # RUN npm install --only=production
14 |
15 | # Bundle app source
16 | COPY . .
17 |
18 | # Delete the web.config file, only needed for IIS
19 | RUN rm ./Web.config
20 |
21 | EXPOSE 8080
22 | CMD [ "npm", "start" ]
23 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "healthbot-container",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "healthbot-container",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "cookie-parser": "^1.4.5",
13 | "dotenv": "^8.2.0",
14 | "express": "^4.17.1",
15 | "jsonwebtoken": "^8.5.1",
16 | "node-fetch": "^2.6.7"
17 | },
18 | "devDependencies": {}
19 | },
20 | "node_modules/accepts": {
21 | "version": "1.3.8",
22 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
23 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
24 | "dependencies": {
25 | "mime-types": "~2.1.34",
26 | "negotiator": "0.6.3"
27 | },
28 | "engines": {
29 | "node": ">= 0.6"
30 | }
31 | },
32 | "node_modules/array-flatten": {
33 | "version": "1.1.1",
34 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
35 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
36 | },
37 | "node_modules/body-parser": {
38 | "version": "1.19.2",
39 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
40 | "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
41 | "dependencies": {
42 | "bytes": "3.1.2",
43 | "content-type": "~1.0.4",
44 | "debug": "2.6.9",
45 | "depd": "~1.1.2",
46 | "http-errors": "1.8.1",
47 | "iconv-lite": "0.4.24",
48 | "on-finished": "~2.3.0",
49 | "qs": "6.9.7",
50 | "raw-body": "2.4.3",
51 | "type-is": "~1.6.18"
52 | },
53 | "engines": {
54 | "node": ">= 0.8"
55 | }
56 | },
57 | "node_modules/buffer-equal-constant-time": {
58 | "version": "1.0.1",
59 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
60 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
61 | },
62 | "node_modules/bytes": {
63 | "version": "3.1.2",
64 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
65 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
66 | "engines": {
67 | "node": ">= 0.8"
68 | }
69 | },
70 | "node_modules/content-disposition": {
71 | "version": "0.5.4",
72 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
73 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
74 | "dependencies": {
75 | "safe-buffer": "5.2.1"
76 | },
77 | "engines": {
78 | "node": ">= 0.6"
79 | }
80 | },
81 | "node_modules/content-type": {
82 | "version": "1.0.4",
83 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
84 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
85 | "engines": {
86 | "node": ">= 0.6"
87 | }
88 | },
89 | "node_modules/cookie": {
90 | "version": "0.4.1",
91 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
92 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
93 | "engines": {
94 | "node": ">= 0.6"
95 | }
96 | },
97 | "node_modules/cookie-parser": {
98 | "version": "1.4.6",
99 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
100 | "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
101 | "dependencies": {
102 | "cookie": "0.4.1",
103 | "cookie-signature": "1.0.6"
104 | },
105 | "engines": {
106 | "node": ">= 0.8.0"
107 | }
108 | },
109 | "node_modules/cookie-signature": {
110 | "version": "1.0.6",
111 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
112 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
113 | },
114 | "node_modules/debug": {
115 | "version": "2.6.9",
116 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
117 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
118 | "dependencies": {
119 | "ms": "2.0.0"
120 | }
121 | },
122 | "node_modules/depd": {
123 | "version": "1.1.2",
124 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
125 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
126 | "engines": {
127 | "node": ">= 0.6"
128 | }
129 | },
130 | "node_modules/destroy": {
131 | "version": "1.0.4",
132 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
133 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
134 | },
135 | "node_modules/dotenv": {
136 | "version": "8.6.0",
137 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
138 | "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
139 | "engines": {
140 | "node": ">=10"
141 | }
142 | },
143 | "node_modules/ecdsa-sig-formatter": {
144 | "version": "1.0.11",
145 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
146 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
147 | "dependencies": {
148 | "safe-buffer": "^5.0.1"
149 | }
150 | },
151 | "node_modules/ee-first": {
152 | "version": "1.1.1",
153 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
154 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
155 | },
156 | "node_modules/encodeurl": {
157 | "version": "1.0.2",
158 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
159 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
160 | "engines": {
161 | "node": ">= 0.8"
162 | }
163 | },
164 | "node_modules/escape-html": {
165 | "version": "1.0.3",
166 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
167 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
168 | },
169 | "node_modules/etag": {
170 | "version": "1.8.1",
171 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
172 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
173 | "engines": {
174 | "node": ">= 0.6"
175 | }
176 | },
177 | "node_modules/express": {
178 | "version": "4.17.3",
179 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
180 | "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
181 | "dependencies": {
182 | "accepts": "~1.3.8",
183 | "array-flatten": "1.1.1",
184 | "body-parser": "1.19.2",
185 | "content-disposition": "0.5.4",
186 | "content-type": "~1.0.4",
187 | "cookie": "0.4.2",
188 | "cookie-signature": "1.0.6",
189 | "debug": "2.6.9",
190 | "depd": "~1.1.2",
191 | "encodeurl": "~1.0.2",
192 | "escape-html": "~1.0.3",
193 | "etag": "~1.8.1",
194 | "finalhandler": "~1.1.2",
195 | "fresh": "0.5.2",
196 | "merge-descriptors": "1.0.1",
197 | "methods": "~1.1.2",
198 | "on-finished": "~2.3.0",
199 | "parseurl": "~1.3.3",
200 | "path-to-regexp": "0.1.7",
201 | "proxy-addr": "~2.0.7",
202 | "qs": "6.9.7",
203 | "range-parser": "~1.2.1",
204 | "safe-buffer": "5.2.1",
205 | "send": "0.17.2",
206 | "serve-static": "1.14.2",
207 | "setprototypeof": "1.2.0",
208 | "statuses": "~1.5.0",
209 | "type-is": "~1.6.18",
210 | "utils-merge": "1.0.1",
211 | "vary": "~1.1.2"
212 | },
213 | "engines": {
214 | "node": ">= 0.10.0"
215 | }
216 | },
217 | "node_modules/express/node_modules/cookie": {
218 | "version": "0.4.2",
219 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
220 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
221 | "engines": {
222 | "node": ">= 0.6"
223 | }
224 | },
225 | "node_modules/finalhandler": {
226 | "version": "1.1.2",
227 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
228 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
229 | "dependencies": {
230 | "debug": "2.6.9",
231 | "encodeurl": "~1.0.2",
232 | "escape-html": "~1.0.3",
233 | "on-finished": "~2.3.0",
234 | "parseurl": "~1.3.3",
235 | "statuses": "~1.5.0",
236 | "unpipe": "~1.0.0"
237 | },
238 | "engines": {
239 | "node": ">= 0.8"
240 | }
241 | },
242 | "node_modules/forwarded": {
243 | "version": "0.2.0",
244 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
245 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
246 | "engines": {
247 | "node": ">= 0.6"
248 | }
249 | },
250 | "node_modules/fresh": {
251 | "version": "0.5.2",
252 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
253 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
254 | "engines": {
255 | "node": ">= 0.6"
256 | }
257 | },
258 | "node_modules/http-errors": {
259 | "version": "1.8.1",
260 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
261 | "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
262 | "dependencies": {
263 | "depd": "~1.1.2",
264 | "inherits": "2.0.4",
265 | "setprototypeof": "1.2.0",
266 | "statuses": ">= 1.5.0 < 2",
267 | "toidentifier": "1.0.1"
268 | },
269 | "engines": {
270 | "node": ">= 0.6"
271 | }
272 | },
273 | "node_modules/iconv-lite": {
274 | "version": "0.4.24",
275 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
276 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
277 | "dependencies": {
278 | "safer-buffer": ">= 2.1.2 < 3"
279 | },
280 | "engines": {
281 | "node": ">=0.10.0"
282 | }
283 | },
284 | "node_modules/inherits": {
285 | "version": "2.0.4",
286 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
287 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
288 | },
289 | "node_modules/ipaddr.js": {
290 | "version": "1.9.1",
291 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
292 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
293 | "engines": {
294 | "node": ">= 0.10"
295 | }
296 | },
297 | "node_modules/jsonwebtoken": {
298 | "version": "8.5.1",
299 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
300 | "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
301 | "dependencies": {
302 | "jws": "^3.2.2",
303 | "lodash.includes": "^4.3.0",
304 | "lodash.isboolean": "^3.0.3",
305 | "lodash.isinteger": "^4.0.4",
306 | "lodash.isnumber": "^3.0.3",
307 | "lodash.isplainobject": "^4.0.6",
308 | "lodash.isstring": "^4.0.1",
309 | "lodash.once": "^4.0.0",
310 | "ms": "^2.1.1",
311 | "semver": "^5.6.0"
312 | },
313 | "engines": {
314 | "node": ">=4",
315 | "npm": ">=1.4.28"
316 | }
317 | },
318 | "node_modules/jsonwebtoken/node_modules/ms": {
319 | "version": "2.1.3",
320 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
321 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
322 | },
323 | "node_modules/jwa": {
324 | "version": "1.4.1",
325 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
326 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
327 | "dependencies": {
328 | "buffer-equal-constant-time": "1.0.1",
329 | "ecdsa-sig-formatter": "1.0.11",
330 | "safe-buffer": "^5.0.1"
331 | }
332 | },
333 | "node_modules/jws": {
334 | "version": "3.2.2",
335 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
336 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
337 | "dependencies": {
338 | "jwa": "^1.4.1",
339 | "safe-buffer": "^5.0.1"
340 | }
341 | },
342 | "node_modules/lodash.includes": {
343 | "version": "4.3.0",
344 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
345 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
346 | },
347 | "node_modules/lodash.isboolean": {
348 | "version": "3.0.3",
349 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
350 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
351 | },
352 | "node_modules/lodash.isinteger": {
353 | "version": "4.0.4",
354 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
355 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
356 | },
357 | "node_modules/lodash.isnumber": {
358 | "version": "3.0.3",
359 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
360 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
361 | },
362 | "node_modules/lodash.isplainobject": {
363 | "version": "4.0.6",
364 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
365 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
366 | },
367 | "node_modules/lodash.isstring": {
368 | "version": "4.0.1",
369 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
370 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
371 | },
372 | "node_modules/lodash.once": {
373 | "version": "4.1.1",
374 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
375 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
376 | },
377 | "node_modules/media-typer": {
378 | "version": "0.3.0",
379 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
380 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
381 | "engines": {
382 | "node": ">= 0.6"
383 | }
384 | },
385 | "node_modules/merge-descriptors": {
386 | "version": "1.0.1",
387 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
388 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
389 | },
390 | "node_modules/methods": {
391 | "version": "1.1.2",
392 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
393 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
394 | "engines": {
395 | "node": ">= 0.6"
396 | }
397 | },
398 | "node_modules/mime": {
399 | "version": "1.6.0",
400 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
401 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
402 | "bin": {
403 | "mime": "cli.js"
404 | },
405 | "engines": {
406 | "node": ">=4"
407 | }
408 | },
409 | "node_modules/mime-db": {
410 | "version": "1.51.0",
411 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
412 | "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
413 | "engines": {
414 | "node": ">= 0.6"
415 | }
416 | },
417 | "node_modules/mime-types": {
418 | "version": "2.1.34",
419 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
420 | "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
421 | "dependencies": {
422 | "mime-db": "1.51.0"
423 | },
424 | "engines": {
425 | "node": ">= 0.6"
426 | }
427 | },
428 | "node_modules/ms": {
429 | "version": "2.0.0",
430 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
431 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
432 | },
433 | "node_modules/negotiator": {
434 | "version": "0.6.3",
435 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
436 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
437 | "engines": {
438 | "node": ">= 0.6"
439 | }
440 | },
441 | "node_modules/node-fetch": {
442 | "version": "2.6.7",
443 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
444 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
445 | "dependencies": {
446 | "whatwg-url": "^5.0.0"
447 | },
448 | "engines": {
449 | "node": "4.x || >=6.0.0"
450 | },
451 | "peerDependencies": {
452 | "encoding": "^0.1.0"
453 | },
454 | "peerDependenciesMeta": {
455 | "encoding": {
456 | "optional": true
457 | }
458 | }
459 | },
460 | "node_modules/on-finished": {
461 | "version": "2.3.0",
462 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
463 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
464 | "dependencies": {
465 | "ee-first": "1.1.1"
466 | },
467 | "engines": {
468 | "node": ">= 0.8"
469 | }
470 | },
471 | "node_modules/parseurl": {
472 | "version": "1.3.3",
473 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
474 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
475 | "engines": {
476 | "node": ">= 0.8"
477 | }
478 | },
479 | "node_modules/path-to-regexp": {
480 | "version": "0.1.7",
481 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
482 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
483 | },
484 | "node_modules/proxy-addr": {
485 | "version": "2.0.7",
486 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
487 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
488 | "dependencies": {
489 | "forwarded": "0.2.0",
490 | "ipaddr.js": "1.9.1"
491 | },
492 | "engines": {
493 | "node": ">= 0.10"
494 | }
495 | },
496 | "node_modules/qs": {
497 | "version": "6.9.7",
498 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
499 | "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==",
500 | "engines": {
501 | "node": ">=0.6"
502 | },
503 | "funding": {
504 | "url": "https://github.com/sponsors/ljharb"
505 | }
506 | },
507 | "node_modules/range-parser": {
508 | "version": "1.2.1",
509 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
510 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
511 | "engines": {
512 | "node": ">= 0.6"
513 | }
514 | },
515 | "node_modules/raw-body": {
516 | "version": "2.4.3",
517 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
518 | "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
519 | "dependencies": {
520 | "bytes": "3.1.2",
521 | "http-errors": "1.8.1",
522 | "iconv-lite": "0.4.24",
523 | "unpipe": "1.0.0"
524 | },
525 | "engines": {
526 | "node": ">= 0.8"
527 | }
528 | },
529 | "node_modules/safe-buffer": {
530 | "version": "5.2.1",
531 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
532 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
533 | "funding": [
534 | {
535 | "type": "github",
536 | "url": "https://github.com/sponsors/feross"
537 | },
538 | {
539 | "type": "patreon",
540 | "url": "https://www.patreon.com/feross"
541 | },
542 | {
543 | "type": "consulting",
544 | "url": "https://feross.org/support"
545 | }
546 | ]
547 | },
548 | "node_modules/safer-buffer": {
549 | "version": "2.1.2",
550 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
551 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
552 | },
553 | "node_modules/semver": {
554 | "version": "5.7.1",
555 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
556 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
557 | "bin": {
558 | "semver": "bin/semver"
559 | }
560 | },
561 | "node_modules/send": {
562 | "version": "0.17.2",
563 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
564 | "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
565 | "dependencies": {
566 | "debug": "2.6.9",
567 | "depd": "~1.1.2",
568 | "destroy": "~1.0.4",
569 | "encodeurl": "~1.0.2",
570 | "escape-html": "~1.0.3",
571 | "etag": "~1.8.1",
572 | "fresh": "0.5.2",
573 | "http-errors": "1.8.1",
574 | "mime": "1.6.0",
575 | "ms": "2.1.3",
576 | "on-finished": "~2.3.0",
577 | "range-parser": "~1.2.1",
578 | "statuses": "~1.5.0"
579 | },
580 | "engines": {
581 | "node": ">= 0.8.0"
582 | }
583 | },
584 | "node_modules/send/node_modules/ms": {
585 | "version": "2.1.3",
586 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
587 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
588 | },
589 | "node_modules/serve-static": {
590 | "version": "1.14.2",
591 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
592 | "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
593 | "dependencies": {
594 | "encodeurl": "~1.0.2",
595 | "escape-html": "~1.0.3",
596 | "parseurl": "~1.3.3",
597 | "send": "0.17.2"
598 | },
599 | "engines": {
600 | "node": ">= 0.8.0"
601 | }
602 | },
603 | "node_modules/setprototypeof": {
604 | "version": "1.2.0",
605 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
606 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
607 | },
608 | "node_modules/statuses": {
609 | "version": "1.5.0",
610 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
611 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
612 | "engines": {
613 | "node": ">= 0.6"
614 | }
615 | },
616 | "node_modules/toidentifier": {
617 | "version": "1.0.1",
618 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
619 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
620 | "engines": {
621 | "node": ">=0.6"
622 | }
623 | },
624 | "node_modules/tr46": {
625 | "version": "0.0.3",
626 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
627 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
628 | },
629 | "node_modules/type-is": {
630 | "version": "1.6.18",
631 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
632 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
633 | "dependencies": {
634 | "media-typer": "0.3.0",
635 | "mime-types": "~2.1.24"
636 | },
637 | "engines": {
638 | "node": ">= 0.6"
639 | }
640 | },
641 | "node_modules/unpipe": {
642 | "version": "1.0.0",
643 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
644 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
645 | "engines": {
646 | "node": ">= 0.8"
647 | }
648 | },
649 | "node_modules/utils-merge": {
650 | "version": "1.0.1",
651 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
652 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
653 | "engines": {
654 | "node": ">= 0.4.0"
655 | }
656 | },
657 | "node_modules/vary": {
658 | "version": "1.1.2",
659 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
660 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
661 | "engines": {
662 | "node": ">= 0.8"
663 | }
664 | },
665 | "node_modules/webidl-conversions": {
666 | "version": "3.0.1",
667 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
668 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
669 | },
670 | "node_modules/whatwg-url": {
671 | "version": "5.0.0",
672 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
673 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
674 | "dependencies": {
675 | "tr46": "~0.0.3",
676 | "webidl-conversions": "^3.0.0"
677 | }
678 | }
679 | },
680 | "dependencies": {
681 | "accepts": {
682 | "version": "1.3.8",
683 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
684 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
685 | "requires": {
686 | "mime-types": "~2.1.34",
687 | "negotiator": "0.6.3"
688 | }
689 | },
690 | "array-flatten": {
691 | "version": "1.1.1",
692 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
693 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
694 | },
695 | "body-parser": {
696 | "version": "1.19.2",
697 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
698 | "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
699 | "requires": {
700 | "bytes": "3.1.2",
701 | "content-type": "~1.0.4",
702 | "debug": "2.6.9",
703 | "depd": "~1.1.2",
704 | "http-errors": "1.8.1",
705 | "iconv-lite": "0.4.24",
706 | "on-finished": "~2.3.0",
707 | "qs": "6.9.7",
708 | "raw-body": "2.4.3",
709 | "type-is": "~1.6.18"
710 | }
711 | },
712 | "buffer-equal-constant-time": {
713 | "version": "1.0.1",
714 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
715 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
716 | },
717 | "bytes": {
718 | "version": "3.1.2",
719 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
720 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
721 | },
722 | "content-disposition": {
723 | "version": "0.5.4",
724 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
725 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
726 | "requires": {
727 | "safe-buffer": "5.2.1"
728 | }
729 | },
730 | "content-type": {
731 | "version": "1.0.4",
732 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
733 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
734 | },
735 | "cookie": {
736 | "version": "0.4.1",
737 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
738 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
739 | },
740 | "cookie-parser": {
741 | "version": "1.4.6",
742 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
743 | "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
744 | "requires": {
745 | "cookie": "0.4.1",
746 | "cookie-signature": "1.0.6"
747 | }
748 | },
749 | "cookie-signature": {
750 | "version": "1.0.6",
751 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
752 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
753 | },
754 | "debug": {
755 | "version": "2.6.9",
756 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
757 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
758 | "requires": {
759 | "ms": "2.0.0"
760 | }
761 | },
762 | "depd": {
763 | "version": "1.1.2",
764 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
765 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
766 | },
767 | "destroy": {
768 | "version": "1.0.4",
769 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
770 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
771 | },
772 | "dotenv": {
773 | "version": "8.6.0",
774 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
775 | "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g=="
776 | },
777 | "ecdsa-sig-formatter": {
778 | "version": "1.0.11",
779 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
780 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
781 | "requires": {
782 | "safe-buffer": "^5.0.1"
783 | }
784 | },
785 | "ee-first": {
786 | "version": "1.1.1",
787 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
788 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
789 | },
790 | "encodeurl": {
791 | "version": "1.0.2",
792 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
793 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
794 | },
795 | "escape-html": {
796 | "version": "1.0.3",
797 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
798 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
799 | },
800 | "etag": {
801 | "version": "1.8.1",
802 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
803 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
804 | },
805 | "express": {
806 | "version": "4.17.3",
807 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
808 | "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
809 | "requires": {
810 | "accepts": "~1.3.8",
811 | "array-flatten": "1.1.1",
812 | "body-parser": "1.19.2",
813 | "content-disposition": "0.5.4",
814 | "content-type": "~1.0.4",
815 | "cookie": "0.4.2",
816 | "cookie-signature": "1.0.6",
817 | "debug": "2.6.9",
818 | "depd": "~1.1.2",
819 | "encodeurl": "~1.0.2",
820 | "escape-html": "~1.0.3",
821 | "etag": "~1.8.1",
822 | "finalhandler": "~1.1.2",
823 | "fresh": "0.5.2",
824 | "merge-descriptors": "1.0.1",
825 | "methods": "~1.1.2",
826 | "on-finished": "~2.3.0",
827 | "parseurl": "~1.3.3",
828 | "path-to-regexp": "0.1.7",
829 | "proxy-addr": "~2.0.7",
830 | "qs": "6.9.7",
831 | "range-parser": "~1.2.1",
832 | "safe-buffer": "5.2.1",
833 | "send": "0.17.2",
834 | "serve-static": "1.14.2",
835 | "setprototypeof": "1.2.0",
836 | "statuses": "~1.5.0",
837 | "type-is": "~1.6.18",
838 | "utils-merge": "1.0.1",
839 | "vary": "~1.1.2"
840 | },
841 | "dependencies": {
842 | "cookie": {
843 | "version": "0.4.2",
844 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
845 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
846 | }
847 | }
848 | },
849 | "finalhandler": {
850 | "version": "1.1.2",
851 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
852 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
853 | "requires": {
854 | "debug": "2.6.9",
855 | "encodeurl": "~1.0.2",
856 | "escape-html": "~1.0.3",
857 | "on-finished": "~2.3.0",
858 | "parseurl": "~1.3.3",
859 | "statuses": "~1.5.0",
860 | "unpipe": "~1.0.0"
861 | }
862 | },
863 | "forwarded": {
864 | "version": "0.2.0",
865 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
866 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
867 | },
868 | "fresh": {
869 | "version": "0.5.2",
870 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
871 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
872 | },
873 | "http-errors": {
874 | "version": "1.8.1",
875 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
876 | "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
877 | "requires": {
878 | "depd": "~1.1.2",
879 | "inherits": "2.0.4",
880 | "setprototypeof": "1.2.0",
881 | "statuses": ">= 1.5.0 < 2",
882 | "toidentifier": "1.0.1"
883 | }
884 | },
885 | "iconv-lite": {
886 | "version": "0.4.24",
887 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
888 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
889 | "requires": {
890 | "safer-buffer": ">= 2.1.2 < 3"
891 | }
892 | },
893 | "inherits": {
894 | "version": "2.0.4",
895 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
896 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
897 | },
898 | "ipaddr.js": {
899 | "version": "1.9.1",
900 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
901 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
902 | },
903 | "jsonwebtoken": {
904 | "version": "8.5.1",
905 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
906 | "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
907 | "requires": {
908 | "jws": "^3.2.2",
909 | "lodash.includes": "^4.3.0",
910 | "lodash.isboolean": "^3.0.3",
911 | "lodash.isinteger": "^4.0.4",
912 | "lodash.isnumber": "^3.0.3",
913 | "lodash.isplainobject": "^4.0.6",
914 | "lodash.isstring": "^4.0.1",
915 | "lodash.once": "^4.0.0",
916 | "ms": "^2.1.1",
917 | "semver": "^5.6.0"
918 | },
919 | "dependencies": {
920 | "ms": {
921 | "version": "2.1.3",
922 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
923 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
924 | }
925 | }
926 | },
927 | "jwa": {
928 | "version": "1.4.1",
929 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
930 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
931 | "requires": {
932 | "buffer-equal-constant-time": "1.0.1",
933 | "ecdsa-sig-formatter": "1.0.11",
934 | "safe-buffer": "^5.0.1"
935 | }
936 | },
937 | "jws": {
938 | "version": "3.2.2",
939 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
940 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
941 | "requires": {
942 | "jwa": "^1.4.1",
943 | "safe-buffer": "^5.0.1"
944 | }
945 | },
946 | "lodash.includes": {
947 | "version": "4.3.0",
948 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
949 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
950 | },
951 | "lodash.isboolean": {
952 | "version": "3.0.3",
953 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
954 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
955 | },
956 | "lodash.isinteger": {
957 | "version": "4.0.4",
958 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
959 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
960 | },
961 | "lodash.isnumber": {
962 | "version": "3.0.3",
963 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
964 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
965 | },
966 | "lodash.isplainobject": {
967 | "version": "4.0.6",
968 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
969 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
970 | },
971 | "lodash.isstring": {
972 | "version": "4.0.1",
973 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
974 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
975 | },
976 | "lodash.once": {
977 | "version": "4.1.1",
978 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
979 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
980 | },
981 | "media-typer": {
982 | "version": "0.3.0",
983 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
984 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
985 | },
986 | "merge-descriptors": {
987 | "version": "1.0.1",
988 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
989 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
990 | },
991 | "methods": {
992 | "version": "1.1.2",
993 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
994 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
995 | },
996 | "mime": {
997 | "version": "1.6.0",
998 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
999 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
1000 | },
1001 | "mime-db": {
1002 | "version": "1.51.0",
1003 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
1004 | "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
1005 | },
1006 | "mime-types": {
1007 | "version": "2.1.34",
1008 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
1009 | "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
1010 | "requires": {
1011 | "mime-db": "1.51.0"
1012 | }
1013 | },
1014 | "ms": {
1015 | "version": "2.0.0",
1016 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1017 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
1018 | },
1019 | "negotiator": {
1020 | "version": "0.6.3",
1021 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1022 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
1023 | },
1024 | "node-fetch": {
1025 | "version": "2.6.7",
1026 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
1027 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
1028 | "requires": {
1029 | "whatwg-url": "^5.0.0"
1030 | }
1031 | },
1032 | "on-finished": {
1033 | "version": "2.3.0",
1034 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
1035 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
1036 | "requires": {
1037 | "ee-first": "1.1.1"
1038 | }
1039 | },
1040 | "parseurl": {
1041 | "version": "1.3.3",
1042 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1043 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
1044 | },
1045 | "path-to-regexp": {
1046 | "version": "0.1.7",
1047 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
1048 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
1049 | },
1050 | "proxy-addr": {
1051 | "version": "2.0.7",
1052 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1053 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1054 | "requires": {
1055 | "forwarded": "0.2.0",
1056 | "ipaddr.js": "1.9.1"
1057 | }
1058 | },
1059 | "qs": {
1060 | "version": "6.9.7",
1061 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
1062 | "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw=="
1063 | },
1064 | "range-parser": {
1065 | "version": "1.2.1",
1066 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1067 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
1068 | },
1069 | "raw-body": {
1070 | "version": "2.4.3",
1071 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
1072 | "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
1073 | "requires": {
1074 | "bytes": "3.1.2",
1075 | "http-errors": "1.8.1",
1076 | "iconv-lite": "0.4.24",
1077 | "unpipe": "1.0.0"
1078 | }
1079 | },
1080 | "safe-buffer": {
1081 | "version": "5.2.1",
1082 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1083 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1084 | },
1085 | "safer-buffer": {
1086 | "version": "2.1.2",
1087 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1088 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1089 | },
1090 | "semver": {
1091 | "version": "5.7.1",
1092 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1093 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
1094 | },
1095 | "send": {
1096 | "version": "0.17.2",
1097 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
1098 | "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
1099 | "requires": {
1100 | "debug": "2.6.9",
1101 | "depd": "~1.1.2",
1102 | "destroy": "~1.0.4",
1103 | "encodeurl": "~1.0.2",
1104 | "escape-html": "~1.0.3",
1105 | "etag": "~1.8.1",
1106 | "fresh": "0.5.2",
1107 | "http-errors": "1.8.1",
1108 | "mime": "1.6.0",
1109 | "ms": "2.1.3",
1110 | "on-finished": "~2.3.0",
1111 | "range-parser": "~1.2.1",
1112 | "statuses": "~1.5.0"
1113 | },
1114 | "dependencies": {
1115 | "ms": {
1116 | "version": "2.1.3",
1117 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1118 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1119 | }
1120 | }
1121 | },
1122 | "serve-static": {
1123 | "version": "1.14.2",
1124 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
1125 | "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
1126 | "requires": {
1127 | "encodeurl": "~1.0.2",
1128 | "escape-html": "~1.0.3",
1129 | "parseurl": "~1.3.3",
1130 | "send": "0.17.2"
1131 | }
1132 | },
1133 | "setprototypeof": {
1134 | "version": "1.2.0",
1135 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1136 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1137 | },
1138 | "statuses": {
1139 | "version": "1.5.0",
1140 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
1141 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
1142 | },
1143 | "toidentifier": {
1144 | "version": "1.0.1",
1145 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1146 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
1147 | },
1148 | "tr46": {
1149 | "version": "0.0.3",
1150 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
1151 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
1152 | },
1153 | "type-is": {
1154 | "version": "1.6.18",
1155 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1156 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1157 | "requires": {
1158 | "media-typer": "0.3.0",
1159 | "mime-types": "~2.1.24"
1160 | }
1161 | },
1162 | "unpipe": {
1163 | "version": "1.0.0",
1164 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1165 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
1166 | },
1167 | "utils-merge": {
1168 | "version": "1.0.1",
1169 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1170 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
1171 | },
1172 | "vary": {
1173 | "version": "1.1.2",
1174 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1175 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
1176 | },
1177 | "webidl-conversions": {
1178 | "version": "3.0.1",
1179 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
1180 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
1181 | },
1182 | "whatwg-url": {
1183 | "version": "5.0.0",
1184 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
1185 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
1186 | "requires": {
1187 | "tr46": "~0.0.3",
1188 | "webidl-conversions": "^3.0.0"
1189 | }
1190 | }
1191 | }
1192 | }
1193 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "healthbot-container",
3 | "version": "1.0.0",
4 | "description": "A simple web page to handoff users to the Microsoft Health bot",
5 | "main": "server.js",
6 | "license": "MIT",
7 | "repository": "https://github.com/Microsoft/HealthBotContainerSample.git",
8 | "dependencies": {
9 | "dotenv": "^8.2.0",
10 | "cookie-parser": "^1.4.5",
11 | "express": "^4.17.1",
12 | "jsonwebtoken": "^8.5.1",
13 | "node-fetch": "^2.6.7"
14 | },
15 | "scripts": {
16 | "prestart": "npm install"
17 | },
18 | "devDependencies": {}
19 | }
20 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/public/index.js:
--------------------------------------------------------------------------------
1 | const defaultLocale = 'en-US';
2 |
3 | function requestChatBot(loc) {
4 | const params = new URLSearchParams(location.search);
5 | const oReq = new XMLHttpRequest();
6 | oReq.addEventListener("load", initBotConversation);
7 | var path = "/chatBot?locale=" + extractLocale(params.get('locale'));
8 |
9 | if (loc) {
10 | path += "&lat=" + loc.lat + "&long=" + loc.long;
11 | }
12 | if (params.has('userId')) {
13 | path += "&userId=" + params.get('userId');
14 | }
15 | if (params.has('userName')) {
16 | path += "&userName=" + params.get('userName');
17 | }
18 | oReq.open("POST", path);
19 | oReq.send();
20 | }
21 |
22 | function extractLocale(localeParam) {
23 | if (!localeParam) {
24 | return defaultLocale;
25 | }
26 | else if (localeParam === 'autodetect') {
27 | return navigator.language;
28 | }
29 | else {
30 | return localeParam;
31 | }
32 | }
33 |
34 | function chatRequested() {
35 | const params = new URLSearchParams(location.search);
36 | if (params.has('shareLocation')) {
37 | getUserLocation(requestChatBot);
38 | }
39 | else {
40 | requestChatBot();
41 | }
42 | }
43 |
44 | function getUserLocation(callback) {
45 | navigator.geolocation.getCurrentPosition(
46 | function(position) {
47 | var latitude = position.coords.latitude;
48 | var longitude = position.coords.longitude;
49 | var location = {
50 | lat: latitude,
51 | long: longitude
52 | }
53 | callback(location);
54 | },
55 | function(error) {
56 | // user declined to share location
57 | console.log("location error:" + error.message);
58 | callback();
59 | });
60 | }
61 |
62 | function initBotConversation() {
63 | if (this.status >= 400) {
64 | alert(this.statusText);
65 | return;
66 | }
67 | // extract the data from the JWT
68 | const jsonWebToken = this.response;
69 | const tokenPayload = JSON.parse(atob(jsonWebToken.split('.')[1]));
70 | const user = {
71 | id: tokenPayload.userId,
72 | name: tokenPayload.userName,
73 | locale: tokenPayload.locale
74 | };
75 | let domain = undefined;
76 | if (tokenPayload.directLineURI) {
77 | domain = "https://" + tokenPayload.directLineURI + "/v3/directline";
78 | }
79 | let location = undefined;
80 | if (tokenPayload.location) {
81 | location = tokenPayload.location;
82 | } else {
83 | // set default location if desired
84 | /*location = {
85 | lat: 44.86448450671394,
86 | long: -93.32597021107624
87 | }*/
88 | }
89 | var botConnection = window.WebChat.createDirectLine({
90 | token: tokenPayload.connectorToken,
91 | domain: domain
92 | });
93 | const styleOptions = {
94 | botAvatarImage: 'https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/logo_bot.svg?view=azure-bot-service-4.0',
95 | // botAvatarInitials: '',
96 | // userAvatarImage: '',
97 | hideSendBox: false, /* set to true to hide the send box from the view */
98 | botAvatarInitials: 'Bot',
99 | userAvatarInitials: 'You',
100 | backgroundColor: '#F8F8F8'
101 | };
102 |
103 | const store = window.WebChat.createStore({}, function(store) { return function(next) { return function(action) {
104 | if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
105 | store.dispatch({
106 | type: 'DIRECT_LINE/POST_ACTIVITY',
107 | meta: {method: 'keyboard'},
108 | payload: {
109 | activity: {
110 | type: "invoke",
111 | name: "InitConversation",
112 | locale: user.locale,
113 | value: {
114 | // must use for authenticated conversation.
115 | jsonWebToken: jsonWebToken,
116 |
117 | // Use the following activity to proactively invoke a bot scenario
118 | /*
119 | triggeredScenario: {
120 | trigger: "{scenario_id}",
121 | args: {
122 | location: location,
123 | myVar1: "{custom_arg_1}",
124 | myVar2: "{custom_arg_2}"
125 | }
126 | }
127 | */
128 | }
129 | }
130 | }
131 | });
132 |
133 | }
134 | else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
135 | if (action.payload && action.payload.activity && action.payload.activity.type === "event" && action.payload.activity.name === "ShareLocationEvent") {
136 | // share
137 | getUserLocation(function (location) {
138 | store.dispatch({
139 | type: 'WEB_CHAT/SEND_POST_BACK',
140 | payload: { value: JSON.stringify(location) }
141 | });
142 | });
143 | }
144 | }
145 | return next(action);
146 | }}});
147 | const webchatOptions = {
148 | directLine: botConnection,
149 | styleOptions: styleOptions,
150 | store: store,
151 | userID: user.id,
152 | username: user.name,
153 | locale: user.locale
154 | };
155 | startChat(user, webchatOptions);
156 | }
157 |
158 | function startChat(user, webchatOptions) {
159 | const botContainer = document.getElementById('webchat');
160 | window.WebChat.renderWebChat(webchatOptions, botContainer);
161 | }
162 |
--------------------------------------------------------------------------------
/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | }
4 | body {
5 | margin: 0;
6 | }
7 |
8 | #webchat {
9 | height: 100%;
10 | width: 100%;
11 | }
12 |
13 | #webchat[watermark="true"] [role="complementary"] ul[role="list"]::after {
14 | content: "Powered By ...";
15 | background: linear-gradient(rgba(248, 248, 248, 0), rgba(248, 248, 248, .63), #F8F8F8 40%);
16 | bottom: 0;
17 | right: 0;
18 | color: #707070;
19 | display: block;
20 | font-family: 'Segoe Semibold', Calibri, 'Helvetica Neue', Arial, sans-serif;
21 | font-size: 12px;
22 | padding: 15px 10px 10px;
23 | position: absolute;
24 | position: sticky;
25 | text-align: right;
26 | }
27 |
28 | #webchat[watermark="true"] .webchat__scrollToEndButton {
29 | bottom: 32px;
30 | left: 50%;
31 | right: unset;
32 | transform: translate(-50%, 0);
33 | }
34 |
--------------------------------------------------------------------------------
/secrets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/HealthBotContainerSample/0e2a40237e6808c83001cfd9236c670416b096df/secrets.png
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const crypto = require('crypto');
3 | const express = require("express");
4 | const path = require("path");
5 | const jwt = require("jsonwebtoken");
6 | const fetch = require('node-fetch');
7 | const cookieParser = require('cookie-parser');
8 | const WEBCHAT_SECRET = process.env.WEBCHAT_SECRET;
9 | const DIRECTLINE_ENDPOINT_URI = process.env.DIRECTLINE_ENDPOINT_URI;
10 | const APP_SECRET = process.env.APP_SECRET;
11 | const directLineTokenEp = `https://${DIRECTLINE_ENDPOINT_URI || "directline.botframework.com"}/v3/directline/tokens/generate`;
12 |
13 | // Initialize the web app instance,
14 | const app = express();
15 | app.use(cookieParser());
16 |
17 | let options = {};
18 | // uncomment the line below if you wish to allow only specific domains to embed this page as a frame
19 | //options = {setHeaders: (res, path, stat) => {res.set('Content-Security-Policy', 'frame-ancestors example.com')}};
20 | // Indicate which directory static resources
21 | // (e.g. stylesheets) should be served from.
22 | app.use(express.static(path.join(__dirname, "public"), options));
23 | // begin listening for requests.
24 | const port = process.env.PORT || 8080;
25 | const region = process.env.REGION || "Unknown";
26 |
27 | app.listen(port, function() {
28 | console.log("Express server listening on port " + port);
29 | });
30 |
31 | function isUserAuthenticated(){
32 | // add here the logic to verify the user is authenticated
33 | return true;
34 | }
35 |
36 | const appConfig = {
37 | isHealthy : false,
38 | options : {
39 | method: 'POST',
40 | headers: {
41 | 'Authorization': 'Bearer ' + WEBCHAT_SECRET
42 | }
43 | }
44 | };
45 |
46 | function healthResponse(res, statusCode, message) {
47 | res.status(statusCode).send({
48 | health: message,
49 | region: region
50 | });
51 | }
52 | function healthy(res) {
53 | healthResponse(res, 200, "Ok");
54 | }
55 |
56 | function unhealthy(res) {
57 | healthResponse(res, 503, "Unhealthy");
58 | }
59 |
60 | app.get('/health', async function(req, res){
61 | if (!appConfig.isHealthy) {
62 | try {
63 | const fetchResponse = await fetch(directLineTokenEp, appConfig.options);
64 | const parsedBody = await fetchResponse.json();
65 | appConfig.isHealthy = true;
66 | healthy(res);
67 | }
68 | catch (err) {
69 | unhealthy(res);
70 | }
71 | }
72 | else {
73 | healthy(res);
74 | }
75 | });
76 |
77 | app.post('/chatBot', async function(req, res) {
78 | if (!isUserAuthenticated()) {
79 | res.status(403).send();
80 | return;
81 | }
82 | try {
83 | const fetchResponse = await fetch(directLineTokenEp, appConfig.options);
84 | const parsedBody = await fetchResponse.json();
85 | var userid = req.query.userId || req.cookies.userid;
86 | if (!userid) {
87 | userid = crypto.randomBytes(4).toString('hex');
88 | res.cookie("userid", userid, { sameSite: "none", secure: true, httpOnly: true, expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1)) });
89 | }
90 |
91 | var response = {};
92 | response['userId'] = userid;
93 | response['userName'] = req.query.userName;
94 | response['locale'] = req.query.locale;
95 | response['connectorToken'] = parsedBody.token;
96 |
97 | /*
98 | //Add any additional attributes
99 | response['optionalAttributes'] = {age: 33};
100 | */
101 |
102 | if (req.query.lat && req.query.long) {
103 | response['location'] = {lat: req.query.lat, long: req.query.long};
104 | }
105 | response['directLineURI'] = DIRECTLINE_ENDPOINT_URI;
106 | const jwtToken = jwt.sign(response, APP_SECRET);
107 | res.send(jwtToken);
108 | }
109 | catch (err) {
110 | appConfig.isHealthy = false;
111 | res.status(err.statusCode).send();
112 | console.log("failed");
113 | }
114 | });
115 |
--------------------------------------------------------------------------------