diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..09818d6a Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index b38db2f2..f49121c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ node_modules/ build/ +env/ + +config/*.yml +!config/test.yml + +.DS_Store diff --git a/.vscode/launch.json b/.vscode/launch.json index 2c51910c..7b579349 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,6 +12,12 @@ "runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"], "args": ["src/index.ts"], + "env": {}, + + "resolveSourceMapLocations": [ + "${workspaceFolder}/**", + "!**/node_modules/**" + ], "cwd": "${workspaceRoot}", "internalConsoleOptions": "openOnSessionStart", diff --git a/@types/express/index.d.ts b/@types/express/index.d.ts index 8354d6db..65bef3a2 100644 --- a/@types/express/index.d.ts +++ b/@types/express/index.d.ts @@ -1,10 +1,10 @@ -import User from '../../src/model/users.model' - +import { AccessToken, RefreshToken } from 'devu-shared-modules' declare global { namespace Express { interface Request { - user?: User - users?: User[] + // Auth Data + currentUser?: AccessToken // Deserialized access token + refreshUser?: RefreshToken // Deserialized refresh token } } } diff --git a/README.md b/README.md index bb6013fd..1738a4ac 100644 --- a/README.md +++ b/README.md @@ -37,13 +37,19 @@ Run the initial migrations to setup our DB schema npm run typeorm -- migration:run ``` +Run the setup script to create local development auth keys. These are used in local development for signing and authenticating JWTs. + +``` +npm run generate-config +``` + Once you've got all the dependencies installed you can run the project via ``` npm start ``` -By defualt the project runs at `localhost:3001`, but you can change the port by setting an alternate port by setting the `PORT` environment variable. +By default the project runs at `localhost:3001`, but you can change the port by setting an alternate port by setting the `PORT` environment variable. If you're working in vscode, a configuration has been included to allow for debugging. Open up the VS Code Run and Debug section and click `Debug API`. @@ -67,6 +73,10 @@ npm run format Use [Azure Data Studio](https://docs.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver15) (or some other sql client) for easier sql queries/ testing while developing. We're using [PostgresSQL](https://www.postgresql.org/) so keep that in mind while googling how to query things as the syntax and features can be slightly different across sql flavors. **[AZURE DATA STUDIO REQUIRES A POSTGRES PLUGIN TO WORK WITH POSTGRESQL](https://docs.microsoft.com/en-us/sql/azure-data-studio/extensions/postgres-extension?view=sql-server-ver15)**. So if you want to use Azure Data Studio, you'll have to install that extension. +### Local Auth Providers + +If you're looking for more information on how to setup auth for your developement environment, check out more info [here](./docs/localAuth.md) + ## Working in the Project This project is built using @@ -82,7 +92,7 @@ For those unfamiliar with Express, I'll attempt to give a brief rundown before t Express is a REST framework for node. Devs new to express will likely find one of the most perplexing parts of Express to be how it handles middleware. For those unfamiliar with what middleware is, it's largely a catch all term for code that connects together pieces of code in the api. In Express's context, middleware is basically everything that runs within each router; here's an example: ```typescript -Router.get('/:id', idAsInt, UserController.detail, serializer) +Router.get('/:id', idAsInt, UserController.detail) ``` In express, all of the functions added after the route's path are considered middleware and each route can have as many middleware as is needed. In this project we separate out `controllers` into their own directory though they are still considered middleware. @@ -113,13 +123,13 @@ Let's take this from the top - `index.ts`: where the application is bootstrapped from, controls all global server controls and middlewares - `routers/index.ts`: largely a rollup for all the other routers. Can be used to add router specific middleware to routes/ subroutes - `routers/route.ts`: Individual routes for each resource, where the list of middleware can be found. _All routers call unique middleware_ -- Middleware: The above diagram is a bit of a misnomer. Not every endpoint will have validators, controllers, and serializers. Some will have all of those, some may have none. Each route will have at least one middleware, and the last middleware will deal with returning the requested data +- Middleware: The above diagram is a bit of a misnomer. Not every endpoint will have auth, validators, and controllers. Some will have all of those, some may have none. Each route will have at least one middleware, and the last middleware will deal with returning the requested data +- Auth: checks the access/ refresh tokens - Validators: validates the bodies of requests -- Controllers: deals with setting status codes, and directing to services +- Controllers: deals with setting status codes, and directing to services. For the most part, controllers should be the last piece of middleware in the chain. - Services: Workhorse of the application. Deals with all major application logic and database calls -- Serializers: Formats the data to be a sane, reusable response. -The database models live outside of this control flow as they don't deal with any buisness logic. However services will use them to access the database. You can largely think of the the models as a 1:1 map to database tables. +The database models live outside of this control flow as they don't deal with any buisness logic. However services will use them to access the database. You can largely think of the models as a 1:1 map to database tables. ### Shared Modules @@ -127,7 +137,7 @@ This project uses shared modules between it and it's client. What this means is The project can be found [here](https://github.com/UBAutograding/devu-shared). -When developing if you need to update the modules, you can do so by updating the branch or SHA on the package url in the `package.json`. As an example, if you wanted to use shared modules from the `auth` branch, you could change the dependancy line in the `package.json` to: +When developing if you need to update the modules, you can do so by updating the branch or SHA on the package url in the `package.json`. As an example, if you wanted to use shared modules from the `auth` branch, you could change the dependency line in the `package.json` to: ``` "devu-shared-modules": "github:UBAutograding/devu-shared#auth", @@ -141,7 +151,7 @@ npm install to install the updated package -If you were to make changes to the your shared branch and push it to the remote, you can update what version you local files are looking at via +If you were to make changes to your shared branch and push it to the remote, you can update what version your local files are looking at via ``` npm update devu-shared-modules @@ -175,7 +185,7 @@ And lastly, if you want to narrow it down to running less than a single test fil npm test -- -t "some test description or name" ``` -I wouldn't reccomend digging that far down as the of tests should be more human readable, and therefor not super great to grab via a regex; but if you really wish to do so, you can. +I wouldn't recommend digging that far down as the of tests should be more human-readable, and therefore not super great to grab via a regex; but if you really wish to do so, you can. ### Common TypeORM Commands (Database/ Schema Stuff) @@ -197,6 +207,36 @@ And revert the latest migration with npm run typeorm --migration:revert ``` +### Configuration Options + +Most of the API's configuraiton options live in a file called `environment.ts`. That file is bootstrapped at startup using the [config library]https://www.npmjs.com/package/config), as well as some environment variables. + +What this means for you (the developer) is that you can control certain api options via environment variables at runtime, or by using your `config/default.yml`. To see which `environment.ts` options support using environment variables directly, open that file and see which are using `process.env.*`; everything else should be configurable via your `default.yml` + +If you update your `default.yml` be sure to hard restart your API, as changing the config options does not update until you rebootstrap the API. + +### Style Guide + +While we use prettier to control most of the style choices for the application, it is not a silver bullet. Here we'll list a few conventions that will (hopefully) make working in the API a little bit more sane. + +When importing stuff we try to keep things in a certain order. Example + +``` +import Libraries + +import RootLevelStuff + +import Controllers + +import Middleware + +import Routers + +import Utils +``` + +The important thing here is once you get into the modules (models/ controllers/ routers/ etc), import them alphebetically with a single empty line inbetween them. + ## Production Builds You can build the project as a production build diff --git a/config/default.yml.template b/config/default.yml.template new file mode 100644 index 00000000..e9a298a4 --- /dev/null +++ b/config/default.yml.template @@ -0,0 +1,78 @@ +api: + clientUrl: http://localhost:9000 + scheme: http + host: localhost + port: 3001 + +database: + host: 'localhost' + username: 'typescript_user' + password: 'password' + name: 'typescript_api' + +logging: + db: false + +auth: + jwt: + activeKeyId: sk07112021 + accessTokenValiditySeconds: 600 # 10 minutes (seconds) + refreshTokenValiditySeconds: 864000 # 10 days (seconds) + refreshTokenExpirationBufferSeconds: 86400 # 1 days (seconds) + keys: + sk07112021: + privateKey: | + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- + publicKey: | + -----BEGIN RSA PUBLIC KEY----- + ... + -----END RSA PUBLIC KEY----- + + providers: + devAuth: + enabled: true + + saml: + name: MyUB + enabled: false + entryPoint: https://samltest.id/idp/profile/SAML2/Redirect/SSO + acceptedClockSkewSeconds: 20 + attributeMap: + urn:oid:0.9.2342.19200300.100.1.3: email + urn:oid:0.9.2342.19200300.100.1.1: externalId + urn:oasis:names:tc:SAML:attribute:subject-id: identifier + urn:oid:2.5.4.4: sn + urn:oid:2.16.840.1.113730.3.1.241: displayName + urn:oid:2.5.4.20: telephoneNumber + urn:oid:2.5.4.42: givenName + https://samltest.id/attributes/role: role + urn:oid:1.3.6.1.4.1.5923.1.1.1.7: eduPersonEntitlement + idpCerts: + - | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + - | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + encryption: + privateKey: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + certificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + signing: + privateKey: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + certificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- diff --git a/config/test.yml b/config/test.yml new file mode 100644 index 00000000..0fe22b79 --- /dev/null +++ b/config/test.yml @@ -0,0 +1,2 @@ +# If you need any env stuff for tests, place here. +# This file exists solely to prevent jest & config from throwing console errors diff --git a/docs/controlFlow.png b/docs/controlFlow.png index 66299069..8b00c5cb 100644 Binary files a/docs/controlFlow.png and b/docs/controlFlow.png differ diff --git a/docs/localAuth.md b/docs/localAuth.md new file mode 100644 index 00000000..016624e7 --- /dev/null +++ b/docs/localAuth.md @@ -0,0 +1,53 @@ +# Local Auth + +## Enabling Developer Auth + +By default (aka in the `default.yml.template` file) developer auth is enabled. If you don't care how that works you can just use the config as is and you should be good to go. (It'll look something like this) + +```yaml +providers: + devAuth: + enabled: true +``` + +If you wish to better understand how this works, here's a bit more information. + +When developer auth is enabled, users can provide the email & externalId of the user they wish to login as (or create) and recieve a valid refresh/ access token. + +With this flag on, it enabled the `/login/developer` route (see `./router/login.router.ts` for more details). + +## Testing SAML Authentication Locally + +To test SAML authentication, you will need to configure an Identity Provider (IDP) for the API to authenticate against. As we don't expect anyone to just have a configured IDP laying around ready to go, this will walk through using [SamlTest.id](https://samltest.id/). + +[SamlTest.id](https://samltest.id/) is an IDP specifically designed for testing. To use it in this project, we can configure it as follows. + +1. If you haven't already, run `npm run generate-config` to generate a base config with keys. +1. Download the IDP metadata from https://samltest.id/saml/idp. +1. Open the downladed IDP metadata xml file and pull out the two `signing` keys. +1. Add these to your `default.yml` config under `providers.saml.idpCerts` between the begin and end certificate tags as stubbed out for you as follows. + +```yaml +idpCerts: + - | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + - | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- +``` + +1. Enable the SAML provider in the `default.yml` config. + +```yaml +saml: + name: MySAMLName + enabled: true +``` + +1. At this point you should be all set to run the API for the first time, though SAML auth will _not_ work yet. +1. Go to `/login/saml/metadata` and save the SP metadata file it presents you with. +1. Navigate to https://samltest.id/upload.php and upload the SP metadata from the previous step. +1. Now you should be all set for local SAML testing and can try logging in. diff --git a/package-lock.json b/package-lock.json index b5bc7e4f..f0305ca4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,18 @@ "version": "1.0.0", "dependencies": { "body-parser": "^1.19.0", + "colors": "^1.4.0", + "config": "^3.3.6", + "cookie-parser": "^1.4.5", "cors": "^2.8.5", "devu-shared-modules": "github:UBAutograding/devu-shared#master", "express": "^4.17.1", "express-validator": "^6.11.1", "helmet": "^4.6.0", + "jsonwebtoken": "^8.5.1", "morgan": "^1.10.0", + "passport": "^0.4.1", + "passport-saml": "^3.0.0", "pg": "^8.4.0", "reflect-metadata": "^0.1.10", "swagger-jsdoc": "^6.1.0", @@ -22,16 +28,26 @@ "typeorm": "0.2.32" }, "devDependencies": { + "@types/config": "^0.0.38", + "@types/cookie-parser": "^1.4.2", + "@types/cors": "^2.8.10", "@types/express": "^4.17.12", "@types/helmet": "^4.0.0", "@types/jest": "^26.0.23", - "@types/node": "^8.0.29", + "@types/jsonwebtoken": "^8.5.1", + "@types/jws": "^3.2.3", + "@types/morgan": "^1.9.2", + "@types/node": "^15.12.2", + "@types/passport": "^1.0.6", + "@types/passport-strategy": "^0.2.35", + "@types/swagger-jsdoc": "^6.0.0", + "@types/swagger-ui-express": "^4.1.2", "husky": "^6.0.0", "jest": "^27.0.4", "lint-staged": "^11.0.0", "npm-run-all": "^4.1.5", "prettier": "^2.3.0", - "rmraf": "^1.0.3", + "rimraf": "^3.0.2", "ts-jest": "^27.0.2", "ts-node": "^10.0.0", "ts-node-dev": "^1.1.6", @@ -1106,6 +1122,12 @@ "@types/node": "*" } }, + "node_modules/@types/config": { + "version": "0.0.38", + "resolved": "https://registry.npmjs.org/@types/config/-/config-0.0.38.tgz", + "integrity": "sha512-z2WizAfIFgSv8SQfQ8c0LlbDAcK47D/o93XW6bxZ9t3bs4fmmfAPjk1nhAIBTG84PBBCHfSPM+8g7vhLdbFokg==", + "dev": true + }, "node_modules/@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -1115,6 +1137,21 @@ "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", + "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==", + "dev": true + }, "node_modules/@types/express": { "version": "4.17.12", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", @@ -1196,16 +1233,43 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-rNAPdomlIUX0i0cg2+I+Q1wOUr531zHBQ+cV/28PJ39bSPKjahatZZ2LMuhiguETkCgLVzfruw/ZvNMNkKoSzw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jws": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@types/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-g54CHxwvaHvyJyeuZqe7VQujV9SfCXwEkboJp355INPL+kjlS3Aq153EHptaeO/Cch/NPJ1i2sHz0sDDizn7LQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "node_modules/@types/morgan": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.2.tgz", + "integrity": "sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", "dev": true }, "node_modules/@types/parse-json": { @@ -1214,6 +1278,25 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "node_modules/@types/passport": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.6.tgz", + "integrity": "sha512-9oKfrJXuAxvyxdrtMCxKkHgmd6DMO8NDOLvMJ1LvIWd6/xP+i81PAkpTaEca7VhJX9S009RciwZL/j6dsLsHrA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, "node_modules/@types/prettier": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", @@ -1260,6 +1343,22 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "node_modules/@types/swagger-jsdoc": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.0.tgz", + "integrity": "sha512-0snGxQMvrPOFEFnEVcXAm8zKH7aLB5tAsUTXfWwQu7XGfMBelt+tSLzF5lH0D+ppRiZrwPnWF7f3fpDHZaWzag==", + "dev": true + }, + "node_modules/@types/swagger-ui-express": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.2.tgz", + "integrity": "sha512-t9teFTU8dKe69rX9EwL6OM2hbVquYdFM+sQ0REny4RalPlxAm+zyP04B12j4c7qEuDS6CnlwICywqWStPA3v4g==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/serve-static": "*" + } + }, "node_modules/@types/yargs": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", @@ -1490,15 +1589,6 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -1508,12 +1598,6 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", - "dev": true - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1770,6 +1854,11 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -1796,7 +1885,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -1829,26 +1917,25 @@ } }, "node_modules/camelcase-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", - "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "dependencies": { - "camelcase": "^4.1.0", - "map-obj": "^2.0.0", - "quick-lru": "^1.0.0" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/caniuse-lite": { @@ -2032,7 +2119,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, "engines": { "node": ">=0.1.90" } @@ -2063,6 +2149,17 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/config": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.6.tgz", + "integrity": "sha512-Hj5916C5HFawjYJat1epbyY2PlAgLpBtDUlr0MxGLgo3p5+7kylyvnRY18PqJHgnNWXcdd0eWDemT7eYWuFgwg==", + "dependencies": { + "json5": "^2.1.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -2099,6 +2196,18 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -2188,15 +2297,6 @@ "node": ">=0.10.0" } }, - "node_modules/cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -2227,381 +2327,141 @@ "node": "*" } }, - "node_modules/dateformat/node_modules/camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/dateformat/node_modules/camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "node_modules/decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "dev": true + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true, - "dependencies": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/dateformat/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "object-keys": "^1.0.12" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/dateformat/node_modules/indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true, - "dependencies": { - "repeating": "^2.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/dateformat/node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/dateformat/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/dateformat/node_modules/meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, + "node_modules/devu-shared-modules": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/UBAutograding/devu-shared.git#ada0a705249a0d83bdf8bfd99274dc62ee0f5faa", + "hasInstallScript": true, "dependencies": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "npm-run-all": "^4.1.5", + "rimraf": "^3.0.2", + "typescript": "^4.3.2" } }, - "node_modules/dateformat/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.3.1" } }, - "node_modules/dateformat/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "node_modules/diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dependencies": { - "pinkie-promise": "^2.0.0" + "esutils": "^2.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/dateformat/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "webidl-conversions": "^5.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "dependencies": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "dependencies": { - "get-stdin": "^4.0.1" - }, - "bin": { - "strip-indent": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dateformat/node_modules/trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-equal": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", - "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/devu-shared-modules": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/UBAutograding/devu-shared.git#6017d70136f1956787ad0d5dd8c5312c1330fcfb", - "hasInstallScript": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" + "node": ">=8" } }, "node_modules/domexception/node_modules/webidl-conversions": { @@ -2630,6 +2490,14 @@ "xtend": "^4.0.0" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2682,7 +2550,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -2691,7 +2558,6 @@ "version": "1.18.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -2721,7 +2587,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -2929,15 +2794,6 @@ "node": ">= 8.0.0" } }, - "node_modules/eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "dev": true, - "engines": { - "node": "> 0.1.90" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3061,8 +2917,7 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -3085,7 +2940,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -3174,14 +3028,12 @@ "node_modules/graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -3212,7 +3064,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3229,7 +3080,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3256,8 +3106,7 @@ "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" }, "node_modules/html-encoding-sniffer": { "version": "2.0.1", @@ -3386,15 +3235,6 @@ "url": "https://github.com/sponsors/typicode" } }, - "node_modules/i": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", - "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3509,14 +3349,12 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "node_modules/is-bigint": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3537,7 +3375,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -3552,7 +3389,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3576,7 +3412,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -3588,7 +3423,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3650,7 +3484,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3671,7 +3504,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3688,15 +3520,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -3707,7 +3530,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-symbols": "^1.0.2" @@ -3741,7 +3563,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3753,7 +3574,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -3791,14 +3611,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "node_modules/istanbul-lib-coverage": { "version": "3.0.0", @@ -4900,8 +4713,7 @@ "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -4913,7 +4725,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, "dependencies": { "minimist": "^1.2.5" }, @@ -4924,6 +4735,59 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -5038,7 +4902,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -5053,7 +4916,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -5066,7 +4928,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, "engines": { "node": ">=4" } @@ -5093,16 +4954,51 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "node_modules/lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5224,12 +5120,12 @@ } }, "node_modules/map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/media-typer": { @@ -5244,29 +5140,29 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true, "engines": { "node": ">= 0.10.0" } }, "node_modules/meow": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "dependencies": { - "camelcase-keys": "^4.0.0", - "decamelize-keys": "^1.0.0", + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", "minimist": "^1.1.3", - "minimist-options": "^3.0.1", "normalize-package-data": "^2.3.4", - "read-pkg-up": "^3.0.0", - "redent": "^2.0.0", - "trim-newlines": "^2.0.0" + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/merge-descriptors": { @@ -5354,21 +5250,7 @@ "node_modules/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/minimist-options": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" - }, - "engines": { - "node": ">= 4" - } + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "node_modules/mkdirp": { "version": "1.0.4", @@ -5409,12 +5291,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -5431,15 +5307,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/ncp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", - "integrity": "sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=", - "dev": true, - "bin": { - "ncp": "bin/ncp" - } - }, "node_modules/negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -5451,8 +5318,15 @@ "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "engines": { + "node": ">= 6.0.0" + } }, "node_modules/node-int64": { "version": "0.4.0", @@ -5479,7 +5353,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -5491,7 +5364,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, "bin": { "semver": "bin/semver" } @@ -5509,7 +5381,6 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "chalk": "^2.4.1", @@ -5534,7 +5405,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -5546,7 +5416,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -5560,7 +5429,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -5568,14 +5436,12 @@ "node_modules/npm-run-all/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/npm-run-all/node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -5591,7 +5457,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -5600,7 +5465,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, "engines": { "node": ">=4" } @@ -5609,7 +5473,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, "engines": { "node": ">=4" } @@ -5618,7 +5481,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, "bin": { "semver": "bin/semver" } @@ -5627,7 +5489,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "dependencies": { "shebang-regex": "^1.0.0" }, @@ -5639,7 +5500,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5648,7 +5508,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -5660,7 +5519,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -5698,7 +5556,6 @@ "version": "1.10.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5707,7 +5564,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -5716,7 +5572,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -5922,6 +5777,64 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-saml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/passport-saml/-/passport-saml-3.0.0.tgz", + "integrity": "sha512-NLR2nVCaZ6a9AG/XmKOs4uuRRlWutybZ8BbzixdbBor8S/dMtmgZFJ6h8sdRSSuS5wMfjqUSaJ/BwDdbiU/zWg==", + "dependencies": { + "debug": "^4.3.1", + "passport-strategy": "^1.0.0", + "xml-crypto": "^2.1.2", + "xml-encryption": "^1.2.4", + "xml2js": "^0.4.23", + "xmlbuilder": "^15.1.1", + "xmldom": "^0.6.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/passport-saml/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/passport-saml/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5951,8 +5864,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -5968,6 +5880,11 @@ "node": ">=8" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "node_modules/pg": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/pg/-/pg-8.6.0.tgz", @@ -6058,7 +5975,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, "bin": { "pidtree": "bin/pidtree.js" }, @@ -6070,7 +5986,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, "engines": { "node": ">=4" } @@ -6225,22 +6140,6 @@ "@types/yargs-parser": "*" } }, - "node_modules/prompt": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.1.0.tgz", - "integrity": "sha512-ec1vUPXCplDBDUVD8uPa3XGA+OzLrO40Vxv3F1uxoiZGkZhdctlK2JotcHq5X6ExjocDOGwGdCSXloGNyU5L1Q==", - "dev": true, - "dependencies": { - "colors": "^1.1.2", - "read": "1.0.x", - "revalidator": "0.1.x", - "utile": "0.3.x", - "winston": "2.x" - }, - "engines": { - "node": ">= 0.6.6" - } - }, "node_modules/prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -6289,15 +6188,6 @@ "node": ">=0.6" } }, - "node_modules/quick-lru": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", - "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6326,23 +6216,10 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, "dependencies": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", @@ -6353,101 +6230,135 @@ } }, "node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "dependencies": { - "locate-path": "^2.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/read-pkg-up/node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/read-pkg-up/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "dependencies": { - "p-try": "^1.0.0" + "error-ex": "^1.2.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "dependencies": { - "p-limit": "^1.1.0" + "pinkie-promise": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "node_modules/read-pkg-up/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "node_modules/read-pkg-up/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/read-pkg-up/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "dependencies": { - "pify": "^3.0.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "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==", + "node_modules/read-pkg-up/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -6470,25 +6381,28 @@ } }, "node_modules/redent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", - "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "dependencies": { - "indent-string": "^3.0.0", - "strip-indent": "^2.0.0" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/redent/node_modules/indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/reflect-metadata": { @@ -6520,7 +6434,6 @@ "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, "dependencies": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" @@ -6563,20 +6476,10 @@ "node": ">=8" } }, - "node_modules/revalidator": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", - "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -6587,121 +6490,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rmraf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/rmraf/-/rmraf-1.0.3.tgz", - "integrity": "sha512-yZL0ZNF1FFkvKlxGZKe9JVgLpyuBns5uGkX+QV8DSLxYOaeX05wqHVmOcELl+6atFPIXRg+fiMsugf0d2FNOUA==", - "dev": true, - "dependencies": { - "chalk": "^2.3.2", - "meow": "^4.0.0", - "prompt": "^1.0.0", - "prompts": "^0.1.8" - }, - "bin": { - "rmraf": "cli.js" - } - }, - "node_modules/rmraf/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/rmraf/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/rmraf/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/rmraf/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/rmraf/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/rmraf/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/rmraf/node_modules/kleur": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", - "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", - "deprecated": "Please upgrade to kleur@3 or migrate to 'ansi-colors' if you prefer the old syntax. Visit for migration path(s).", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/rmraf/node_modules/prompts": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", - "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", - "dev": true, - "dependencies": { - "kleur": "^2.0.1", - "sisteransi": "^0.1.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/rmraf/node_modules/sisteransi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz", - "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==", - "dev": true - }, - "node_modules/rmraf/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -6839,8 +6627,7 @@ "node_modules/shell-quote": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", - "dev": true + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" }, "node_modules/signal-exit": { "version": "3.0.3", @@ -6900,7 +6687,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -6909,14 +6695,12 @@ "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -6925,8 +6709,7 @@ "node_modules/spdx-license-ids": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==" }, "node_modules/split2": { "version": "3.2.2", @@ -6942,15 +6725,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", @@ -7037,7 +6811,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -7054,7 +6827,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -7067,7 +6839,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -7120,12 +6891,18 @@ } }, "node_modules/strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, + "dependencies": { + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/strip-json-comments": { @@ -7383,12 +7160,12 @@ } }, "node_modules/trim-newlines": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", - "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/ts-jest": { @@ -7706,7 +7483,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7719,7 +7495,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "has-bigints": "^1.0.1", @@ -7752,47 +7527,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "node_modules/utile": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/utile/-/utile-0.3.0.tgz", - "integrity": "sha1-E1LDQOuCDk2N26A5pPv6oy7U7zo=", - "dev": true, - "dependencies": { - "async": "~0.9.0", - "deep-equal": "~0.2.1", - "i": "0.3.x", - "mkdirp": "0.x.x", - "ncp": "1.0.x", - "rimraf": "2.x.x" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/utile/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/utile/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -7828,7 +7562,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -7937,7 +7670,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -7949,38 +7681,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/winston": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", - "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", - "dev": true, - "dependencies": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "stack-trace": "0.0.x" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/winston/node_modules/async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", - "dev": true - }, - "node_modules/winston/node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -8044,6 +7744,32 @@ } } }, + "node_modules/xml-crypto": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-2.1.2.tgz", + "integrity": "sha512-DBhZXtBjENtLwJmeJhLUBwUm9YWNjCRvAx6ESP4VJyM9PDuKqZu2Fp5Y5HKqcdJT7vV7eI25Z4UBMezji6QloQ==", + "dependencies": { + "xmldom": "^0.6.0", + "xpath": "0.0.32" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xml-encryption": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/xml-encryption/-/xml-encryption-1.2.4.tgz", + "integrity": "sha512-+4aSBIv/lwmv5PntfYsZyelOnCcyDmCt/MNxXUukRGlcWW8DObJ26obbVX3iXYRdqkLqbv3AKk8ntNCGKIq/UQ==", + "dependencies": { + "escape-html": "^1.0.3", + "node-forge": "^0.10.0", + "xmldom": "~0.6.0", + "xpath": "0.0.32" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -8062,7 +7788,7 @@ "node": ">=4.0.0" } }, - "node_modules/xmlbuilder": { + "node_modules/xml2js/node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", @@ -8070,12 +7796,36 @@ "node": ">=4.0" } }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "engines": { + "node": ">=8.0" + } + }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "node_modules/xmldom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xpath": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", + "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==", + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -9102,6 +8852,12 @@ "@types/node": "*" } }, + "@types/config": { + "version": "0.0.38", + "resolved": "https://registry.npmjs.org/@types/config/-/config-0.0.38.tgz", + "integrity": "sha512-z2WizAfIFgSv8SQfQ8c0LlbDAcK47D/o93XW6bxZ9t3bs4fmmfAPjk1nhAIBTG84PBBCHfSPM+8g7vhLdbFokg==", + "dev": true + }, "@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -9111,6 +8867,21 @@ "@types/node": "*" } }, + "@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/cors": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", + "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==", + "dev": true + }, "@types/express": { "version": "4.17.12", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", @@ -9191,16 +8962,43 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" }, + "@types/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-rNAPdomlIUX0i0cg2+I+Q1wOUr531zHBQ+cV/28PJ39bSPKjahatZZ2LMuhiguETkCgLVzfruw/ZvNMNkKoSzw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jws": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@types/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-g54CHxwvaHvyJyeuZqe7VQujV9SfCXwEkboJp355INPL+kjlS3Aq153EHptaeO/Cch/NPJ1i2sHz0sDDizn7LQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "@types/morgan": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.2.tgz", + "integrity": "sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", "dev": true }, "@types/parse-json": { @@ -9209,6 +9007,25 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/passport": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.6.tgz", + "integrity": "sha512-9oKfrJXuAxvyxdrtMCxKkHgmd6DMO8NDOLvMJ1LvIWd6/xP+i81PAkpTaEca7VhJX9S009RciwZL/j6dsLsHrA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*" + } + }, "@types/prettier": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", @@ -9255,6 +9072,22 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "@types/swagger-jsdoc": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.0.tgz", + "integrity": "sha512-0snGxQMvrPOFEFnEVcXAm8zKH7aLB5tAsUTXfWwQu7XGfMBelt+tSLzF5lH0D+ppRiZrwPnWF7f3fpDHZaWzag==", + "dev": true + }, + "@types/swagger-ui-express": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.2.tgz", + "integrity": "sha512-t9teFTU8dKe69rX9EwL6OM2hbVquYdFM+sQ0REny4RalPlxAm+zyP04B12j4c7qEuDS6CnlwICywqWStPA3v4g==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/serve-static": "*" + } + }, "@types/yargs": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", @@ -9430,24 +9263,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", - "dev": true - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -9630,6 +9451,11 @@ "ieee754": "^1.2.1" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -9650,7 +9476,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -9674,20 +9499,19 @@ "dev": true }, "camelcase-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", - "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { - "camelcase": "^4.1.0", - "map-obj": "^2.0.0", - "quick-lru": "^1.0.0" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" }, "dependencies": { "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", "dev": true } } @@ -9830,8 +9654,7 @@ "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, "combined-stream": { "version": "1.0.8", @@ -9853,6 +9676,14 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "config": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.6.tgz", + "integrity": "sha512-Hj5916C5HFawjYJat1epbyY2PlAgLpBtDUlr0MxGLgo3p5+7kylyvnRY18PqJHgnNWXcdd0eWDemT7eYWuFgwg==", + "requires": { + "json5": "^2.1.1" + } + }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -9880,6 +9711,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, + "cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -9900,253 +9740,83 @@ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", "dev": true, "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", - "dev": true - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true } } }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -10161,24 +9831,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - } - } - }, "decimal.js": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", @@ -10191,12 +9843,6 @@ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, - "deep-equal": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", - "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=", - "dev": true - }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -10213,7 +9859,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -10241,8 +9886,13 @@ "dev": true }, "devu-shared-modules": { - "version": "git+ssh://git@github.com/UBAutograding/devu-shared.git#6017d70136f1956787ad0d5dd8c5312c1330fcfb", - "from": "devu-shared-modules@github:UBAutograding/devu-shared#master" + "version": "git+ssh://git@github.com/UBAutograding/devu-shared.git#ada0a705249a0d83bdf8bfd99274dc62ee0f5faa", + "from": "devu-shared-modules@github:UBAutograding/devu-shared#master", + "requires": { + "npm-run-all": "^4.1.5", + "rimraf": "^3.0.2", + "typescript": "^4.3.2" + } }, "diff": { "version": "4.0.2", @@ -10295,6 +9945,14 @@ "xtend": "^4.0.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -10335,7 +9993,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -10344,7 +10001,6 @@ "version": "1.18.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -10368,7 +10024,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -10517,12 +10172,6 @@ "validator": "^13.5.2" } }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "dev": true - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -10618,8 +10267,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gensync": { "version": "1.0.0-beta.2", @@ -10636,7 +10284,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -10698,14 +10345,12 @@ "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -10728,8 +10373,7 @@ "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" }, "has-flag": { "version": "4.0.0", @@ -10739,8 +10383,7 @@ "has-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, "helmet": { "version": "4.6.0", @@ -10755,8 +10398,7 @@ "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" }, "html-encoding-sniffer": { "version": "2.0.1", @@ -10852,12 +10494,6 @@ "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", "dev": true }, - "i": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", - "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", - "dev": true - }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10933,14 +10569,12 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-bigint": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" }, "is-binary-path": { "version": "2.1.0", @@ -10955,7 +10589,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -10963,8 +10596,7 @@ "is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" }, "is-ci": { "version": "3.0.0", @@ -10979,7 +10611,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -10987,8 +10618,7 @@ "is-date-object": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" }, "is-extglob": { "version": "2.1.1", @@ -11025,8 +10655,7 @@ "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" }, "is-number": { "version": "7.0.0", @@ -11037,8 +10666,7 @@ "is-number-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" }, "is-obj": { "version": "1.0.1", @@ -11046,12 +10674,6 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -11062,7 +10684,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-symbols": "^1.0.2" @@ -11083,14 +10704,12 @@ "is-string": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" }, "is-symbol": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -11116,14 +10735,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "istanbul-lib-coverage": { "version": "3.0.0", @@ -11966,8 +11578,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-parse-even-better-errors": { "version": "2.3.1", @@ -11979,11 +11590,58 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, "requires": { "minimist": "^1.2.5" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -12071,7 +11729,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -12083,7 +11740,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -12092,8 +11748,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" } } }, @@ -12116,16 +11771,51 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -12216,9 +11906,9 @@ } }, "map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true }, "media-typer": { @@ -12229,24 +11919,24 @@ "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" }, "meow": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { - "camelcase-keys": "^4.0.0", - "decamelize-keys": "^1.0.0", + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", "minimist": "^1.1.3", - "minimist-options": "^3.0.1", "normalize-package-data": "^2.3.4", - "read-pkg-up": "^3.0.0", - "redent": "^2.0.0", - "trim-newlines": "^2.0.0" + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" } }, "merge-descriptors": { @@ -12310,18 +12000,7 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "minimist-options": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" - } + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mkdirp": { "version": "1.0.4", @@ -12352,12 +12031,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -12374,12 +12047,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "ncp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", - "integrity": "sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=", - "dev": true - }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -12388,8 +12055,12 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "node-int64": { "version": "0.4.0", @@ -12413,7 +12084,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -12424,8 +12094,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -12439,7 +12108,6 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "chalk": "^2.4.1", @@ -12456,7 +12124,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -12465,7 +12132,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -12476,7 +12142,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -12484,14 +12149,12 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -12503,32 +12166,27 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -12536,14 +12194,12 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -12552,7 +12208,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, "requires": { "isexe": "^2.0.0" } @@ -12582,20 +12237,17 @@ "object-inspect": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", - "dev": true + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -12741,6 +12393,49 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-saml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/passport-saml/-/passport-saml-3.0.0.tgz", + "integrity": "sha512-NLR2nVCaZ6a9AG/XmKOs4uuRRlWutybZ8BbzixdbBor8S/dMtmgZFJ6h8sdRSSuS5wMfjqUSaJ/BwDdbiU/zWg==", + "requires": { + "debug": "^4.3.1", + "passport-strategy": "^1.0.0", + "xml-crypto": "^2.1.2", + "xml-encryption": "^1.2.4", + "xml2js": "^0.4.23", + "xmlbuilder": "^15.1.1", + "xmldom": "^0.6.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -12761,8 +12456,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "0.1.7", @@ -12775,6 +12469,11 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "pg": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/pg/-/pg-8.6.0.tgz", @@ -12839,14 +12538,12 @@ "pidtree": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==" }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "pinkie": { "version": "2.0.4", @@ -12961,19 +12658,6 @@ } } }, - "prompt": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.1.0.tgz", - "integrity": "sha512-ec1vUPXCplDBDUVD8uPa3XGA+OzLrO40Vxv3F1uxoiZGkZhdctlK2JotcHq5X6ExjocDOGwGdCSXloGNyU5L1Q==", - "dev": true, - "requires": { - "colors": "^1.1.2", - "read": "1.0.x", - "revalidator": "0.1.x", - "utile": "0.3.x", - "winston": "2.x" - } - }, "prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -13010,12 +12694,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, - "quick-lru": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", - "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", - "dev": true - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -13038,20 +12716,10 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, "requires": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", @@ -13062,7 +12730,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, "requires": { "pify": "^3.0.0" } @@ -13070,63 +12737,92 @@ } }, "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "locate-path": "^2.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "p-try": "^1.0.0" + "error-ex": "^1.2.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "pinkie-promise": "^2.0.0" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } } } }, @@ -13150,20 +12846,23 @@ } }, "redent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", - "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "requires": { - "indent-string": "^3.0.0", - "strip-indent": "^2.0.0" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" }, "dependencies": { "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } } } }, @@ -13190,7 +12889,6 @@ "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" @@ -13221,113 +12919,14 @@ "signal-exit": "^3.0.2" } }, - "revalidator": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", - "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", - "dev": true - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } }, - "rmraf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/rmraf/-/rmraf-1.0.3.tgz", - "integrity": "sha512-yZL0ZNF1FFkvKlxGZKe9JVgLpyuBns5uGkX+QV8DSLxYOaeX05wqHVmOcELl+6atFPIXRg+fiMsugf0d2FNOUA==", - "dev": true, - "requires": { - "chalk": "^2.3.2", - "meow": "^4.0.0", - "prompt": "^1.0.0", - "prompts": "^0.1.8" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "kleur": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", - "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", - "dev": true - }, - "prompts": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", - "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", - "dev": true, - "requires": { - "kleur": "^2.0.1", - "sisteransi": "^0.1.1" - } - }, - "sisteransi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz", - "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -13443,8 +13042,7 @@ "shell-quote": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", - "dev": true + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" }, "signal-exit": { "version": "3.0.3", @@ -13495,7 +13093,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -13504,14 +13101,12 @@ "spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" }, "spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -13520,8 +13115,7 @@ "spdx-license-ids": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==" }, "split2": { "version": "3.2.2", @@ -13537,12 +13131,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true - }, "stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", @@ -13602,7 +13190,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -13613,7 +13200,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -13623,7 +13209,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -13661,10 +13246,13 @@ "dev": true }, "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } }, "strip-json-comments": { "version": "2.0.1", @@ -13857,9 +13445,9 @@ "dev": true }, "trim-newlines": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", - "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, "ts-jest": { @@ -14078,14 +13666,12 @@ "typescript": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", - "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", - "dev": true + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==" }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has-bigints": "^1.0.1", @@ -14109,40 +13695,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "utile": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/utile/-/utile-0.3.0.tgz", - "integrity": "sha1-E1LDQOuCDk2N26A5pPv6oy7U7zo=", - "dev": true, - "requires": { - "async": "~0.9.0", - "deep-equal": "~0.2.1", - "i": "0.3.x", - "mkdirp": "0.x.x", - "ncp": "1.0.x", - "rimraf": "2.x.x" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -14171,7 +13723,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -14259,7 +13810,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -14268,34 +13818,6 @@ "is-symbol": "^1.0.3" } }, - "winston": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", - "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", - "dev": true, - "requires": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "stack-trace": "0.0.x" - }, - "dependencies": { - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", - "dev": true - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - } - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -14336,6 +13858,26 @@ "dev": true, "requires": {} }, + "xml-crypto": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-2.1.2.tgz", + "integrity": "sha512-DBhZXtBjENtLwJmeJhLUBwUm9YWNjCRvAx6ESP4VJyM9PDuKqZu2Fp5Y5HKqcdJT7vV7eI25Z4UBMezji6QloQ==", + "requires": { + "xmldom": "^0.6.0", + "xpath": "0.0.32" + } + }, + "xml-encryption": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/xml-encryption/-/xml-encryption-1.2.4.tgz", + "integrity": "sha512-+4aSBIv/lwmv5PntfYsZyelOnCcyDmCt/MNxXUukRGlcWW8DObJ26obbVX3iXYRdqkLqbv3AKk8ntNCGKIq/UQ==", + "requires": { + "escape-html": "^1.0.3", + "node-forge": "^0.10.0", + "xmldom": "~0.6.0", + "xpath": "0.0.32" + } + }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -14349,12 +13891,19 @@ "requires": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" + }, + "dependencies": { + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } } }, "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==" }, "xmlchars": { "version": "2.2.0", @@ -14362,6 +13911,16 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "xmldom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==" + }, + "xpath": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", + "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index f2d41fd2..6276c1c4 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,18 @@ { "name": "typescript-api-example", "version": "1.0.0", - "description": "Tyepscript Express/ TypeORM Example", + "description": "Typescript Express/ TypeORM Example", "scripts": { "start": "ts-node-dev src/index.ts", + "update-shared": "npm update devu-shared-modules", "typeorm": "ts-node ./node_modules/typeorm/cli.js --config src/database.ts", "test": "jest --passWithNoTests", "clean": "rimraf build/*", "lint": "tsc", "build": "npm-run-all clean lint", "format": "prettier --write \"./**/*.{js,ts,json,md}\"", - "pre-commit": "lint-staged" + "pre-commit": "lint-staged", + "generate-config": "docker run --pull always -v $(pwd)/config:/config --user $(id -u):$(id -g) --rm ubautograding/devtools /generateConfig.sh config/default.yml" }, "lint-staged": { "./**/*.{js,ts,json,md}": [ @@ -21,16 +23,26 @@ "node": ">=16" }, "devDependencies": { + "@types/config": "^0.0.38", + "@types/cookie-parser": "^1.4.2", + "@types/cors": "^2.8.10", "@types/express": "^4.17.12", "@types/helmet": "^4.0.0", "@types/jest": "^26.0.23", - "@types/node": "^8.0.29", + "@types/jsonwebtoken": "^8.5.1", + "@types/jws": "^3.2.3", + "@types/morgan": "^1.9.2", + "@types/node": "^15.12.2", + "@types/passport": "^1.0.6", + "@types/passport-strategy": "^0.2.35", + "@types/swagger-jsdoc": "^6.0.0", + "@types/swagger-ui-express": "^4.1.2", "husky": "^6.0.0", "jest": "^27.0.4", "lint-staged": "^11.0.0", "npm-run-all": "^4.1.5", "prettier": "^2.3.0", - "rmraf": "^1.0.3", + "rimraf": "^3.0.2", "ts-jest": "^27.0.2", "ts-node": "^10.0.0", "ts-node-dev": "^1.1.6", @@ -38,12 +50,18 @@ }, "dependencies": { "body-parser": "^1.19.0", + "colors": "^1.4.0", + "config": "^3.3.6", + "cookie-parser": "^1.4.5", "cors": "^2.8.5", "devu-shared-modules": "github:UBAutograding/devu-shared#master", "express": "^4.17.1", "express-validator": "^6.11.1", "helmet": "^4.6.0", + "jsonwebtoken": "^8.5.1", "morgan": "^1.10.0", + "passport": "^0.4.1", + "passport-saml": "^3.0.0", "pg": "^8.4.0", "reflect-metadata": "^0.1.10", "swagger-jsdoc": "^6.1.0", diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 00000000..c2191d27 --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,12 @@ +# This is the Dockerfile for ubautograding/devtools and can be extended as +# necessary. Currently it only contains the generateConfig utility. + +# GenerateConfig can be used as follows: +#docker run -v $(pwd)/config:/config --rm ubautograding/devtools /generateConfig.sh config/default.yml + +FROM docker.io/python:alpine + +RUN apk add --no-cache bash jq openssl \ + && pip install yq + +COPY ./generateConfig.sh /generateConfig.sh \ No newline at end of file diff --git a/scripts/generateConfig.sh b/scripts/generateConfig.sh new file mode 100755 index 00000000..e75a348f --- /dev/null +++ b/scripts/generateConfig.sh @@ -0,0 +1,29 @@ +#!/bin/bash +tmp_dir=$(mktemp -d -t config-XXXXXXXXXX) +trap 'rm -rf -- "$tmp_dir"' EXIT + +renderedFile=${1:-config/newconfig.yml} +templateFile=${2:-config/default.yml.template} + +cp ${templateFile} ${renderedFile} + +openssl genrsa -out ${tmp_dir}/jwt_private_key.pem 3072 2> /dev/null +openssl rsa -in ${tmp_dir}/jwt_private_key.pem -pubout -out ${tmp_dir}/jwt_public_key.pem 2> /dev/null + +openssl req -x509 -newkey rsa:4096 -keyout ${tmp_dir}/saml_signing_key.pem -subj "/CN=devu-signing.local/emailAddress=admin@devu-dev.local/C=US/ST=New York/L=Buffalo/O=DevU" -out ${tmp_dir}/saml_signing_cert.pem -nodes -days 900 2> /dev/null +openssl req -x509 -newkey rsa:4096 -keyout ${tmp_dir}/saml_encryption_key.pem -subj "/CN=devu-encryption.local/emailAddress=admin@devu-dev.local/C=US/ST=New York/L=Buffalo/O=DevU" -out ${tmp_dir}/saml_encryption_cert.pem -nodes -days 900 2> /dev/null + +yq -Yi --arg jwt_private_key "$(cat ${tmp_dir}/jwt_private_key.pem)" \ + --arg jwt_public_key "$(cat ${tmp_dir}/jwt_public_key.pem)" \ + --arg saml_signing_key "$(cat ${tmp_dir}/saml_signing_key.pem)" \ + --arg saml_signing_cert "$(cat ${tmp_dir}/saml_signing_cert.pem)" \ + --arg saml_encryption_key "$(cat ${tmp_dir}/saml_encryption_key.pem)" \ + --arg saml_encryption_cert "$(cat ${tmp_dir}/saml_encryption_cert.pem)" \ + '.auth.jwt.keys.sk07112021.privateKey=$jwt_private_key | + .auth.jwt.keys.sk07112021.publicKey=$jwt_public_key | + .auth.providers.saml.signing.privateKey=$saml_signing_key | + .auth.providers.saml.signing.certificate=$saml_signing_cert | + .auth.providers.saml.encryption.privateKey=$saml_encryption_key | + .auth.providers.saml.encryption.certificate=$saml_encryption_cert | + .auth.providers.saml.idpCerts=[]' \ + -- ${renderedFile} \ No newline at end of file diff --git a/src/controller/login.controller.ts b/src/controller/login.controller.ts new file mode 100644 index 00000000..21e9f79d --- /dev/null +++ b/src/controller/login.controller.ts @@ -0,0 +1,42 @@ +import { Request, Response, NextFunction } from 'express' + +import UserService from '../services/user.service' +import AuthService from '../services/auth.service' +import ProviderService from '../services/provider.service' + +import { Unauthorized } from '../utils/apiResponse.utils' + +export async function login(req: Request, res: Response, next: NextFunction) { + try { + if (req.refreshUser === undefined) return res.status(401).json(Unauthorized) + + const { userId } = req.refreshUser + + if (!userId) return res.status(401).json(Unauthorized) + + const user = await UserService.retrieve(userId) + + if (!user) return res.status(401).json(Unauthorized) + + const accessToken = AuthService.createAccessToken(user) + + res.status(200).json({ accessToken }) + } catch (err) { + next(err) + } +} + +export function getProviders(req: Request, res: Response, next: NextFunction) { + try { + const providers = ProviderService.get() + + res.status(200).json(providers) + } catch (err) { + next(err) + } +} + +export default { + login, + getProviders, +} diff --git a/src/controller/login.developer.controller.ts b/src/controller/login.developer.controller.ts new file mode 100644 index 00000000..06f0d2b0 --- /dev/null +++ b/src/controller/login.developer.controller.ts @@ -0,0 +1,25 @@ +import { Request, Response, NextFunction } from 'express' + +import UserService from '../services/user.service' +import AuthService from '../services/auth.service' + +import { GenericResponse } from '../utils/apiResponse.utils' +import { refreshCookieOptions } from '../utils/cookie.utils' + +export async function callback(req: Request, res: Response, next: NextFunction) { + try { + const { email = '', externalId = '' } = req.body + + const { user } = await UserService.ensure({ email, externalId }) + const refreshToken = AuthService.createRefreshToken(user) + + res.cookie('refreshToken', refreshToken, refreshCookieOptions) + res.status(200).json(new GenericResponse('Login successful')) + } catch (err) { + next(err) + } +} + +export default { + callback, +} diff --git a/src/controller/login.saml.controller.ts b/src/controller/login.saml.controller.ts new file mode 100644 index 00000000..d8f9d90e --- /dev/null +++ b/src/controller/login.saml.controller.ts @@ -0,0 +1,46 @@ +import { Request, Response, NextFunction } from 'express' +import { User } from 'devu-shared-modules' + +import environment from '../environment' + +import UserService from '../services/user.service' +import AuthService from '../services/auth.service' + +import { samlStrategy } from '../utils/passport/saml.passport' +import { refreshCookieOptions } from '../utils/cookie.utils' + +export async function callback(req: Request, res: Response, next: NextFunction) { + try { + const samlUser = req.user as User + + const { user } = await UserService.ensure(samlUser) + + const refreshToken = AuthService.createRefreshToken(user) + + res.cookie('refreshToken', refreshToken, refreshCookieOptions) + res.redirect(environment.clientUrl) + } catch (err) { + next(err) + } +} + +export async function generateMetadata(req: Request, res: Response, next: NextFunction) { + try { + res + .type('application/xml') + .status(200) + .send( + samlStrategy.generateServiceProviderMetadata( + environment.providers.saml.encryption.certificate, + environment.providers.saml.signing.certificate + ) + ) + } catch (err) { + next(err) + } +} + +export default { + callback, + generateMetadata, +} diff --git a/src/controller/tests/login.controller.test.ts b/src/controller/tests/login.controller.test.ts new file mode 100644 index 00000000..9f2ad43b --- /dev/null +++ b/src/controller/tests/login.controller.test.ts @@ -0,0 +1,102 @@ +import { Token } from 'devu-shared-modules' + +import controller from '../login.controller' + +import UserModel from '../../model/users.model' + +import UserService from '../../services/user.service' +import AuthService from '../../services/auth.service' +import ProviderService from '../../services/provider.service' + +import Testing from '../../utils/testing.utils' +import { Unauthorized } from '../../utils/apiResponse.utils' + +// Testing Globals +let req: any +let res: any +let next: any + +let mockedUser: UserModel +let expectedAccessToken: Token = { accessToken: 'encodedAccessToken' } +let expectedError = new Error('Some error') + +describe('LoginController', () => { + beforeEach(() => { + req = Testing.fakeRequest() + res = Testing.fakeResponse() + next = Testing.fakeNext() + + req.refreshUser = { userId: 1, isRefreshToken: true } + + mockedUser = Testing.generateTypeOrm(UserModel) + }) + + describe('GET - /login', () => { + describe('200 - Ok', () => { + beforeEach(async () => { + UserService.retrieve = jest.fn().mockImplementation(() => Promise.resolve(mockedUser)) + AuthService.createAccessToken = jest.fn().mockImplementation(() => expectedAccessToken.accessToken) + + await controller.login(req, res, next) + }) + + test('Returns access token', () => expect(res.json).toBeCalledWith(expectedAccessToken)) + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) + }) + + describe('400 - Bad Request', () => { + test('Next called with err', async () => { + UserService.retrieve = jest.fn().mockImplementation(() => Promise.reject(expectedError)) + await controller.login(req, res, next) + + expect(next).toBeCalledWith(expectedError) + }) + }) + + describe('401 - Unauthorized', () => { + test('Without decoded refresh token', async () => { + req.refreshUser = undefined + await controller.login(req, res, next) + + expect(res.status).toBeCalledWith(401) + expect(res.json).toBeCalledWith(Unauthorized) + }) + test('Malformed (missing userId) refreshToken', async () => { + delete req.refreshUser.userId + await controller.login(req, res, next) + + expect(res.status).toBeCalledWith(401) + expect(res.json).toBeCalledWith(Unauthorized) + }) + test('Unknown userId returned on refresh token', async () => { + UserService.retrieve = jest.fn().mockImplementation(() => Promise.resolve(undefined)) + await controller.login(req, res, next) + + expect(res.status).toBeCalledWith(401) + expect(res.json).toBeCalledWith(Unauthorized) + }) + }) + }) + + describe('GET - /login/providers', () => { + test('Returns providers', async () => { + const expectedProviders = ['Mock Provider'] + + ProviderService.get = jest.fn().mockImplementation(() => expectedProviders) + await controller.getProviders(req, res, next) + + expect(res.status).toBeCalledWith(200) + expect(res.json).toBeCalledWith(expectedProviders) + }) + + test('Next called with err', async () => { + ProviderService.get = jest.fn().mockImplementation(() => { + throw expectedError + }) + + await controller.getProviders(req, res, next) + + expect(next).toBeCalledWith(expectedError) + }) + }) +}) diff --git a/src/controller/tests/login.developer.controller.test.ts b/src/controller/tests/login.developer.controller.test.ts new file mode 100644 index 00000000..5caf7e0a --- /dev/null +++ b/src/controller/tests/login.developer.controller.test.ts @@ -0,0 +1,70 @@ +import controller from '../login.developer.controller' + +import UserModel from '../../model/users.model' + +import UserService from '../../services/user.service' +import AuthService from '../../services/auth.service' + +import Testing from '../../utils/testing.utils' +import { refreshCookieOptions } from '../../utils/cookie.utils' + +// Testing Globals +let req: any +let res: any +let next: any + +let mockedUser: UserModel +let expectedResult: { user: UserModel } +let refreshToken: string = 'pretendRefreshToken' +let expectedError = new Error('Some error') + +describe('LoginDeveloperController', () => { + beforeEach(() => { + req = Testing.fakeRequest() + res = Testing.fakeResponse() + next = Testing.fakeNext() + + mockedUser = Testing.generateTypeOrm(UserModel) + expectedResult = { user: mockedUser } + }) + + describe('POST - /login/developer/callback', () => { + beforeEach(() => { + UserService.ensure = jest.fn().mockImplementation(() => Promise.resolve(expectedResult)) + AuthService.createRefreshToken = jest.fn().mockImplementation(() => refreshToken) + }) + + describe('200 - Ok', () => { + beforeEach(async () => { + await controller.callback(req, res, next) + }) + + test('Returns refreshToken as cookie', () => + expect(res.cookie).toBeCalledWith('refreshToken', refreshToken, refreshCookieOptions)) + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) + test('Generic response returned ', () => expect(res.json).toBeCalledWith({ message: 'Login successful' })) + }) + + describe('400 - Bad Request', () => { + test('Next called with err if user service failes', async () => { + UserService.ensure = jest.fn().mockImplementation(() => { + throw expectedError + }) + + await controller.callback(req, res, next) + + expect(next).toHaveBeenCalledWith(expectedError) + }) + + test('Next called with err if auth service failes', async () => { + AuthService.createRefreshToken = jest.fn().mockImplementation(() => { + throw expectedError + }) + + await controller.callback(req, res, next) + + expect(next).toHaveBeenCalledWith(expectedError) + }) + }) + }) +}) diff --git a/src/controller/tests/login.saml.controller.test.ts b/src/controller/tests/login.saml.controller.test.ts new file mode 100644 index 00000000..45528824 --- /dev/null +++ b/src/controller/tests/login.saml.controller.test.ts @@ -0,0 +1,99 @@ +import controller from '../login.saml.controller' + +import UserModel from '../../model/users.model' + +import UserService from '../../services/user.service' +import AuthService from '../../services/auth.service' + +import Testing from '../../utils/testing.utils' +import { refreshCookieOptions } from '../../utils/cookie.utils' +import generateSamlStrategy, { samlStrategy } from '../../utils/passport/saml.passport' + +// Testing Globals +let req: any +let res: any +let next: any + +let mockedUser: UserModel +let expectedResult: { user: UserModel } +let expectedXml = '

Fake XML

' +let refreshToken = 'pretendRefreshToken' +let expectedError = new Error('Some error') + +describe('LoginSamlController', () => { + beforeEach(() => { + req = Testing.fakeRequest() + res = Testing.fakeResponse() + next = Testing.fakeNext() + + req.user = { email: 'samlresponse@mail.com' } + + mockedUser = Testing.generateTypeOrm(UserModel) + expectedResult = { user: mockedUser } + }) + + describe('POST - /login/saml/callback', () => { + beforeEach(() => { + UserService.ensure = jest.fn().mockImplementation(() => Promise.resolve(expectedResult)) + AuthService.createRefreshToken = jest.fn().mockImplementation(() => refreshToken) + }) + + describe('200 - Ok', () => { + beforeEach(async () => { + await controller.callback(req, res, next) + }) + + test('Returns refreshToken as cookie', () => + expect(res.cookie).toBeCalledWith('refreshToken', refreshToken, refreshCookieOptions)) + test('Redirect to be called ', () => expect(res.redirect).toHaveBeenCalled()) + }) + + describe('400 - Bad Request', () => { + test('Next called with err if user service failes', async () => { + UserService.ensure = jest.fn().mockImplementation(() => { + throw expectedError + }) + + await controller.callback(req, res, next) + + expect(next).toHaveBeenCalledWith(expectedError) + }) + + test('Next called with err if auth service failes', async () => { + AuthService.createRefreshToken = jest.fn().mockImplementation(() => { + throw expectedError + }) + + await controller.callback(req, res, next) + + expect(next).toHaveBeenCalledWith(expectedError) + }) + }) + }) + + describe('GET - /login/saml/metadata', () => { + beforeEach(generateSamlStrategy) // initializes saml strategy + + describe('200 - Ok', () => { + beforeEach(async () => { + samlStrategy.generateServiceProviderMetadata = jest.fn().mockImplementation(() => expectedXml) + await controller.generateMetadata(req, res, next) + }) + + test('200 Status returned', () => expect(res.status).toHaveBeenCalledWith(200)) + test('Response matches XML', () => expect(res.send).toHaveBeenCalledWith(expectedXml)) + }) + + describe('400 - Bad Request', () => { + test('Next called with expected error ', async () => { + samlStrategy.generateServiceProviderMetadata = jest.fn().mockImplementation(() => { + throw expectedError + }) + + await controller.generateMetadata(req, res, next) + + expect(next).toHaveBeenCalledWith(expectedError) + }) + }) + }) +}) diff --git a/src/controller/tests/users.controller.test.ts b/src/controller/tests/users.controller.test.ts index 31def3c2..b62b349d 100644 --- a/src/controller/tests/users.controller.test.ts +++ b/src/controller/tests/users.controller.test.ts @@ -1,19 +1,25 @@ import { UpdateResult } from 'typeorm' +import { User } from 'devu-shared-modules' + import controller from '../users.controller' -import User from '../../model/users.model' +import UserModel from '../../model/users.model' import UserService from '../../services/user.service' +import { serialize } from '../../utils/serializer/users.serializer' + import Testing from '../../utils/testing.utils' import { GenericResponse, NotFound, Updated } from '../../utils/apiResponse.utils' // Testing Globals -let req -let res -let next +let req: any +let res: any +let next: any +let mockedUsers: UserModel[] +let mockedUser: UserModel let expectedResults: User[] let expectedResult: User let expectedError: Error @@ -26,8 +32,11 @@ describe('UserController', () => { res = Testing.fakeResponse() next = Testing.fakeNext() - expectedResults = Testing.generateTypeOrmArray(User, 3) - expectedResult = Testing.generateTypeOrm(User) + mockedUsers = Testing.generateTypeOrmArray(UserModel, 3) + mockedUser = Testing.generateTypeOrm(UserModel) + + expectedResults = mockedUsers.map(serialize) + expectedResult = serialize(mockedUser) expectedError = new Error('Expected Error') expectedDbResult = {} as UpdateResult @@ -36,13 +45,12 @@ describe('UserController', () => { describe('GET - /users', () => { describe('200 - Ok', () => { beforeEach(async () => { - UserService.list = jest.fn().mockImplementation(() => Promise.resolve(expectedResults)) + UserService.list = jest.fn().mockImplementation(() => Promise.resolve(mockedUsers)) await controller.get(req, res, next) // what we're testing }) - test('Returns list of users', () => expect(req.users).toEqual(expectedResults)) - test('Status code is 200', () => expect(req.statusCode).toEqual(200)) - test('Next called empty', () => expect(next).toBeCalledWith()) + test('Returns list of users', () => expect(res.json).toBeCalledWith(expectedResults)) + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) }) describe('400 - Bad request', () => { @@ -63,13 +71,12 @@ describe('UserController', () => { describe('GET - /users/:id', () => { describe('200 - Ok', () => { beforeEach(async () => { - UserService.retrieve = jest.fn().mockImplementation(() => Promise.resolve(expectedResult)) + UserService.retrieve = jest.fn().mockImplementation(() => Promise.resolve(mockedUser)) await controller.detail(req, res, next) }) - test('Returns expected user', () => expect(req.user).toEqual(expectedResult)) - test('Status code is 200', () => expect(req.statusCode).toEqual(200)) - test('Next called empty', () => expect(next).toBeCalledWith()) + test('Returns expected user', () => expect(res.json).toBeCalledWith(expectedResult)) + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) }) describe('404 - Not Found', () => { @@ -101,13 +108,12 @@ describe('UserController', () => { describe('POST - /users/', () => { describe('201 - Created', () => { beforeEach(async () => { - UserService.create = jest.fn().mockImplementation(() => Promise.resolve(expectedResult)) + UserService.create = jest.fn().mockImplementation(() => Promise.resolve(mockedUser)) await controller.post(req, res, next) }) - test('Returns expected user', () => expect(req.user).toEqual(expectedResult)) - test('Status code is 201', () => expect(req.statusCode).toEqual(201)) - test('Next called empty', () => expect(next).toBeCalledWith()) + test('Returns expected user', () => expect(res.json).toBeCalledWith(expectedResult)) + test('Status code is 201', () => expect(res.status).toBeCalledWith(201)) }) describe('400 - Bad Reqeust', () => { diff --git a/src/controller/users.controller.ts b/src/controller/users.controller.ts index 3ccaa3ea..7bfa13b8 100644 --- a/src/controller/users.controller.ts +++ b/src/controller/users.controller.ts @@ -4,12 +4,14 @@ import UserService from '../services/user.service' import { GenericResponse, NotFound, Updated } from '../utils/apiResponse.utils' +import { serialize } from '../utils/serializer/users.serializer' + export async function get(req: Request, res: Response, next: NextFunction) { try { - req.users = await UserService.list() - req.statusCode = 200 + const users = await UserService.list() + const response = users.map(serialize) - next() + res.status(200).json(response) } catch (err) { next(err) } @@ -22,10 +24,9 @@ export async function detail(req: Request, res: Response, next: NextFunction) { if (!user) return res.status(404).json(NotFound) - req.user = user - req.statusCode = 200 + const response = serialize(user) - next() + res.status(200).json(response) } catch (err) { next(err) } @@ -33,10 +34,10 @@ export async function detail(req: Request, res: Response, next: NextFunction) { export async function post(req: Request, res: Response, next: NextFunction) { try { - req.user = await UserService.create(req.body) - req.statusCode = 201 + const user = await UserService.create(req.body) + const response = serialize(user) - next() + res.status(201).json(response) } catch (err) { res.status(400).json(new GenericResponse(err.message)) } diff --git a/src/environment.ts b/src/environment.ts index 5739fde2..baa2bec1 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -1,8 +1,75 @@ -export default { - port: process.env.PORT || 3001, - dbHost: process.env.DB_HOST || 'localhost', - dbUsername: process.env.DB_USERNAME || 'typescript_user', - dbPassword: process.env.DB_PASSWORD || 'password', - database: process.env.DATABASE || 'typescript_api', - logDB: process.env.LOG_DB !== undefined, // logs all sql commands for gut/fact checking endpoints +import config from 'config' + +type Keys = { + privateKey: string + publicKey: string } + +type Certificate = { + certificate: string + privateKey: string +} + +type Saml = { + name: string + enabled: boolean + attributeMap: Record + entryPoint: string + idpCerts: string[] + encryption: Certificate + signing: Certificate + acceptedClockSkewSeconds: number +} + +type DevAuth = { + enabled: boolean +} + +type Providers = { + saml: Saml + devAuth: DevAuth +} + +function load(path: string): any { + if (!config.has(path)) return false + + return config.get(path) +} + +const scheme = (load('api.scheme') || 'http') as string +const host = (load('api.host') || 'localhost') as string +const port = (process.env.PORT || load('api.port') || 3001) as number + +const apiUrl = `${scheme}://${host}:${port}` + +// prettier-ignore +const refreshTokenExp = load('auth.jwt.refreshTokenValiditySeconds') || 864000 +const accessTokenExp = load('auth.jwt.accessTokenValiditySeconds') || 600 +const refreshTokenBuffer = load('auth.jwt.refreshTokenExpirationBufferSeconds') || 864000 + +const environment = { + port, + apiUrl, + clientUrl: (process.env.CLIENT_URL || load('api.clientUrl') || 'http://localhost:9000') as string, + + // Database settings + dbHost: (load('database.host') || 'localhost') as string, + dbUsername: (load('database.username') || 'typescript_user') as string, + dbPassword: (load('database.password') || 'password') as string, + database: (load('database.name') || 'typescript_api') as string, + + // Logging + logDB: (process.env.LOG_DB !== undefined || load('logging.db')) as boolean, // logs all sql commands for gut/fact checking endpoints + + // Auth Settings + activeKeyId: config.get('auth.jwt.activeKeyId') as string, + keys: config.get('auth.jwt.keys') as Record, + accessTokenValiditySeconds: parseInt(accessTokenExp), + refreshTokenValiditySeconds: parseInt(refreshTokenExp), + refreshTokenExpirationBufferSeconds: parseInt(refreshTokenBuffer), + + // BE CAREFUL WITH PROVIDERS - THEY'RE NOT TOTALLY TYPE SAFE UNLESS PROPERLY CONFIGURED + providers: config.get('auth.providers') as Providers, +} + +export default environment diff --git a/src/index.ts b/src/index.ts index 999652ae..3e9c041a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,9 @@ import cors from 'cors' import helmet from 'helmet' import morgan from 'morgan' import { createConnection } from 'typeorm' +import cookieParser from 'cookie-parser' + +import passport from 'passport' import environment from './environment' import connectionInfo from './database' @@ -15,19 +18,25 @@ import connectionInfo from './database' import router from './router' import errorHandler from './middleware/errorHandler.middleware' +// Authentication Handlers +import './utils/passport.utils' + const app = express() createConnection(connectionInfo) - .then(connection => { + .then(_connection => { app.use(helmet()) + app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json()) - app.use(cors()) + app.use(cookieParser()) + app.use(cors({ origin: environment.clientUrl, credentials: true })) app.use(morgan('combined')) + app.use(passport.initialize()) // Middleware; app.use('/', router) app.use(errorHandler) - app.listen(environment.port, () => console.log(`API listenting at port - ${environment.port}`)) + app.listen(environment.port, () => console.log(`API listening at port - ${environment.port}`)) }) .catch(err => console.log('TypeORM connection error:', err)) diff --git a/src/middleware/auth.middleware.ts b/src/middleware/auth.middleware.ts new file mode 100644 index 00000000..d62830ac --- /dev/null +++ b/src/middleware/auth.middleware.ts @@ -0,0 +1,86 @@ +import passport from 'passport' +import { Request, Response, NextFunction } from 'express' + +import environment from '../environment' + +import { AccessToken, RefreshToken } from 'devu-shared-modules' + +import AuthService from '../services/auth.service' + +import { GenericResponse, Unauthorized } from '../utils/apiResponse.utils' + +function checkAuth(req: Request): [TokenType | null, GenericResponse | null] { + const authorization = req.headers.authorization + + if (!authorization) return [null, new GenericResponse('Missing authentication headers')] + + const [type, token] = authorization.split(' ') + + if (type !== 'Bearer') return [null, new GenericResponse('Missing Bearer in authentication header')] + if (!token) return [null, Unauthorized] + + const deserializedToken = AuthService.validateJwt(token) + + if (!deserializedToken) return [null, Unauthorized] + + return [deserializedToken, null] +} + +export async function isAuthorized(req: Request, res: Response, next: NextFunction) { + const [currentUser, error] = checkAuth(req) + + if (!currentUser) return res.status(401).json(error) + + req.currentUser = currentUser + + next() +} + +export async function isValidRefreshToken(req: Request, res: Response, next: NextFunction) { + // If authorization header exists DON'T CHECK COOKIE AT ALL + if (req.headers.authorization) { + const [refreshToken, error] = checkAuth(req) + + if (!refreshToken) return res.status(401).json(error) + // Because the refresh token and access token are signed the same way the access token + // would be valid up to here. If the token isn't a refresh token kick back a 401 + if (!refreshToken.isRefreshToken) return res.status(401).json(new GenericResponse('Not a refresh token')) + + req.refreshUser = refreshToken + + return next() + } + + // Check cookie + const { refreshToken = '' } = req.cookies + + const deserializedToken = AuthService.validateJwt(refreshToken) + + if (!deserializedToken) return res.status(401).json(Unauthorized) + + req.refreshUser = deserializedToken + + next() +} + +export async function isRefreshNearingExpiration(req: Request, res: Response, next: NextFunction) { + if (!req.refreshUser?.exp) return res.status(401).json(Unauthorized) + + const nowEpochTime = Math.round(Date.now() / 1000) + + // If the difference in time between expiration and now is larger than the buffer time, continue + // aka if our refresh token is outside of our buffer window, continue. Otherwise tell them + // their token is nearing expiration + if (environment.refreshTokenExpirationBufferSeconds > req.refreshUser.exp - nowEpochTime) + res.setHeader('x-nearing-expiration', 'true') + + next() +} + +export const saml = passport.authenticate('saml', { session: false }) + +export default { + isAuthorized, + isValidRefreshToken, + isRefreshNearingExpiration, +} diff --git a/src/middleware/serializer/tests/users.serializer.test.ts b/src/middleware/serializer/tests/users.serializer.test.ts deleted file mode 100644 index 26cdd721..00000000 --- a/src/middleware/serializer/tests/users.serializer.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import serializer from '../users.serializer' - -import User from '../../../model/users.model' - -import Testing from '../../../utils/testing.utils' -import { Unknown } from '../../../utils/apiResponse.utils' - -// Testing Globals -let req -let res -let next - -let expectedResults: User[] -let expectedResult: User -let expectedStatusCode: number - -describe('User Serializer', () => { - beforeEach(() => { - req = Testing.fakeRequest() - res = Testing.fakeResponse() - next = Testing.fakeNext() - - expectedResults = Testing.generateTypeOrmArray(User, 3) - expectedResult = Testing.generateTypeOrm(User) - - expectedResult.createdAt = new Date() - expectedResult.updatedAt = new Date() - - expectedStatusCode = 200 - }) - - describe('Missing user and users', () => { - // by default fakeReq has no user || users so we're good to test with the defualts - beforeEach(() => serializer(req, res, next)) - - test('400 without user or users', () => expect(res.status).toBeCalledWith(400)) - test('Unknown request message without user or users', () => expect(res.json).toBeCalledWith(Unknown)) - test('Next is not called', () => expect(next).toBeCalledTimes(0)) - }) - - describe('Serializing User list (users)', () => { - beforeEach(() => { - req.users = expectedResults // user list - req.statusCode = expectedStatusCode - serializer(req, res, next) - }) - - test('Status code from req', () => expect(res.status).toBeCalledWith(expectedStatusCode)) - test('CreatedAt and ModifiedAt are ISO strings for all users', () => { - expect(res.json).toBeCalledTimes(1) - - const response = res.json.mock.calls[0][0] - - expect(Array.isArray(response)).toBe(true) - - for (const index in response) { - const expectedUser = expectedResults[index] - const serializedUser = response[index] - - expect(serializedUser.updatedAt).toEqual(expectedUser.updatedAt.toISOString()) - expect(serializedUser.createdAt).toEqual(expectedUser.updatedAt.toISOString()) - } - }) - }) - - describe('Serializing User (user)', () => { - beforeEach(() => { - req.user = expectedResult // user list - req.statusCode = expectedStatusCode - serializer(req, res, next) - }) - - test('Status code from req', () => expect(res.status).toBeCalledWith(expectedStatusCode)) - test('CreatedAt and ModifiedAt are ISO strings', () => { - expect(res.json).toBeCalledTimes(1) - - const response = res.json.mock.calls[0][0] - - expect(response).toBeDefined() - expect(response.updatedAt).toEqual(expectedResult.updatedAt.toISOString()) - expect(response.createdAt).toEqual(expectedResult.updatedAt.toISOString()) - }) - }) -}) diff --git a/src/middleware/serializer/users.serializer.ts b/src/middleware/serializer/users.serializer.ts deleted file mode 100644 index b90cb9c7..00000000 --- a/src/middleware/serializer/users.serializer.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Request, Response, NextFunction } from 'express' - -import { User as UserType } from 'devu-shared-modules' - -import User from '../../model/users.model' - -import { Unknown } from '../../utils/apiResponse.utils' - -export default function (req: Request, res: Response, next: NextFunction) { - // No data applied at the controller level - if (!req.user && !req.users) return res.status(400).json(Unknown) - - const response = req.user ? serialize(req.user) : req.users.map(serialize) - - res.status(req.statusCode).json(response) -} - -function serialize(user: User): UserType { - return { - id: user.id, - schoolId: user.schoolId, - email: user.email, - createdAt: user.createdAt.toISOString(), - updatedAt: user.updatedAt.toISOString(), - preferredName: user.preferredName, - } -} diff --git a/src/middleware/tests/auth.middleware.test.ts b/src/middleware/tests/auth.middleware.test.ts new file mode 100644 index 00000000..59512584 --- /dev/null +++ b/src/middleware/tests/auth.middleware.test.ts @@ -0,0 +1,150 @@ +import { AccessToken, RefreshToken } from 'devu-shared-modules' + +import environment from '../../environment' + +import { isAuthorized, isValidRefreshToken, isRefreshNearingExpiration } from '../auth.middleware' + +import AuthService from '../../services/auth.service' + +import Testing from '../../utils/testing.utils' +import { Unauthorized } from '../../utils/apiResponse.utils' + +// Testing Globals +let req: any +let res: any +let next: any + +let expectedAccessToken: AccessToken = { userId: 1, email: '' } +let expectedRefreshToken: RefreshToken = { userId: 1, isRefreshToken: true } +// let expectedError = new Error('Some error') + +describe('AuthMiddleware', () => { + beforeEach(() => { + req = Testing.fakeRequest() + res = Testing.fakeResponse() + next = Testing.fakeNext() + + req.headers.authorization = 'Bearer heehee.nottoken' + }) + + describe('isAuthenticated', () => { + describe('Authorization Successful', () => { + beforeEach(async () => { + AuthService.validateJwt = jest.fn().mockImplementation(() => expectedAccessToken) + + await isAuthorized(req, res, next) + }) + + test('Expect access token to be added to req', () => expect(req.currentUser).toEqual(expectedAccessToken)) + + test('Expect next to be called on successful token validation', async () => expect(next).toHaveBeenCalled()) + test('Next is called', () => expect(next).toHaveBeenCalledTimes(1)) + }) + + describe('Authorization Failure', () => { + test('Missing authroization header', async () => { + delete req.headers.authorization + await isAuthorized(req, res, next) + + expect(res.status).toBeCalledWith(401) + expect(next).toHaveBeenCalledTimes(0) + }) + + test('Missing Bearer', async () => { + req.headers.authorization = 'NotBearer and.a.fake.token' + await isAuthorized(req, res, next) + + expect(res.status).toBeCalledWith(401) + expect(next).toHaveBeenCalledTimes(0) + }) + + test('Missing Token', async () => { + req.headers.authorization = 'Bearer' // missing token + await isAuthorized(req, res, next) + + expect(res.status).toBeCalledWith(401) + expect(next).toHaveBeenCalledTimes(0) + }) + test('Invalid token', async () => { + AuthService.validateJwt = jest.fn().mockImplementation(() => null) + await isAuthorized(req, res, next) + + expect(res.status).toHaveBeenCalledWith(401) + expect(next).toHaveBeenCalledTimes(0) + }) + }) + }) + + describe('isValidRefreshToken', () => { + describe('Validate via cookies', () => { + beforeEach(() => (req.headers.authorization = undefined)) // no header on cookies requests + describe('Authorization Successful', () => { + beforeEach(async () => { + AuthService.validateJwt = jest.fn().mockImplementation(() => expectedRefreshToken) + await isValidRefreshToken(req, res, next) + }) + + test('Refresh token added to req', () => expect(req.refreshUser).toEqual(expectedRefreshToken)) + test('Next called with no parameters', () => expect(next).toBeCalledWith()) + }) + + describe('Authorization Failure', () => { + beforeEach(async () => { + AuthService.validateJwt = jest.fn().mockImplementation(() => null) + await isValidRefreshToken(req, res, next) + }) + + test('Status set to 401', () => expect(res.status).toHaveBeenCalledWith(401)) + test('Unauthorized returned as response', () => expect(res.json).toHaveBeenCalledWith(Unauthorized)) + test('Next is not called', () => expect(next).toHaveBeenCalledTimes(0)) + }) + }) + + describe('Validate via header', () => { + describe('Authorization Successful', () => { + beforeEach(async () => { + AuthService.validateJwt = jest.fn().mockImplementation(() => expectedRefreshToken) + await isValidRefreshToken(req, res, next) + }) + + test('Refresh token added to req', () => expect(req.refreshUser).toEqual(expectedRefreshToken)) + test('Next called with no parameters', () => expect(next).toBeCalledWith()) + }) + + describe('Authorization Failure', () => { + beforeEach(async () => { + AuthService.validateJwt = jest.fn().mockImplementation(() => null) + await isValidRefreshToken(req, res, next) + }) + + test('Status set to 401', () => expect(res.status).toHaveBeenCalledWith(401)) + test('Unauthorized returned as response', () => expect(res.json).toHaveBeenCalledWith(Unauthorized)) + test('Next is not called', () => expect(next).toHaveBeenCalledTimes(0)) + }) + }) + }) + + describe('isRefreshNearingExpiration', () => { + beforeEach(() => { + environment.refreshTokenExpirationBufferSeconds = 20 // seconds + }) + test('Expiration within buffer acts as expired', async () => { + const nowInEpoch = Math.round(Date.now() / 1000) + req.refreshUser = { exp: nowInEpoch + 10 } // expires 10 seconds from now + + await isRefreshNearingExpiration(req, res, next) + + expect(res.setHeader).toBeCalledWith('x-nearing-expiration', 'true') + expect(next).toBeCalledWith() + }) + + test('Token does not act as if expired when expiration is outside of buffer window', async () => { + const nowInEpoch = Math.round(Date.now() / 1000) + req.refreshUser = { exp: nowInEpoch + 30 } // expires 30 seconds from now + + await isRefreshNearingExpiration(req, res, next) + + expect(next).toBeCalledWith() + }) + }) +}) diff --git a/src/middleware/tests/errorHandler.middleware.test.ts b/src/middleware/tests/errorHandler.middleware.test.ts index a05e30a4..09b09998 100644 --- a/src/middleware/tests/errorHandler.middleware.test.ts +++ b/src/middleware/tests/errorHandler.middleware.test.ts @@ -5,21 +5,22 @@ import globalErrorHandler from '../errorHandler.middleware' import { GenericResponse, Unknown, Unimplemented } from '../../utils/apiResponse.utils' // Testing Globals -let req -let res -let next +let req: any +let res: any +let next: any let expectedErrorMessage = 'Expected Message' describe('Global Error Handler', () => { - describe('Missing error', () => { - beforeEach(() => { - req = Testing.fakeRequest() - res = Testing.fakeResponse() - next = Testing.fakeNext() + beforeEach(() => { + req = Testing.fakeRequest() + res = Testing.fakeResponse() + next = Testing.fakeNext() + }) - globalErrorHandler(null, req, res, next) - }) + describe('Missing error', () => { + //@ts-ignore - if someone throws a non error 😬 + beforeEach(() => globalErrorHandler(null, req, res, next)) test('Responds with 400', () => expect(res.status).toBeCalledWith(400)) test('Responds with unknown without error', () => expect(res.json).toBeCalledWith(Unknown)) diff --git a/src/middleware/validator/generic.validator.ts b/src/middleware/validator/generic.validator.ts index f3408d8e..31ff7c54 100644 --- a/src/middleware/validator/generic.validator.ts +++ b/src/middleware/validator/generic.validator.ts @@ -6,7 +6,7 @@ import { GenericResponse } from '../../utils/apiResponse.utils' export function validate(req: Request, res: Response, next: NextFunction) { const errors = validationResult(req) - if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }) + if (!errors.isEmpty()) return res.status(400).json(errors.array()) next() } diff --git a/src/middleware/validator/login.validator.ts b/src/middleware/validator/login.validator.ts new file mode 100644 index 00000000..662376f9 --- /dev/null +++ b/src/middleware/validator/login.validator.ts @@ -0,0 +1,34 @@ +import { Request, Response, NextFunction } from 'express' +import { check, validationResult } from 'express-validator' +import { User } from 'devu-shared-modules' + +import validate from './generic.validator' +import environment from '../../environment' + +const email = check('email').isString().trim().isEmail() +const externalId = check('externalId').isString().trim() + +export const validateDeveloper = [email, externalId, validate] + +function forcePassportAuthToBody(req: Request, res: Response, next: NextFunction) { + const callbackUser = req.user as User + + // express-validator only checks the body/headers/cookies/params/query so we have to set passports info + // onto the body (or the others listed) to use express-validator validation + req.body.email = callbackUser.email + req.body.externalId = callbackUser.externalId + + next() +} + +function callbackValidator(req: Request, res: Response, next: NextFunction) { + const errors = validationResult(req) + + if (errors.isEmpty()) return next() + + return res.redirect( + `${environment.clientUrl}/authProviderError?message=Invalid email or externalId provided by auth provider` + ) +} + +export const authCallbackValidator = [forcePassportAuthToBody, email, externalId, callbackValidator] diff --git a/src/middleware/validator/users.validator.ts b/src/middleware/validator/users.validator.ts index afde1180..4abecd65 100644 --- a/src/middleware/validator/users.validator.ts +++ b/src/middleware/validator/users.validator.ts @@ -4,8 +4,8 @@ import validate from './generic.validator' const email = check('email').isString().trim().isEmail() const preferredName = check('preferredName').isString().trim().isLength({ max: 128 }).optional({ nullable: true }) -const schoolId = check('schoolId').isString().trim().isLength({ max: 128 }).optional({ nullable: true }) +const externalId = check('externalId').isString().trim().isLength({ max: 128 }) -const validator = [email, preferredName, schoolId, validate] +const validator = [email, preferredName, externalId, validate] export default validator diff --git a/src/migration/1623375449310-tightenUpUserModel.ts b/src/migration/1623375449310-tightenUpUserModel.ts new file mode 100644 index 00000000..4e231e32 --- /dev/null +++ b/src/migration/1623375449310-tightenUpUserModel.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class tightenUpUserModel1623375449310 implements MigrationInterface { + name = 'tightenUpUserModel1623375449310' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "schoolId"`) + await queryRunner.query(`ALTER TABLE "users" ADD "externalId" character varying(320) NOT NULL`) + await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "unique_user_externaId" UNIQUE ("externalId")`) + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "email"`) + await queryRunner.query(`ALTER TABLE "users" ADD "email" character varying(320) NOT NULL`) + await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "unique_user_email" UNIQUE ("email")`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "unique_user_email"`) + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "email"`) + await queryRunner.query(`ALTER TABLE "users" ADD "email" character varying(128) NOT NULL`) + await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "unique_user_externaId"`) + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "externalId"`) + await queryRunner.query(`ALTER TABLE "users" ADD "schoolId" character varying(128)`) + } +} diff --git a/src/migration/1623389391024-renameUserColumns.ts b/src/migration/1623389391024-renameUserColumns.ts new file mode 100644 index 00000000..a5adf533 --- /dev/null +++ b/src/migration/1623389391024-renameUserColumns.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class renameUserColumns1623389391024 implements MigrationInterface { + name = 'renameUserColumns1623389391024' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "createdAt" TO "created_at"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "updatedAt" TO "updated_at"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "deletedAt" TO "deleted_at"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "preferredName" TO "preferred_name"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "externalId" TO "external_id"`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "created_at" TO "createdAt"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "updated_at" TO "updatedAt"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "deleted_at" TO "deletedAt"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "preferred_name" TO "preferredName"`) + await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "external_id" TO "externalId"`) + } +} diff --git a/src/model/index.ts b/src/model/index.ts index dd2266c4..e28faf5c 100644 --- a/src/model/index.ts +++ b/src/model/index.ts @@ -1,5 +1,5 @@ -import User from './users.model' +import UserModel from './users.model' -type Models = User +type Models = UserModel export default Models diff --git a/src/model/users.model.ts b/src/model/users.model.ts index bace9bf2..afb65850 100644 --- a/src/model/users.model.ts +++ b/src/model/users.model.ts @@ -1,25 +1,25 @@ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm' @Entity('users') -export default class User { +export default class UserModel { @PrimaryGeneratedColumn() id: number - @CreateDateColumn() + @CreateDateColumn({ name: 'created_at' }) createdAt: Date - @UpdateDateColumn() + @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date - @DeleteDateColumn() + @DeleteDateColumn({ name: 'deleted_at' }) deletedAt?: Date - @Column({ length: 128 }) + @Column({ length: 320, unique: true, nullable: false }) email: string - @Column({ length: 128, nullable: true }) - schoolId: string + @Column({ name: 'external_id', length: 320, unique: true, nullable: false }) + externalId: string - @Column({ length: 128, nullable: true }) + @Column({ name: 'preferred_name', length: 128, nullable: true }) preferredName: string } diff --git a/src/router/index.ts b/src/router/index.ts index 5b025512..0d9d9900 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -3,15 +3,19 @@ import swaggerUi from 'swagger-ui-express' import swagger from '../utils/swagger.utils' -import status from './status.router' +import login from './login.router' import users from './users.router' +import status from './status.router' + +import { isAuthorized } from '../middleware/auth.middleware' import { NotFound } from '../utils/apiResponse.utils' const Router = express.Router() +Router.use('/login', login) +Router.use('/users', isAuthorized, users) Router.use('/status', status) -Router.use('/users', users) Router.use('/docs', swaggerUi.serve, swaggerUi.setup(swagger)) Router.use('/', (req: Request, res: Response, next: NextFunction) => res.status(404).send(NotFound)) diff --git a/src/router/login.developer.router.ts b/src/router/login.developer.router.ts new file mode 100644 index 00000000..7c96f07c --- /dev/null +++ b/src/router/login.developer.router.ts @@ -0,0 +1,17 @@ +import express from 'express' + +import controller from '../controller/login.developer.controller' + +import { validateDeveloper } from '../middleware/validator/login.validator' + +const Router = express.Router() + +/** + * @swagger + * /login/developer: + * post: + * summary: NOT IN PRODUCTION. Gives a way for developers to log in while developing locally via an externalId & email + */ +Router.post('/', validateDeveloper, controller.callback) + +export default Router diff --git a/src/router/login.router.ts b/src/router/login.router.ts new file mode 100644 index 00000000..fdd63f33 --- /dev/null +++ b/src/router/login.router.ts @@ -0,0 +1,38 @@ +import express from 'express' +import colors from 'colors' + +import environment from '../environment' + +import controller from '../controller/login.controller' + +import { isValidRefreshToken, isRefreshNearingExpiration } from '../middleware/auth.middleware' + +import SamlRouter from './login.saml.router' +import DeveloperRouter from './login.developer.router' + +const Router = express.Router() + +/** + * @swagger + * /login: + * get: + * summary: Gets access token by via refresh token (called on client bootstrap) + */ +Router.get('/', isValidRefreshToken, isRefreshNearingExpiration, controller.login) + +/** + * @swagger + * /login/providers: + * get: + * summary: Gets a list of available authentication providers + */ +Router.get('/providers', controller.getProviders) + +// Provider Routers +if (environment.providers.saml.enabled) Router.use('/saml', SamlRouter) +if (environment.providers.devAuth.enabled) { + console.log(colors.red.bold(`DEVELOPER AUTH ENABLED. IF YOU'RE SEEING THIS MESSAGE IN PRODUCTION, YOU SHOULD PANIC.`)) + Router.use('/developer', DeveloperRouter) +} + +export default Router diff --git a/src/router/login.saml.router.ts b/src/router/login.saml.router.ts new file mode 100644 index 00000000..5430b5ab --- /dev/null +++ b/src/router/login.saml.router.ts @@ -0,0 +1,36 @@ +// Libraries +import express from 'express' + +import controller from '../controller/login.saml.controller' + +import { saml } from '../middleware/auth.middleware' + +import { authCallbackValidator } from '../middleware/validator/login.validator' + +const Router = express.Router() + +/** + * @swagger + * /login/saml: + * get: + * summary: Redirects to external SAML auth server + */ +Router.get('/', saml) + +/** + * @swagger + * /login/saml/callback: + * post: + * summary: Handles successful SAML authentication and is called from SAML auth server + */ +Router.post('/callback', saml, authCallbackValidator, controller.callback) + +/** + * @swagger + * /login/saml/metadata: + * post: + * summary: Gets meta SAML information (usually accessed by SAML server) + */ +Router.get('/metadata', controller.generateMetadata) + +export default Router diff --git a/src/router/users.router.ts b/src/router/users.router.ts index 41a5dfb6..585c2be8 100644 --- a/src/router/users.router.ts +++ b/src/router/users.router.ts @@ -1,12 +1,8 @@ -// Libraries import express from 'express' -// Middleware import validator from '../middleware/validator/users.validator' -import serializer from '../middleware/serializer/users.serializer' import { idAsInt } from '../middleware/validator/generic.validator' -// Controller import UserController from '../controller/users.controller' const Router = express.Router() @@ -17,7 +13,7 @@ const Router = express.Router() * get: * summary: Retrieve a list of users */ -Router.get('/', UserController.get, serializer) +Router.get('/', UserController.get) /** * @swagger @@ -25,7 +21,7 @@ Router.get('/', UserController.get, serializer) * get: * summary: Retrieve a single user */ -Router.get('/:id', idAsInt, UserController.detail, serializer) +Router.get('/:id', idAsInt, UserController.detail) /** * @swagger @@ -33,7 +29,7 @@ Router.get('/:id', idAsInt, UserController.detail, serializer) * post: * summary: Create a user */ -Router.post('/', validator, UserController.post, serializer) +Router.post('/', validator, UserController.post) /** * @swagger diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts new file mode 100644 index 00000000..0e05299c --- /dev/null +++ b/src/services/auth.service.ts @@ -0,0 +1,62 @@ +import jws from 'jws' +import jwt, { SignOptions, VerifyOptions } from 'jsonwebtoken' + +import { AccessToken, RefreshToken } from 'devu-shared-modules' + +import environment from '../environment' + +import UserModel from '../model/users.model' + +const signingKey = environment.keys[environment.activeKeyId].privateKey + +function getVerificationKey(kid?: string) { + if (!kid || !environment.keys[kid]) throw new Error('Invalid key id') + + return environment.keys[kid].publicKey +} + +// TODO - Add jwtid to refresh tokens for revocation ability in the future +// or add rev_sig (hashed value of some fields that revoke tokens if any change) +const jwtOptions: SignOptions & VerifyOptions = { + issuer: 'devU-auth', + audience: ['devU-api', 'devU-client'], + keyid: environment.activeKeyId, +} + +function createToken(payload: AccessToken | RefreshToken, expiresIn: string) { + const token = jwt.sign(payload, signingKey, { + ...jwtOptions, + expiresIn, + algorithm: 'RS256', + subject: `${payload.userId}`, + }) + + return token +} + +export function createAccessToken(user: UserModel): string { + const payload: AccessToken = { userId: user.id, email: user.email } + return createToken(payload, `${environment.accessTokenValiditySeconds}s`) +} + +export function createRefreshToken(user: UserModel): string { + const payload: RefreshToken = { userId: user.id, isRefreshToken: true } + return createToken(payload, `${environment.refreshTokenValiditySeconds}s`) +} + +export function validateJwt(token: string): TokenType | null { + try { + const verificationKey = getVerificationKey(jws.decode(token).header.kid) + const payload: unknown = jwt.verify(token, verificationKey, { ...jwtOptions, algorithms: ['RS256'] }) + + return payload as TokenType + } catch (_err) { + return null + } +} + +export default { + createAccessToken, + createRefreshToken, + validateJwt, +} diff --git a/src/services/provider.service.ts b/src/services/provider.service.ts new file mode 100644 index 00000000..20548056 --- /dev/null +++ b/src/services/provider.service.ts @@ -0,0 +1,38 @@ +import { AuthProvider } from 'devu-shared-modules' + +import environment from '../environment' + +const DEV_AUTH_SKIP_PROVIDER: AuthProvider = { + name: 'Developer Auth', + route: '/login/developer', + description: 'A user will be created for you with your provided credentials, or sign you in the user already exists.', + method: 'post', + body: ['email', 'externalId'], +} + +const SAML_PROVIDER: AuthProvider = { + name: environment.providers.saml.name, + route: '/login/saml', + description: 'SAML Login', + method: 'get', +} + +const providers = new Array() + +if (environment.providers.devAuth.enabled) providers.push(DEV_AUTH_SKIP_PROVIDER) +if (environment.providers.saml.enabled) providers.push(SAML_PROVIDER) + +export function get() { + return providers +} + +export function validate(providerRoute: string) { + const providerRoutes = providers.map(p => p.route) + + return providerRoutes.includes(providerRoute) +} + +export default { + get, + validate, +} diff --git a/src/services/user.service.ts b/src/services/user.service.ts index a5394058..a0567826 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -1,30 +1,45 @@ -import { getRepository } from 'typeorm' +import { getRepository, IsNull } from 'typeorm' -import { User as UserType } from 'devu-shared-modules' +import UserModel from '../model/users.model' -import User from '../model/users.model' +import { User } from 'devu-shared-modules' -const connect = () => getRepository(User) +const connect = () => getRepository(UserModel) -export async function create(user: UserType) { +export async function create(user: User) { return await connect().save(user) } -export async function update(user: UserType) { - const { id, email, schoolId, preferredName } = user - return await connect().update(id, { email, schoolId, preferredName }) +export async function update(user: User) { + const { id, email, externalId, preferredName } = user + + if (!id) throw new Error('Missing Id') + + return await connect().update(id, { email, externalId, preferredName }) } export async function _delete(id: number) { - return await connect().softDelete({ id, deletedAt: null }) + return await connect().softDelete({ id, deletedAt: IsNull() }) } export async function retrieve(id: number) { - return await connect().findOne({ id, deletedAt: null }) + return await connect().findOne({ id, deletedAt: IsNull() }) } export async function list() { - return await connect().find({ deletedAt: null }) + return await connect().find({ deletedAt: IsNull() }) +} + +export async function ensure(userInfo: User) { + const { externalId, email } = userInfo + + const user = await connect().findOne({ externalId }) + + if (user) return { user, isNewUser: false } + + const newUser = await create({ email, externalId }) + + return { user: newUser, isNewUser: true } } export default { @@ -33,4 +48,5 @@ export default { update, _delete, list, + ensure, } diff --git a/src/utils/cookie.utils.ts b/src/utils/cookie.utils.ts new file mode 100644 index 00000000..f1ea9ab1 --- /dev/null +++ b/src/utils/cookie.utils.ts @@ -0,0 +1,10 @@ +import { CookieOptions } from 'express' + +import environment from '../environment' + +export const refreshCookieOptions: CookieOptions = { + maxAge: environment.refreshTokenValiditySeconds * 1000, + httpOnly: true, + secure: true, + sameSite: true, +} diff --git a/src/utils/passport.utils.ts b/src/utils/passport.utils.ts new file mode 100644 index 00000000..84229675 --- /dev/null +++ b/src/utils/passport.utils.ts @@ -0,0 +1,7 @@ +import passport from 'passport' + +import environment from '../environment' + +import saml from './passport/saml.passport' + +if (environment.providers.saml.enabled) passport.use(saml()) diff --git a/src/utils/passport/saml.passport.ts b/src/utils/passport/saml.passport.ts new file mode 100644 index 00000000..92d57ac2 --- /dev/null +++ b/src/utils/passport/saml.passport.ts @@ -0,0 +1,42 @@ +import { Strategy as SamlStrategy } from 'passport-saml' + +import { renameKeys } from 'devu-shared-modules' + +import environment from '../../environment' + +export let samlStrategy: SamlStrategy + +function generateSamlStrategy() { + samlStrategy = new SamlStrategy( + { + // URL that goes from the Identity Provider -> Service Provider + callbackUrl: `${environment.apiUrl}/login/saml/callback`, + // URL that goes from the Service Provider -> Identity Provider + entryPoint: environment.providers.saml.entryPoint, + // Usually specified as `/shibboleth` from site root + issuer: `${environment.apiUrl}/login/saml`, + // Service Provider Decryption key + decryptionPvk: environment.providers.saml.encryption.privateKey, + // Service Provider Signing Key + privateKey: environment.providers.saml.signing.privateKey, + // Identity Provider's public key + cert: environment.providers.saml.idpCerts, + identifierFormat: null, + validateInResponseTo: true, + disableRequestedAuthnContext: true, + wantAssertionsSigned: true, + acceptedClockSkewMs: environment.providers.saml.acceptedClockSkewSeconds * 1000, + signatureAlgorithm: 'sha256', + digestAlgorithm: 'sha256', + }, + function (profile: any, done: any) { + renameKeys(environment.providers.saml.attributeMap, profile) + + return done(null, profile) + } + ) + + return samlStrategy +} + +export default generateSamlStrategy diff --git a/src/utils/serializer/tests/users.serializer.test.ts b/src/utils/serializer/tests/users.serializer.test.ts new file mode 100644 index 00000000..67a22644 --- /dev/null +++ b/src/utils/serializer/tests/users.serializer.test.ts @@ -0,0 +1,20 @@ +import { serialize } from '../users.serializer' + +import UserModel from '../../../model/users.model' + +import Testing from '../../testing.utils' + +let mockUser: UserModel + +describe('User Serializer', () => { + beforeEach(() => { + mockUser = Testing.generateTypeOrm(UserModel) + }) + + test('CreatedAt and ModifiedAt are ISO strings for all users', () => { + const serializedUser = serialize(mockUser) + + expect(serializedUser.updatedAt).toEqual(mockUser.updatedAt.toISOString()) + expect(serializedUser.createdAt).toEqual(mockUser.updatedAt.toISOString()) + }) +}) diff --git a/src/utils/serializer/users.serializer.ts b/src/utils/serializer/users.serializer.ts new file mode 100644 index 00000000..bdfed3ad --- /dev/null +++ b/src/utils/serializer/users.serializer.ts @@ -0,0 +1,14 @@ +import { User } from 'devu-shared-modules' + +import UserModel from '../../model/users.model' + +export function serialize(user: UserModel): User { + return { + id: user.id, + externalId: user.externalId, + email: user.email, + createdAt: user.createdAt.toISOString(), + updatedAt: user.updatedAt.toISOString(), + preferredName: user.preferredName, + } +} diff --git a/src/utils/testing.utils.ts b/src/utils/testing.utils.ts index b2b11a27..31ffd652 100644 --- a/src/utils/testing.utils.ts +++ b/src/utils/testing.utils.ts @@ -1,4 +1,4 @@ -import { Request, Response, NextFunction } from 'express' +import { Request, Response, NextFunction, CookieOptions } from 'express' import Models from '../model' @@ -7,6 +7,8 @@ export function fakeRequest(overrides?: Partial): Request { req.params = {} req.body = {} + req.headers = {} + req.cookies = {} return { ...req, ...overrides } as Request } @@ -18,6 +20,10 @@ export function fakeResponse(overrides?: Partial): Response { res.json = jest.fn().mockImplementation((r: any) => res) res.send = jest.fn().mockImplementation(() => res) res.end = jest.fn().mockImplementation(() => res) + res.cookie = jest.fn().mockImplementation((n: string, v: string, o: CookieOptions) => res) + res.redirect = jest.fn().mockImplementation(() => res) + res.type = jest.fn().mockImplementation(() => res) + res.setHeader = jest.fn().mockImplementation(() => res) return { ...res, ...overrides } as Response } @@ -54,7 +60,7 @@ export function generateTypeOrmArray( model: { new (): ModelClass }, count: number ): ModelClass[] { - const data = [] + const data: ModelClass[] = [] for (let i = 0; i < count; i++) { const newObject = generateTypeOrm(model) diff --git a/tsconfig.json b/tsconfig.json index 78b39eca..a07aa094 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "lib": ["es5", "es6"], + "lib": ["es5", "es6", "dom"], "target": "es5", "module": "commonjs", "moduleResolution": "node", @@ -8,7 +8,23 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "sourceMap": true, + "strict": true, // Force some below options to be true (we know it's redundant) + "alwaysStrict": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": false, // Fixes typeorm models issues with strict "esModuleInterop": true, - "typeRoots": ["@types", "./node_modules/@types"] - } + "noImplicitAny": true, + "noImplicitThis": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "allowUnreachableCode": false, + "forceConsistentCasingInFileNames": true, + "newLine": "lf", + "typeRoots": ["@types", "./node_modules/@types"], + "resolveJsonModule": true + }, + "exclude": [ + "src/**/*.test.ts" + ] }