From 377765985d1f40a52adca858d931c4ef292acf4e Mon Sep 17 00:00:00 2001 From: Ben Coleman Date: Fri, 7 Oct 2022 14:33:11 +0100 Subject: [PATCH] Update App Insights, track custom events (#28) --- README.md | 3 +- deploy/container-app.bicep | 20 +- deploy/kubernetes/aks-live.yaml | 6 +- deploy/kubernetes/app.sample.yaml | 2 +- deploy/readme.md | 3 +- src/graph.mjs | 36 +++ src/package-lock.json | 426 +++++++++++++++--------------- src/package.json | 8 +- src/routes/api.mjs | 10 +- src/routes/auth.mjs | 49 ++-- src/routes/metrics.mjs | 6 + src/server.mjs | 23 +- 12 files changed, 310 insertions(+), 282 deletions(-) create mode 100644 src/graph.mjs diff --git a/README.md b/README.md index faaafe5..37d2279 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ If running in an Azure Web App, all of these values can be injected as applicati | PORT | 3000 | Port the server will listen on | | TODO_MONGO_CONNSTR | _none_ | Connect to specified MongoDB instance, when set the todo feature will be enabled | | TODO_MONGO_DB | todoDb | Name of the database in MongoDB to use (optional) | -| APPLICATIONINSIGHTS_CONNECTION_STRING | _none_ | Enable Application Insights monitoring | +| APPINSIGHTS_CONNECTION_STRING | _none_ | Enable AZure Application Insights monitoring | | WEATHER_API_KEY | _none_ | OpenWeather API key. [Info here](https://openweathermap.org/api) | | AAD_APP_ID | _none_ | Client ID of app registered in Azure AD | | DISABLE_METRICS | _none_ | Set to truthy value if you want to switch off Prometheus metrics | @@ -179,6 +179,7 @@ See [deployment folder](./deploy) for deploying into Kubernetes with Helm or int # Updates +- Oct 2022 - Update App Insights, track custom events - Sept 2022 - Add Prometheus metrics - Aug 2022 - Switch to PKCE for auth & login flow - Nov 2021 - Replace DarkSky API with OpenWeather diff --git a/deploy/container-app.bicep b/deploy/container-app.bicep index cc9d4e6..4048a6a 100644 --- a/deploy/container-app.bicep +++ b/deploy/container-app.bicep @@ -15,15 +15,13 @@ param image string = 'ghcr.io/benc-uk/nodejs-demoapp:latest' param weatherApiKey string = '' @description('Optional feature: Enable Azure App Insights') -param appInsightsInstrumentationKey string = '' +param appInsightsConnString string = '' @description('Optional feature: Enable todo app with MongoDB') param todoMongoConnstr string = '' @description('Optional feature: Enable auth with Azure AD, client id') param aadAppId string = '' -@description('Optional feature: Enable auth with Azure AD, client secret') -param aadAppSecret string = '' // ===== Variables ============================================================ @@ -35,8 +33,8 @@ var environmentName = '${resourceGroup().name}-environment' resource logWorkspace 'Microsoft.OperationalInsights/workspaces@2020-08-01' = { location: location name: logWorkspaceName - properties:{ - sku:{ + properties: { + sku: { name: 'Free' } } @@ -46,13 +44,13 @@ resource kubeEnv 'Microsoft.Web/kubeEnvironments@2021-02-01' = { location: location name: environmentName kind: 'containerenvironment' - + properties: { type: 'Managed' appLogsConfiguration: { destination: 'log-analytics' logAnalyticsConfiguration: { - customerId: logWorkspace.properties.customerId + customerId: logWorkspace.properties.customerId sharedKey: logWorkspace.listKeys().primarySharedKey } } @@ -80,8 +78,8 @@ resource containerApp 'Microsoft.Web/containerApps@2021-03-01' = { value: weatherApiKey } { - name: 'APPINSIGHTS_INSTRUMENTATIONKEY' - value: appInsightsInstrumentationKey + name: 'APPINSIGHTS_CONNECTION_STRING' + value: appInsightsConnString } { name: 'TODO_MONGO_CONNSTR' @@ -91,10 +89,6 @@ resource containerApp 'Microsoft.Web/containerApps@2021-03-01' = { name: 'AAD_APP_ID' value: aadAppId } - { - name: 'AAD_APP_SECRET' - value: aadAppSecret - } ] } ] diff --git a/deploy/kubernetes/aks-live.yaml b/deploy/kubernetes/aks-live.yaml index ba1f5cc..69dc431 100644 --- a/deploy/kubernetes/aks-live.yaml +++ b/deploy/kubernetes/aks-live.yaml @@ -15,7 +15,7 @@ secretEnv: env: AAD_APP_ID: 129e29d2-6c0a-4dbf-849e-320a3aa93d52 - APPLICATIONINSIGHTS_CONNECTION_STRING: "InstrumentationKey=76ae0e4d-5b1f-4081-915a-34cd49c8c4c2;IngestionEndpoint=https://uksouth-1.in.applicationinsights.azure.com/;LiveEndpoint=https://uksouth.livediagnostics.monitor.azure.com/" + APPINSIGHTS_CONNECTION_STRING: 'InstrumentationKey=76ae0e4d-5b1f-4081-915a-34cd49c8c4c2;IngestionEndpoint=https://uksouth-1.in.applicationinsights.azure.com/;LiveEndpoint=https://uksouth.livediagnostics.monitor.azure.com/' REDIS_SESSION_HOST: redis resources: @@ -35,3 +35,7 @@ ingress: tls: enabled: true secretName: benco-io-cert + +podAnnotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '3000' \ No newline at end of file diff --git a/deploy/kubernetes/app.sample.yaml b/deploy/kubernetes/app.sample.yaml index bc7a1f3..aa797b7 100644 --- a/deploy/kubernetes/app.sample.yaml +++ b/deploy/kubernetes/app.sample.yaml @@ -25,7 +25,7 @@ service: # secretName: nodejs-secrets # secretKey: mongoConnString # env: -# APPINSIGHTS_INSTRUMENTATIONKEY: __CHANGE_ME__ +# APPINSIGHTS_CONNECTION_STRING: __CHANGE_ME__ # AAD_APP_ID: __CHANGE_ME__ # TODO_MONGO_DB: __CHANGE_ME__ diff --git a/deploy/readme.md b/deploy/readme.md index 524418a..845c099 100644 --- a/deploy/readme.md +++ b/deploy/readme.md @@ -24,7 +24,6 @@ az deployment group create --template-file container-app.bicep --resource-group Optional deployment parameters, each one maps to an environment variable (see [main docs](../#configuration) for details): - **weatherApiKey** -- **appInsightsInstrumentationKey** +- **appInsightsConnString** - **todoMongoConnstr** - **aadAppId** -- **aadAppSecret** diff --git a/src/graph.mjs b/src/graph.mjs new file mode 100644 index 0000000..be68d02 --- /dev/null +++ b/src/graph.mjs @@ -0,0 +1,36 @@ +// +// Graph helper module, far more lightweight than the massive Graph SDK +// ------------------------------------------------------------------------- +// Ben C - Sept 2022 +// + +import axios from 'axios' + +export async function getUserDetails(accessToken) { + try { + const graphReq = { + url: 'https://graph.microsoft.com/v1.0/me', + headers: { Authorization: accessToken }, + } + + const resp = await axios(graphReq) + return resp.data + } catch (err) { + console.log(`### 💥 ERROR! Failed to get user details ${err.toString()}`) + } +} + +export async function getUserPhoto(accessToken) { + try { + const graphReq = { + url: 'https://graph.microsoft.com/v1.0/me/photo/$value', + responseType: 'arraybuffer', + headers: { Authorization: accessToken }, + } + + const resp = await axios(graphReq) + return new Buffer.from(resp.data, 'binary').toString('base64') + } catch (err) { + console.log(`### 💥 ERROR! Failed to get user photo ${err.toString()}`) + } +} diff --git a/src/package-lock.json b/src/package-lock.json index 46812b8..f0731dc 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,16 +1,16 @@ { "name": "nodejs-demoapp", - "version": "4.9.6", + "version": "4.9.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nodejs-demoapp", - "version": "4.9.6", + "version": "4.9.7", "license": "MIT", "dependencies": { - "@azure/msal-node": "^1.14.0", - "applicationinsights": "^2.3.4", + "@azure/msal-node": "^1.14.1", + "applicationinsights": "^2.3.5", "axios": "^0.27.2", "connect-redis": "^6.1.3", "cookie-parser": "^1.4.6", @@ -98,10 +98,11 @@ } }, "node_modules/@azure/core-util": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.1.0.tgz", - "integrity": "sha512-+i93lNJNA3Pl3KSuC6xKP2jTL4YFeDfO6VNOaYdk0cppZcLCxt811gS878VsqsCisaltdhl9lhMzK5kbxCiF4w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.1.1.tgz", + "integrity": "sha512-A4TBYVQCtHOigFb2ETiiKFDocBoI1Zk2Ui1KpI42aJSIDexF7DHQFpnjonltXAIU/ceH+1fsZAWWgvX6/AKzog==", "dependencies": { + "@azure/abort-controller": "^1.0.0", "tslib": "^2.2.0" }, "engines": { @@ -120,19 +121,19 @@ } }, "node_modules/@azure/msal-common": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.4.1.tgz", - "integrity": "sha512-zxcxg9pRdgGTS5mrRJeQvwA8aIjD8qSGzaAiz5SeTVkyhtjB0AeFnAcvBOKHv/TkswWNfYKpERxsXOAKXkXk0w==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.5.0.tgz", + "integrity": "sha512-W+SIsGSjkUAyDggA/6QVMKErttQ/8Bq9l/7ADr7GJwt9JFsc+XNBdQDsOsUvZ7YCVkZcSgzJw2MZJLIBqfQtQA==", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.0.tgz", - "integrity": "sha512-3XB7FuHLhmGBjw7bxuz1LCHOXQgmNIO3J56tlbOjuJcyJtd4aBCgnYIXNKLed3uRcQNHEO0mlg24I4iGxAV/UA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.1.tgz", + "integrity": "sha512-RftjLd35xlafh5cPT17zrzpYdcsbHKJal7R/FTbThpbetSk8y8vQHUzNwWNhBM6GFFiyMS4IQ+zs+z8bgJ4sKQ==", "dependencies": { - "@azure/msal-common": "^7.4.1", + "@azure/msal-common": "^7.5.0", "jsonwebtoken": "^8.5.1", "uuid": "^8.3.0" }, @@ -164,9 +165,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -255,11 +256,11 @@ } }, "node_modules/@opentelemetry/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.6.0.tgz", - "integrity": "sha512-MsEhsyCTfYme6frK8/AqEWwbS9SB3Ta5bjgz4jPQJjL7ijUM3JiLVvqh/kHo1UlUjbUbLmGG7jA5Nw4d7SMcLQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.7.0.tgz", + "integrity": "sha512-AVqAi5uc8DrKJBimCTFUT4iFI+5eXpo4sYmGbQ0CypG0piOTHE2g9c5aSoTGYXu3CzOmJZf7pT6Xh+nwm5d6yQ==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/semantic-conventions": "1.7.0" }, "engines": { "node": ">=14" @@ -269,12 +270,12 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.6.0.tgz", - "integrity": "sha512-07GlHuq72r2rnJugYVdGumviQvfrl8kEPidkZSVoseLVfIjV7nzxxt5/vqs9pK7JItWOrvjRdr/jTBVayFBr/w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.7.0.tgz", + "integrity": "sha512-u1M0yZotkjyKx8dj+46Sg5thwtOTBmtRieNXqdCRiWUp6SfFiIP0bI+1XK3LhuXqXkBXA1awJZaTqKduNMStRg==", "dependencies": { - "@opentelemetry/core": "1.6.0", - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/core": "1.7.0", + "@opentelemetry/semantic-conventions": "1.7.0" }, "engines": { "node": ">=14" @@ -284,13 +285,13 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.6.0.tgz", - "integrity": "sha512-yx/uuzHdT0QNRSEbCgXHc0GONk90uvaFcPGaNowIFSl85rTp4or4uIIMkG7R8ckj8xWjDSjsaztH6yQxoZrl5g==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.7.0.tgz", + "integrity": "sha512-Iz84C+FVOskmauh9FNnj4+VrA+hG5o+tkMzXuoesvSfunVSioXib0syVFeNXwOm4+M5GdWCuW632LVjqEXStIg==", "dependencies": { - "@opentelemetry/core": "1.6.0", - "@opentelemetry/resources": "1.6.0", - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/core": "1.7.0", + "@opentelemetry/resources": "1.7.0", + "@opentelemetry/semantic-conventions": "1.7.0" }, "engines": { "node": ">=14" @@ -300,9 +301,9 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.6.0.tgz", - "integrity": "sha512-aPfcBeLErM/PPiAuAbNFLN5sNbZLc3KZlar27uohllN8Zs6jJbHyJU1y7cMA6W/zuq+thkaG8mujiS+3iD/FWQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.7.0.tgz", + "integrity": "sha512-FGBx/Qd09lMaqQcogCHyYrFEpTx4cAjeS+48lMIR12z7LdH+zofGDVQSubN59nL6IpubfKqTeIDu9rNO28iHVA==", "engines": { "node": ">=14" } @@ -387,9 +388,9 @@ } }, "node_modules/@types/node": { - "version": "18.7.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz", - "integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==" + "version": "18.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", + "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==" }, "node_modules/@types/node-fetch": { "version": "2.6.2", @@ -542,9 +543,9 @@ } }, "node_modules/applicationinsights": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.3.4.tgz", - "integrity": "sha512-B/u2MepyV8r70NtG9nQ+7/MFog0j0P0tdEAz9coZGwNcW/T816ewROrre5QWBNyjYnsUB3dUF5OscGd0F0l2fA==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.3.5.tgz", + "integrity": "sha512-QU6EEZbobj9NL2o/XLIDStCMfwrrLwFrbJrDw9ih1wb5bz7v0cwUm6kPXiKtNAAny4hWp9/BtBhtFKvc3tWZ3w==", "dependencies": { "@azure/core-http": "^2.2.3", "@microsoft/applicationinsights-web-snippet": "^1.0.1", @@ -1324,9 +1325,9 @@ } }, "node_modules/dotenv": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", - "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", "engines": { "node": ">=12" } @@ -1417,13 +1418,13 @@ } }, "node_modules/eslint": { - "version": "8.23.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", - "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", + "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/config-array": "^0.10.5", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", @@ -3190,9 +3191,9 @@ } }, "node_modules/js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", "dev": true }, "node_modules/js-sha512": { @@ -3702,13 +3703,27 @@ "marge": "bin/cli.js" } }, + "node_modules/mochawesome-report-generator/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/mochawesome-report-generator/node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -3730,9 +3745,9 @@ } }, "node_modules/mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.10.0.tgz", + "integrity": "sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==", "dependencies": { "bson": "^4.7.0", "denque": "^2.1.0", @@ -3747,9 +3762,9 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", - "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.4.tgz", + "integrity": "sha512-SeAxuWs0ez3iI3vvmLk/j2y+zHwigTDKQhtdxTgt5ZCOQQS5+HW4g45/Xw5vzzbn7oQXCNQ24Z40AkJsizEy7w==", "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" @@ -3952,16 +3967,15 @@ "dev": true }, "node_modules/nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", "dev": true, - "hasInstallScript": true, "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", @@ -4722,20 +4736,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5082,9 +5082,9 @@ } }, "node_modules/socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dependencies": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -5168,15 +5168,6 @@ "bluebird": "^2.6.2" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5216,9 +5207,10 @@ } }, "node_modules/superagent": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz", - "integrity": "sha512-iudipXEel+SzlP9y29UBWGDjB+Zzag+eeA1iLosaR2YHBRr1Q1kC29iBrF2zIVD9fqVbpZnXkN/VJmwFMVyNWg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.2.tgz", + "integrity": "sha512-QtYZ9uaNAMexI7XWl2vAXAh0j4q9H7T0WVEI/y5qaUB3QLwxo+voUgCQ217AokJzUTIVOp0RTo7fhZrwhD7A2Q==", + "deprecated": "Please use v8.0.0 until https://github.com/visionmedia/superagent/issues/1743 is resolved", "dev": true, "dependencies": { "component-emitter": "^1.3.0", @@ -5229,8 +5221,7 @@ "formidable": "^2.0.1", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.10.3", - "readable-stream": "^3.6.0", + "qs": "^6.11.0", "semver": "^7.3.7" }, "engines": { @@ -5249,10 +5240,25 @@ "node": ">=4.0.0" } }, + "node_modules/superagent/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/superagent/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5265,9 +5271,9 @@ } }, "node_modules/supertest": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.2.4.tgz", - "integrity": "sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.0.tgz", + "integrity": "sha512-QgWju1cNoacP81Rv88NKkQ4oXTzGg0eNZtOoxp1ROpbS4OHY/eK5b8meShuFtdni161o5X0VQvgo7ErVyKK+Ow==", "dev": true, "dependencies": { "methods": "^1.1.2", @@ -5445,9 +5451,9 @@ } }, "node_modules/uglify-js": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", - "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==", + "version": "3.17.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.3.tgz", + "integrity": "sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==", "dev": true, "optional": true, "bin": { @@ -5523,12 +5529,6 @@ "node": ">=6.0.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -5821,10 +5821,11 @@ } }, "@azure/core-util": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.1.0.tgz", - "integrity": "sha512-+i93lNJNA3Pl3KSuC6xKP2jTL4YFeDfO6VNOaYdk0cppZcLCxt811gS878VsqsCisaltdhl9lhMzK5kbxCiF4w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.1.1.tgz", + "integrity": "sha512-A4TBYVQCtHOigFb2ETiiKFDocBoI1Zk2Ui1KpI42aJSIDexF7DHQFpnjonltXAIU/ceH+1fsZAWWgvX6/AKzog==", "requires": { + "@azure/abort-controller": "^1.0.0", "tslib": "^2.2.0" } }, @@ -5837,16 +5838,16 @@ } }, "@azure/msal-common": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.4.1.tgz", - "integrity": "sha512-zxcxg9pRdgGTS5mrRJeQvwA8aIjD8qSGzaAiz5SeTVkyhtjB0AeFnAcvBOKHv/TkswWNfYKpERxsXOAKXkXk0w==" + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.5.0.tgz", + "integrity": "sha512-W+SIsGSjkUAyDggA/6QVMKErttQ/8Bq9l/7ADr7GJwt9JFsc+XNBdQDsOsUvZ7YCVkZcSgzJw2MZJLIBqfQtQA==" }, "@azure/msal-node": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.0.tgz", - "integrity": "sha512-3XB7FuHLhmGBjw7bxuz1LCHOXQgmNIO3J56tlbOjuJcyJtd4aBCgnYIXNKLed3uRcQNHEO0mlg24I4iGxAV/UA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.1.tgz", + "integrity": "sha512-RftjLd35xlafh5cPT17zrzpYdcsbHKJal7R/FTbThpbetSk8y8vQHUzNwWNhBM6GFFiyMS4IQ+zs+z8bgJ4sKQ==", "requires": { - "@azure/msal-common": "^7.4.1", + "@azure/msal-common": "^7.5.0", "jsonwebtoken": "^8.5.1", "uuid": "^8.3.0" } @@ -5869,9 +5870,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -5934,36 +5935,36 @@ "integrity": "sha512-0nBr+VZNKm9tvNDZFstI3Pq1fCTEDK5OZTnVKNvBNAKgd0yIvmwsP4m61rEv7ZP+tOUjWJhROpxK5MsnlF911g==" }, "@opentelemetry/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.6.0.tgz", - "integrity": "sha512-MsEhsyCTfYme6frK8/AqEWwbS9SB3Ta5bjgz4jPQJjL7ijUM3JiLVvqh/kHo1UlUjbUbLmGG7jA5Nw4d7SMcLQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.7.0.tgz", + "integrity": "sha512-AVqAi5uc8DrKJBimCTFUT4iFI+5eXpo4sYmGbQ0CypG0piOTHE2g9c5aSoTGYXu3CzOmJZf7pT6Xh+nwm5d6yQ==", "requires": { - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/semantic-conventions": "1.7.0" } }, "@opentelemetry/resources": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.6.0.tgz", - "integrity": "sha512-07GlHuq72r2rnJugYVdGumviQvfrl8kEPidkZSVoseLVfIjV7nzxxt5/vqs9pK7JItWOrvjRdr/jTBVayFBr/w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.7.0.tgz", + "integrity": "sha512-u1M0yZotkjyKx8dj+46Sg5thwtOTBmtRieNXqdCRiWUp6SfFiIP0bI+1XK3LhuXqXkBXA1awJZaTqKduNMStRg==", "requires": { - "@opentelemetry/core": "1.6.0", - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/core": "1.7.0", + "@opentelemetry/semantic-conventions": "1.7.0" } }, "@opentelemetry/sdk-trace-base": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.6.0.tgz", - "integrity": "sha512-yx/uuzHdT0QNRSEbCgXHc0GONk90uvaFcPGaNowIFSl85rTp4or4uIIMkG7R8ckj8xWjDSjsaztH6yQxoZrl5g==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.7.0.tgz", + "integrity": "sha512-Iz84C+FVOskmauh9FNnj4+VrA+hG5o+tkMzXuoesvSfunVSioXib0syVFeNXwOm4+M5GdWCuW632LVjqEXStIg==", "requires": { - "@opentelemetry/core": "1.6.0", - "@opentelemetry/resources": "1.6.0", - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/core": "1.7.0", + "@opentelemetry/resources": "1.7.0", + "@opentelemetry/semantic-conventions": "1.7.0" } }, "@opentelemetry/semantic-conventions": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.6.0.tgz", - "integrity": "sha512-aPfcBeLErM/PPiAuAbNFLN5sNbZLc3KZlar27uohllN8Zs6jJbHyJU1y7cMA6W/zuq+thkaG8mujiS+3iD/FWQ==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.7.0.tgz", + "integrity": "sha512-FGBx/Qd09lMaqQcogCHyYrFEpTx4cAjeS+48lMIR12z7LdH+zofGDVQSubN59nL6IpubfKqTeIDu9rNO28iHVA==" }, "@postman/form-data": { "version": "3.1.1", @@ -6026,9 +6027,9 @@ "requires": {} }, "@types/node": { - "version": "18.7.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz", - "integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==" + "version": "18.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", + "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==" }, "@types/node-fetch": { "version": "2.6.2", @@ -6150,9 +6151,9 @@ } }, "applicationinsights": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.3.4.tgz", - "integrity": "sha512-B/u2MepyV8r70NtG9nQ+7/MFog0j0P0tdEAz9coZGwNcW/T816ewROrre5QWBNyjYnsUB3dUF5OscGd0F0l2fA==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.3.5.tgz", + "integrity": "sha512-QU6EEZbobj9NL2o/XLIDStCMfwrrLwFrbJrDw9ih1wb5bz7v0cwUm6kPXiKtNAAny4hWp9/BtBhtFKvc3tWZ3w==", "requires": { "@azure/core-http": "^2.2.3", "@microsoft/applicationinsights-web-snippet": "^1.0.1", @@ -6742,9 +6743,9 @@ } }, "dotenv": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", - "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==" + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, "ecc-jsbn": { "version": "0.1.2", @@ -6814,13 +6815,13 @@ "dev": true }, "eslint": { - "version": "8.23.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", - "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", + "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/config-array": "^0.10.5", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", @@ -8156,9 +8157,9 @@ } }, "js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", "dev": true }, "js-sha512": { @@ -8575,13 +8576,24 @@ "yargs": "^17.2.1" }, "dependencies": { + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -8599,9 +8611,9 @@ } }, "mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.10.0.tgz", + "integrity": "sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==", "requires": { "bson": "^4.7.0", "denque": "^2.1.0", @@ -8611,9 +8623,9 @@ } }, "mongodb-connection-string-url": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", - "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.4.tgz", + "integrity": "sha512-SeAxuWs0ez3iI3vvmLk/j2y+zHwigTDKQhtdxTgt5ZCOQQS5+HW4g45/Xw5vzzbn7oQXCNQ24Z40AkJsizEy7w==", "requires": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" @@ -8781,15 +8793,15 @@ "dev": true }, "nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", "dev": true, "requires": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", @@ -9341,17 +9353,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -9611,9 +9612,9 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "requires": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -9676,15 +9677,6 @@ "bluebird": "^2.6.2" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -9712,9 +9704,9 @@ "dev": true }, "superagent": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz", - "integrity": "sha512-iudipXEel+SzlP9y29UBWGDjB+Zzag+eeA1iLosaR2YHBRr1Q1kC29iBrF2zIVD9fqVbpZnXkN/VJmwFMVyNWg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.2.tgz", + "integrity": "sha512-QtYZ9uaNAMexI7XWl2vAXAh0j4q9H7T0WVEI/y5qaUB3QLwxo+voUgCQ217AokJzUTIVOp0RTo7fhZrwhD7A2Q==", "dev": true, "requires": { "component-emitter": "^1.3.0", @@ -9725,8 +9717,7 @@ "formidable": "^2.0.1", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.10.3", - "readable-stream": "^3.6.0", + "qs": "^6.11.0", "semver": "^7.3.7" }, "dependencies": { @@ -9736,10 +9727,19 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -9748,9 +9748,9 @@ } }, "supertest": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.2.4.tgz", - "integrity": "sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.0.tgz", + "integrity": "sha512-QgWju1cNoacP81Rv88NKkQ4oXTzGg0eNZtOoxp1ROpbS4OHY/eK5b8meShuFtdni161o5X0VQvgo7ErVyKK+Ow==", "dev": true, "requires": { "methods": "^1.1.2", @@ -9891,9 +9891,9 @@ } }, "uglify-js": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", - "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==", + "version": "3.17.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.3.tgz", + "integrity": "sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==", "dev": true, "optional": true }, @@ -9951,12 +9951,6 @@ "resolved": "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.2.0.tgz", "integrity": "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==" }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/src/package.json b/src/package.json index 15ee09b..e772ad1 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "nodejs-demoapp", "description": "Node.js Express app for demos", - "version": "4.9.6", + "version": "4.9.7", "author": "Ben Coleman", "engines": { "node": ">=16.0.0" @@ -15,7 +15,7 @@ "scripts": { "start": "node --expose_gc server.mjs", "start-bg": "node server.mjs &", - "watch": "nodemon --experimental-modules", + "watch": "nodemon --trace-deprecation --experimental-modules", "test-report": "mocha --reporter mochawesome --exit ./tests > test-results.json", "test": "mocha --exit ./tests", "test-postman": "newman run tests/postman_collection.json --timeout 60000 --env-var apphost=$TEST_HOST", @@ -23,8 +23,8 @@ "lint-fix": "eslint . --ext mjs --fix && prettier --write **/*.mjs" }, "dependencies": { - "@azure/msal-node": "^1.14.0", - "applicationinsights": "^2.3.4", + "@azure/msal-node": "^1.14.1", + "applicationinsights": "^2.3.5", "axios": "^0.27.2", "connect-redis": "^6.1.3", "cookie-parser": "^1.4.6", diff --git a/src/routes/api.mjs b/src/routes/api.mjs index f31fcb8..ec13131 100644 --- a/src/routes/api.mjs +++ b/src/routes/api.mjs @@ -19,15 +19,21 @@ router.get('/api/weather/:lat/:long', async function (req, res, next) { const long = req.params.long const lat = req.params.lat - // Call OpenWeather API try { + // Call external OpenWeather API const weatherResp = await axios.get( `https://api.openweathermap.org/data/2.5/weather?units=metric&lat=${lat}&lon=${long}&appid=${WEATHER_API_KEY}` ) if (weatherResp.data) { + // Send custom metric over to App Insights - 'weatherTemp' with the temperature if (appInsights.defaultClient && weatherResp.data.main) { - appInsights.defaultClient.trackMetric({ name: 'weatherTemp', value: weatherResp.data.main.temp }) + appInsights.defaultClient.trackMetric({ + name: 'weatherTemp', + value: weatherResp.data.main.temp, + // Extra meta data + properties: { city: weatherResp.data.name, country: weatherResp.data.sys.country }, + }) } // Proxy the OpenWeather response through to the caller diff --git a/src/routes/auth.mjs b/src/routes/auth.mjs index 9c08757..01267b7 100644 --- a/src/routes/auth.mjs +++ b/src/routes/auth.mjs @@ -6,8 +6,10 @@ import express from 'express' const router = express.Router() -import axios from 'axios' import msal from '@azure/msal-node' +import appInsights from 'applicationinsights' + +import { getUserDetails, getUserPhoto } from '../graph.mjs' // For reasons we need to do this here as well import { config as dotenvConfig } from 'dotenv' @@ -120,6 +122,16 @@ router.get(`/${AUTH_CALLBACK_PATH}`, async (req, res) => { accessToken: tokenResponse.accessToken, } + // Track user login as an App Insights custom event + appInsights.defaultClient.trackEvent({ + name: 'userLogin', + properties: { + user: tokenResponse.account.username, + tenantId: tokenResponse.account.tenantId, + userId: tokenResponse.uniqueId, + }, + }) + res.redirect('/account') } catch (err) { res.render('error', { @@ -137,10 +149,12 @@ router.get('/logout', function (req, res) { }) router.get('/account', async function (req, res) { + // Protect this route by checking if user is logged in if (!req.session.user) { res.redirect('/login') return } + let details = {} let photo = null @@ -159,37 +173,4 @@ router.get('/account', async function (req, res) { }) }) -// ============================== -// MS Graph calls -// ============================== - -async function getUserDetails(accessToken) { - try { - const graphReq = { - url: 'https://graph.microsoft.com/v1.0/me', - headers: { Authorization: accessToken }, - } - - const resp = await axios(graphReq) - return resp.data - } catch (err) { - console.log(`### 💥 ERROR! Failed to get user details ${err.toString()}`) - } -} - -async function getUserPhoto(accessToken) { - try { - const graphReq = { - url: 'https://graph.microsoft.com/v1.0/me/photo/$value', - responseType: 'arraybuffer', - headers: { Authorization: accessToken }, - } - - const resp = await axios(graphReq) - return new Buffer.from(resp.data, 'binary').toString('base64') - } catch (err) { - console.log(`### 💥 ERROR! Failed to get user photo ${err.toString()}`) - } -} - export default router diff --git a/src/routes/metrics.mjs b/src/routes/metrics.mjs index e02cf1b..8e35303 100644 --- a/src/routes/metrics.mjs +++ b/src/routes/metrics.mjs @@ -7,11 +7,17 @@ import PromMiddleware from 'express-prometheus-middleware' +// Add metrics to the app +// We can't use app.use() here due to how the metrics middleware wants to be registered export default function addMetrics(app) { app.use( PromMiddleware({ metricsPath: '/metrics', + + // Standard NodeJS runtime metrics collectDefaultMetrics: true, + + // HTTP request metrics requestDurationBuckets: [0.1, 0.5, 1, 1.5], requestLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400], responseLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400], diff --git a/src/server.mjs b/src/server.mjs index 5ad6ec5..176b349 100644 --- a/src/server.mjs +++ b/src/server.mjs @@ -4,7 +4,8 @@ // Ben C, Oct 2017 - Updated: Sept 2022 // -console.log('### 🚀 Node.js demo app starting...') +const packageJson = JSON.parse(readFileSync(new URL('./package.json', import.meta.url))) +console.log(`### 🚀 Node.js demo app v${packageJson.version} starting...`) // Dotenv handy for local config & debugging import { config as dotenvConfig } from 'dotenv' @@ -12,11 +13,11 @@ dotenvConfig() import appInsights from 'applicationinsights' -// App Insights. -// Enable by setting APPLICATIONINSIGHTS_CONNECTION_STRING env var -if (process.env.APPLICATIONINSIGHTS_CONNECTION_STRING) { - appInsights.setup(process.env.APPLICATIONINSIGHTS_CONNECTION_STRING).setSendLiveMetrics(true).start() - appInsights.start() +// Configure App Insights +// Enable by setting APPINSIGHTS_CONNECTION_STRING environmental var +if (process.env.APPINSIGHTS_CONNECTION_STRING) { + appInsights.setup(process.env.APPINSIGHTS_CONNECTION_STRING).setSendLiveMetrics(true).start() + console.log('### 🩺 Azure App Insights enabled') } @@ -28,7 +29,6 @@ import session from 'express-session' import { createClient as createRedisClient } from 'redis' import connectRedis from 'connect-redis' import { readFileSync } from 'fs' -const packageJson = JSON.parse(readFileSync(new URL('./package.json', import.meta.url))) const app = new express() @@ -64,7 +64,14 @@ app.use(session(sessionConfig)) // Request logging, switch off when running tests if (process.env.NODE_ENV !== 'test') { - app.use(logger('dev')) + app.use( + logger('dev', { + skip: function (req, res) { + // Don't log the signin code PKCE redirect + return req.path.indexOf('/signin') == 0 + }, + }) + ) } // Parsing middleware