diff --git a/README.md b/README.md index 45d106107..128307cbc 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ API documentation is generated using [swagger-autogen](https://github.com/daviba To ensure you are using the correct API specification the following endpoints can be used: - [Test Instance](https://cveawg-test.mitre.org/api-docs/) -- [Production](https://cveawg.mitre.org/api-docs/openapi.json) +- [Production](https://cveawg.mitre.org/api-docs/) Note: The specification file stored in GitHub will only be correct for that branch; there could be differences between branches and production. diff --git a/api-docs/openapi.json b/api-docs/openapi.json index b0a02b642..2995d6a98 100644 --- a/api-docs/openapi.json +++ b/api-docs/openapi.json @@ -1,13 +1,12 @@ { "openapi": "3.0.2", "info": { - "version": "2.1.0", + "version": "2.1.1", "title": "CVE Services API", - "description": "The CVE Services API supports automation tooling for the CVE Program. Credentials are required for most service endpoints. Representatives of CVE Numbering Authorities (CNAs) should use one of the methods below to obtain credentials:
CVE data is to be in the JSON 5.0 CVE Record format. Details of the JSON 5.0 schema are located here.
Contact the CVE Services team", "contact": { - "name": "CVE Services", - "url": "https://cveawg-dev.mitre.org/api", - "email": "cve-board-auto-list@mitre.org" + "name": "CVE Services Overview", + "url": "https://cveproject.github.io/automation-cve-services#services-overview" } }, "servers": [ @@ -21,7 +20,7 @@ "tags": [ "CVE ID" ], - "summary": "Retrieves CVE ID entries after applying the query parameters as filters (accessible to all registered users)", + "summary": "Retrieves information about CVE IDs after applying the query parameters as filters (accessible to all registered users)", "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves filtered CVE IDs owned by the user's organization
Secretariat: Retrieves filtered CVE IDs owned by any organization
", "operationId": "cveIdGetFiltered", "parameters": [ @@ -58,7 +57,7 @@ ], "responses": { "200": { - "description": "A filtered list of CVE ID entries owned by the organization, along with pagination fields if results span multiple pages of data", + "description": "A filtered list of information about CVE IDs owned by the organization, along with pagination fields if results span multiple pages of data", "content": { "application/json": { "schema": { @@ -124,7 +123,7 @@ "CVE ID" ], "summary": "Reserves CVE IDs for the organization provided in the short_name query parameter (accessible to CNAs and Secretariat)", - "description": "User must belong to an organization with the CNA or Secretariat role
CNA: Reserves CVE IDs for the CNA's organization
Secretariat: Reserves CVE IDs for any organization
", + "description": "User must belong to an organization with the CNA or Secretariat role
CNA: Reserves CVE IDs for the CNA
Secretariat: Reserves CVE IDs for any organization
", "operationId": "cveIdReserve", "parameters": [ { @@ -228,8 +227,8 @@ "tags": [ "CVE ID" ], - "summary": "Retrieves a CVE ID entry for the specified id (acessible to all users)", - "description": "Endpoint is accessible to all
Regular, CNA & Admin Users: Retrieves full information for a CVE ID owned by their organization; partial information for a CVE ID owned by other organizations
Unauthenticated Users: Retrieves partial information for a CVE ID
Secretariat: Retrieves full information for a CVE ID owned by any organization
Note - The owning organization of RESERVED CVE IDs is redacted for all users other than those in the owning organization or Secretariat
", + "summary": "Retrieves information about the specified CVE ID (accessible to all users)", + "description": "Endpoint is accessible to all
Regular, CNA & Admin Users: Retrieves full information about a CVE ID owned by their organization; partial information about a CVE ID owned by other organizations
Unauthenticated Users: Retrieves partial information about a CVE ID
Secretariat: Retrieves full information about a CVE ID owned by any organization
Note - The owning organization of RESERVED CVE IDs is redacted for all users other than those in the owning organization or Secretariat
", "operationId": "cveIdGetSingle", "parameters": [ { @@ -239,7 +238,7 @@ "schema": { "type": "string" }, - "description": "The id of CVE ID entry to retrieve" + "description": "The id of the CVE ID information to retrieve" }, { "$ref": "#/components/parameters/apiEntityHeader" @@ -253,7 +252,7 @@ ], "responses": { "200": { - "description": "The requested CVE ID entry is returned", + "description": "The requested CVE ID information is returned", "content": { "application/json": { "schema": { @@ -318,8 +317,8 @@ "tags": [ "CVE ID" ], - "summary": "Updates the CVE ID entry for the specified id (accessible to CNAs and Secretariat)", - "description": "User must belong to an organization with the CNA or Secretariat role
CNA: Updates a CVE ID entry owned by the CNA's organization
Secretariat: Updates a CVE ID entry owned by any organization
", + "summary": "Updates information related to the specified CVE ID (accessible to CNAs and Secretariat)", + "description": "User must belong to an organization with the CNA or Secretariat role
CNA: Updates information related to a CVE ID owned by the CNA
Secretariat: Updates a CVE ID owned by any organization
", "operationId": "cveIdUpdateSingle", "parameters": [ { @@ -329,7 +328,7 @@ "schema": { "type": "string" }, - "description": "The id of the CVE ID entry to update" + "description": "The id of the CVE ID to update" }, { "$ref": "#/components/parameters/org" @@ -349,7 +348,7 @@ ], "responses": { "200": { - "description": "The updated CVE ID entry is returned", + "description": "The updated CVE ID information is returned", "content": { "application/json": { "schema": { @@ -416,8 +415,8 @@ "tags": [ "CVE ID" ], - "summary": "Creates a CVE-ID-Range entry for the specified year (accessible to Secretariat)", - "description": "User must belong to an organization with the Secretariat role
Secretariat: Creates a CVE-ID-Range entry for the specified year
", + "summary": "Creates a CVE-ID-Range for the specified year (accessible to Secretariat)", + "description": "User must belong to an organization with the Secretariat role
Secretariat: Creates a CVE-ID-Range for the specified year
", "operationId": "cveIdRangeCreate", "parameters": [ { @@ -427,7 +426,7 @@ "schema": { "type": "integer" }, - "description": "The year of the CVE-ID-Range entry" + "description": "The year of the CVE-ID-Range" }, { "$ref": "#/components/parameters/apiEntityHeader" @@ -441,7 +440,7 @@ ], "responses": { "200": { - "description": "The CVE-ID-Range entity was created" + "description": "The CVE-ID-Range was created" }, "400": { "description": "Bad Request", @@ -790,7 +789,7 @@ "CVE Record" ], "summary": "Retrieves all CVE Records after applying the query parameters as filters (accessible to Secretariat)", - "description": "User must belong to an organization with the Secretariat role
Secretariat: Retrieves all CVE entries for all organizations
", + "description": "User must belong to an organization with the Secretariat role
Secretariat: Retrieves all CVE records for all organizations
", "operationId": "cveGetFiltered", "parameters": [ { @@ -1288,8 +1287,8 @@ "tags": [ "Organization" ], - "summary": "Retrieves all organization entries (accessible to Secretariat)", - "description": "User must belong to an organization with the Secretariat role
Secretariat: Retrieves all organization entries
", + "summary": "Retrieves all organizations (accessible to Secretariat)", + "description": "User must belong to an organization with the Secretariat role
Secretariat: Retrieves information about all organizations
", "operationId": "orgAll", "parameters": [ { @@ -1307,7 +1306,7 @@ ], "responses": { "200": { - "description": "Returns all organization entries, along with pagination fields if results span multiple pages of data", + "description": "Returns information about all organizations, along with pagination fields if results span multiple pages of data", "content": { "application/json": { "schema": { @@ -1372,8 +1371,8 @@ "tags": [ "Organization" ], - "summary": "Creates an organization entry as specified in the request body (accessible to Secretariat)", - "description": "User must belong to an organization with the Secretariat role
Secretariat: Creates an organization entry
", + "summary": "Creates an organization as specified in the request body (accessible to Secretariat)", + "description": "User must belong to an organization with the Secretariat role
Secretariat: Creates an organization
", "operationId": "orgCreateSingle", "parameters": [ { @@ -1388,7 +1387,7 @@ ], "responses": { "200": { - "description": "Returns the organization entry created", + "description": "Returns information about the organization created", "content": { "application/json": { "schema": { @@ -1465,8 +1464,8 @@ "tags": [ "Organization" ], - "summary": "Retrieves the organization entry for the specified short name or UUID (accessible to all registered users)", - "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves organization record for the specified shortname or UUID if it is the user's organization
Secretariat: Retrieves any organization entry
", + "summary": "Retrieves information about the organization specified by short name or UUID (accessible to all registered users)", + "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves organization record for the specified shortname or UUID if it is the user's organization
Secretariat: Retrieves information about any organization
", "operationId": "orgSingle", "parameters": [ { @@ -1490,7 +1489,7 @@ ], "responses": { "200": { - "description": "Returns the organization entry", + "description": "Returns the organization information", "content": { "application/json": { "schema": { @@ -1557,7 +1556,7 @@ "tags": [ "Organization" ], - "summary": "Updates an organization entry for the specified organization short name (accessible to Secretariat)", + "summary": "Updates information about the organization specified by short name (accessible to Secretariat)", "description": "User must belong to an organization with the Secretariat role
Secretariat: Updates any organization's information
", "operationId": "orgUpdateSingle", "parameters": [ @@ -1597,7 +1596,7 @@ ], "responses": { "200": { - "description": "Returns the organization entry updated", + "description": "Returns information about the organization updated", "content": { "application/json": { "schema": { @@ -1664,8 +1663,8 @@ "tags": [ "Organization" ], - "summary": "Retrieves an organization's CVE ID quota information (accessible to all registered users)", - "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves CVE ID quota information for user's organization
Secretariat: Retrieves CVE ID quota information of any organization
", + "summary": "Retrieves an organization's CVE ID quota (accessible to all registered users)", + "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves the CVE ID quota for the user's organization
Secretariat: Retrieves the CVE ID quota for any organization
", "operationId": "orgIdQuota", "parameters": [ { @@ -1689,7 +1688,7 @@ ], "responses": { "200": { - "description": "Returns CVE ID quota details of an organization", + "description": "Returns the CVE ID quota for an organization", "content": { "application/json": { "schema": { @@ -1757,7 +1756,7 @@ "Users" ], "summary": "Retrieves all users for the organization with the specified short name (accessible to all registered users)", - "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves information for users in the same organization
Secretariat: Retrieves all user information from any organization
", + "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves information about users in the same organization
Secretariat: Retrieves all user information for any organization
", "operationId": "userOrgAll", "parameters": [ { @@ -1784,7 +1783,7 @@ ], "responses": { "200": { - "description": "Returns all user entries for the organization, along with pagination fields if results span multiple pages of data", + "description": "Returns all users for the organization, along with pagination fields if results span multiple pages of data", "content": { "application/json": { "schema": { @@ -1851,8 +1850,8 @@ "tags": [ "Users" ], - "summary": "Create a user entry with the provided short name as the owning organization (accessible to Admins and Secretariats)", - "description": "User must belong to an organization with the Secretariat role or be an Admin of the organization
Admin User: Creates a user entry for the Admin's organization
Secretariat: Creates a user entry for any organization
", + "summary": "Create a user with the provided short name as the owning organization (accessible to Admins and Secretariats)", + "description": "User must belong to an organization with the Secretariat role or be an Admin of the organization
Admin User: Creates a user for the Admin's organization
Secretariat: Creates a user for any organization
", "operationId": "userCreateSingle", "parameters": [ { @@ -1876,7 +1875,7 @@ ], "responses": { "200": { - "description": "Returns the created user entry (with the secret)", + "description": "Returns the new user information (with the secret)", "content": { "application/json": { "schema": { @@ -1953,8 +1952,8 @@ "tags": [ "Users" ], - "summary": "Retrieves a user entry for the specified username and organization short name (accessible to all registered users)", - "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves information for a user in the same organization
Secretariat: Retrieves any user's information
", + "summary": "Retrieves information about a user for the specified username and organization short name (accessible to all registered users)", + "description": "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves information about a user in the same organization
Secretariat: Retrieves any user's information
", "operationId": "userSingle", "parameters": [ { @@ -1987,7 +1986,7 @@ ], "responses": { "200": { - "description": "Returns user entry details", + "description": "Returns information about the specified user", "content": { "application/json": { "schema": { @@ -2052,8 +2051,8 @@ "tags": [ "Users" ], - "summary": "Updates a user entry for the specified username and organization shortname (accessible to all registered users)", - "description": "All registered users can access this endpoint
Regular User: Updates the user's own user entry. Only name fields may be changed.
Admin User: Updates a user entry for users in the Admin's organization. Allowed to change all fields except org_short_name.
Secretariat: Updates a user entry in any organization. Allowed to change all fields.
", + "summary": "Updates information about a user for the specified username and organization shortname (accessible to all registered users)", + "description": "All registered users can access this endpoint
Regular User: Updates the user's own information. Only name fields may be changed.
Admin User: Updates information about a user in the Admin's organization. Allowed to change all fields except org_short_name.
Secretariat: Updates information about a user in any organization. Allowed to change all fields.
", "operationId": "userUpdateSingle", "parameters": [ { @@ -2113,7 +2112,7 @@ ], "responses": { "200": { - "description": "Returns the updated user entry", + "description": "Returns the updated user information", "content": { "application/json": { "schema": { @@ -2281,8 +2280,8 @@ "tags": [ "Users" ], - "summary": "Retrieves information for all registered users (accessible to Secretariat)", - "description": "User must belong to an organization with the Secretariat role
Secretariat: Retrieves information of all users from any organization
", + "summary": "Retrieves information about all registered users (accessible to Secretariat)", + "description": "User must belong to an organization with the Secretariat role
Secretariat: Retrieves information about all users for all organizations
", "operationId": "userAll", "parameters": [ { @@ -2325,11 +2324,6 @@ "application/json": { "schema": { "$ref": "/schemas/errors/generic.json" - }, - "examples": { - "errorGeneric": { - "$ref": "#/components/examples/errorGeneric" - } } } } @@ -2570,7 +2564,7 @@ "cveIdGetFilteredTimeReservedLt": { "in": "query", "name": "time_reserved.lt", - "description": "Most recent CVE ID reserved timestamp to retrieve", + "description": "Most recent reserved timestamp to retrieve. Include with all requests potentially returning multiple pages of CVE IDs to avoid issues if new IDs are reserved during use.", "required": false, "schema": { "type": "string", @@ -2590,7 +2584,7 @@ "cveIdGetFilteredTimeModifiedLt": { "in": "query", "name": "time_modified.lt", - "description": "Most recent CVE ID modified timestamp to retrieve", + "description": "Most recent modified timestamp to retrieve. Include with all requests using a time_modified.gt filter potentially returning multiple pages of CVE IDs. This will avoid issues if IDs are reserved or modified during use.", "required": false, "schema": { "type": "string", @@ -2610,7 +2604,7 @@ "cveRecordFilteredTimeModifiedLt": { "in": "query", "name": "time_modified.lt", - "description": "Most recent CVE entry modified timestamp to retrieve", + "description": "Most recent CVE record modified timestamp to retrieve", "required": false, "schema": { "type": "string", @@ -2620,7 +2614,7 @@ "cveRecordFilteredTimeModifiedGt": { "in": "query", "name": "time_modified.gt", - "description": "Earliest CVE entry modified timestamp to retrieve", + "description": "Earliest CVE record modified timestamp to retrieve", "required": false, "schema": { "type": "string", @@ -2705,7 +2699,7 @@ "org": { "in": "query", "name": "org", - "description": "The new owning_cna for the CVE ID entry", + "description": "The new owning_cna for the CVE ID", "required": false, "schema": { "type": "string" @@ -2752,7 +2746,7 @@ "state": { "in": "query", "name": "state", - "description": "The new state for the CVE ID entry", + "description": "The new state for the CVE ID", "required": false, "schema": { "type": "string" @@ -2804,7 +2798,7 @@ "tags": [ "string" ], - "url": "https://cveawg-dev.mitre.org/api" + "url": "string" } ] } @@ -2907,4 +2901,4 @@ } } } -} +} \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index 2350685da..37c4b66ab 100644 --- a/docker/README.md +++ b/docker/README.md @@ -176,3 +176,9 @@ See the [API documentation](https://github.com/CVEProject/cve-services#api-docum ## Mongo DB The `docker-compose.yml` file exposes the default Mongo port to the host: `localhost:27017`. You can connect using any Mongo viewer such as [Mongo Express](https://github.com/mongo-express/mongo-express) or [Compass](https://www.mongodb.com/try/download/compass) on the host. + +## Running unit tests + +You can run unit tests using the docker image by running the following command: + +`docker exec -it cveawg npm run test` diff --git a/package-lock.json b/package-lock.json index 380470f6c..b73a5bbf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,19 +27,21 @@ "mongoose": "^5.12.3", "mongoose-aggregate-paginate-v2": "1.0.6", "morgan": "^1.9.1", - "node-dev": "^4.0.0", + "node-dev": "^7.4.3", "prompt-sync": "^4.2.0", + "replace-in-file": "6.3.5", "replace-json-property": "^1.8.0", "swagger-autogen": "^2.19.0", "swagger-ui-express": "^4.3.0", "uuid": "^8.3.2", "uuid-apikey": "^1.5.1", + "validate-date": "^2.0.0", "validator": ">=13.7.0", "winston": "^3.2.1", "yamljs": "^0.3.0" }, "devDependencies": { - "apidoc": "^0.17.7", + "apidoc": "^0.53.1", "chai": "^4.2.0", "chai-arrays": "^2.0.0", "chai-http": "^4.3.0", @@ -414,6 +416,47 @@ "kuler": "^2.0.0" } }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", + "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", + "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", @@ -568,6 +611,64 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, "node_modules/@phc/format": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz", @@ -596,6 +697,38 @@ "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "dev": true }, + "node_modules/@types/eslint": { + "version": "8.4.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz", + "integrity": "sha512-ehM7cCt2RSFs42mb+lcmhFT9ouIlV92PuaeRGn8N8c98oMjG4Z5pJHA9b1QiCcuqnbPSHcyfiD3mlhqMaHsQIw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -626,6 +759,200 @@ "@types/node": "*" } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -747,7 +1074,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -764,69 +1090,96 @@ "node": ">=4" } }, - "node_modules/apidoc": { - "version": "0.17.7", - "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.7.tgz", - "integrity": "sha512-9Wf4bRPwCuWOIOxR42dDnsXnFw+rhJg5VrMQK+KmNxJwyIh30UqX6gvjjXSG6YO74MqE87F18bbQXUENK9dPGg==", + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { - "apidoc-core": "~0.8.2", - "commander": "^2.19.0", - "fs-extra": "^7.0.0", - "lodash": "^4.17.10", - "markdown-it": "^8.3.1", - "winston": "^3.0.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/apidoc": { + "version": "0.53.1", + "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.53.1.tgz", + "integrity": "sha512-ijiLtIVEzTMdF29B/QzkvR4weMatgcElMsYKP1asszrImWYwzlZ9x0ZMLTXZrCe7GVMtkGSwQdugdLTZMZ+lww==", + "dev": true, + "os": [ + "darwin", + "freebsd", + "linux", + "openbsd", + "win32" + ], + "dependencies": { + "bootstrap": "3.4.1", + "commander": "^8.3.0", + "diff-match-patch": "^1.0.5", + "esbuild-loader": "^2.16.0", + "expose-loader": "^3.1.0", + "fs-extra": "^10.0.0", + "glob": "^7.2.0", + "handlebars": "^4.7.7", + "iconv-lite": "^0.6.3", + "jquery": "^3.6.0", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "markdown-it": "^12.2.0", + "nodemon": "^2.0.15", + "prismjs": "^1.25.0", + "semver": "^7.3.5", + "style-loader": "^3.3.1", + "webpack": "^5.64.2", + "webpack-cli": "^4.9.1", + "winston": "^3.3.3" }, "bin": { "apidoc": "bin/apidoc" }, "engines": { - "node": ">= 0.10.0" + "node": ">=14.0.0" } }, - "node_modules/apidoc-core": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.8.3.tgz", - "integrity": "sha1-2dY1RYKd8lDSzKBJaDqH53U2S5Y=", + "node_modules/apidoc/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, - "dependencies": { - "fs-extra": "^3.0.1", - "glob": "^7.1.1", - "iconv-lite": "^0.4.17", - "klaw-sync": "^2.1.0", - "lodash": "~4.17.4", - "semver": "~5.3.0" - }, "engines": { - "node": ">= 0.10.0" + "node": ">= 12" } }, - "node_modules/apidoc-core/node_modules/fs-extra": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", - "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "node_modules/apidoc/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^3.0.0", - "universalify": "^0.1.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/apidoc-core/node_modules/semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "node_modules/apidoc/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/apidoc/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "node_modules/append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", @@ -1041,6 +1394,24 @@ "node": ">= 0.8" } }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/bl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", @@ -1083,6 +1454,15 @@ "ms": "2.0.0" } }, + "node_modules/bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/bowser": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", @@ -1097,12 +1477,52 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/bson": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", @@ -1111,6 +1531,12 @@ "node": ">=0.6.19" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "node_modules/builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", @@ -1203,6 +1629,22 @@ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" }, + "node_modules/caniuse-lite": { + "version": "1.0.30001422", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001422.tgz", + "integrity": "sha512-hSesn02u1QacQHhaxl/kNMZwqVG35Sz/8DgvmgedxSH8z9UUpcDYSPYgsj3x5dQNRcNp6BwpSfQfVzYUTm+fog==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, "node_modules/chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -1306,11 +1748,47 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -1352,6 +1830,20 @@ "wrap-ansi": "^6.2.0" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1391,6 +1883,12 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "node_modules/colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -1851,6 +2349,12 @@ "node": ">=0.3.1" } }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "dev": true + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1892,11 +2396,25 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } }, "node_modules/enabled": { "version": "2.0.0", @@ -1919,6 +2437,19 @@ "node": ">= 0.8" } }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", @@ -1941,10 +2472,25 @@ } }, "node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } }, "node_modules/error-ex": { "version": "1.3.2", @@ -1980,6 +2526,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -1997,11 +2549,396 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", + "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.12", + "@esbuild/linux-loong64": "0.15.12", + "esbuild-android-64": "0.15.12", + "esbuild-android-arm64": "0.15.12", + "esbuild-darwin-64": "0.15.12", + "esbuild-darwin-arm64": "0.15.12", + "esbuild-freebsd-64": "0.15.12", + "esbuild-freebsd-arm64": "0.15.12", + "esbuild-linux-32": "0.15.12", + "esbuild-linux-64": "0.15.12", + "esbuild-linux-arm": "0.15.12", + "esbuild-linux-arm64": "0.15.12", + "esbuild-linux-mips64le": "0.15.12", + "esbuild-linux-ppc64le": "0.15.12", + "esbuild-linux-riscv64": "0.15.12", + "esbuild-linux-s390x": "0.15.12", + "esbuild-netbsd-64": "0.15.12", + "esbuild-openbsd-64": "0.15.12", + "esbuild-sunos-64": "0.15.12", + "esbuild-windows-32": "0.15.12", + "esbuild-windows-64": "0.15.12", + "esbuild-windows-arm64": "0.15.12" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", + "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", + "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", + "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", + "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", + "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", + "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", + "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", + "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", + "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", + "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", + "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", + "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", + "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", + "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.20.0.tgz", + "integrity": "sha512-dr+j8O4w5RvqZ7I4PPB4EIyVTd679EBQnMm+JBB7av+vu05Zpje2IpK5N3ld1VWa+WxrInIbNFAg093+E1aRsA==", + "dev": true, + "dependencies": { + "esbuild": "^0.15.6", + "joycon": "^3.0.1", + "json5": "^2.2.0", + "loader-utils": "^2.0.0", + "tapable": "^2.2.0", + "webpack-sources": "^2.2.0" + }, + "funding": { + "url": "https://github.com/privatenumber/esbuild-loader?sponsor=1" + }, + "peerDependencies": { + "webpack": "^4.40.0 || ^5.0.0" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", + "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", + "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", + "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", + "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", + "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", + "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } }, "node_modules/escape-html": { "version": "1.0.3", @@ -2640,6 +3577,31 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expose-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-3.1.0.tgz", + "integrity": "sha512-2RExSo0yJiqP+xiUue13jQa2IHE8kLDzTI7b6kn+vUlBVvlzNSiLDzo4e5Pp5J039usvTUnxZ8sUOhv0Kg15NA==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -2764,6 +3726,15 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/feature-policy": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", @@ -2812,6 +3783,18 @@ "debounce": "^1.0.0" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -2996,26 +3979,26 @@ ] }, "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=12" } }, - "node_modules/fs-extra/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": ">= 10.0.0" } }, "node_modules/fs-minipass": { @@ -3031,6 +4014,20 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3113,7 +4110,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -3145,7 +4141,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "engines": { "node": ">=8.0.0" } @@ -3193,6 +4188,12 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3214,9 +4215,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "devOptional": true }, "node_modules/growl": { @@ -3231,7 +4232,37 @@ "node_modules/growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" + "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==" + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/has": { "version": "1.0.3", @@ -3425,6 +4456,12 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/ignore-walk": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", @@ -3446,6 +4483,37 @@ "node": ">=4" } }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3591,6 +4659,15 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -3614,6 +4691,18 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-buffer": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", @@ -3650,9 +4739,9 @@ } }, "node_modules/is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { "has": "^1.0.3" }, @@ -3681,6 +4770,20 @@ "node": ">=0.10.0" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3694,7 +4797,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -3735,6 +4837,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -3801,11 +4924,14 @@ } }, "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/isarray": { @@ -3818,6 +4944,15 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -4000,6 +5135,59 @@ "node": ">=8" } }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/jquery": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", + "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==", + "dev": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4037,6 +5225,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -4060,14 +5254,26 @@ } }, "node_modules/jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, + "node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -4117,12 +5323,21 @@ "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/klaw-sync": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-2.1.0.tgz", - "integrity": "sha1-PTvNhgDnv971MjHHOf8FOu1WDkQ=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", "dev": true, - "optionalDependencies": { + "dependencies": { "graceful-fs": "^4.1.11" } }, @@ -4153,9 +5368,9 @@ } }, "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, "dependencies": { "uc.micro": "^1.0.1" @@ -4188,6 +5403,29 @@ "node": ">=0.10.0" } }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -4256,7 +5494,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -4267,8 +5504,7 @@ "node_modules/lru-cache/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/make-dir": { "version": "3.1.0", @@ -4295,14 +5531,14 @@ } }, "node_modules/markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, @@ -4310,10 +5546,16 @@ "markdown-it": "bin/markdown-it.js" } }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true }, "node_modules/media-typer": { @@ -4335,6 +5577,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -4933,6 +6181,12 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4953,20 +6207,36 @@ "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" }, "node_modules/node-dev": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-dev/-/node-dev-4.3.0.tgz", - "integrity": "sha512-rKXIUEHCETQWwNu0t0mK2fPxHjdtR0BFH35LjXsGq0e0gJf7z8Lgor348h8WqTVl7P5YWgNu5ZtarOV2uKvlVg==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/node-dev/-/node-dev-7.4.3.tgz", + "integrity": "sha512-o8aYipN28xY+WEunMHHiNc3hpPSkGG8ulHyYBapNbkg4dQxohmhx6jiRbiFhTF6zy+5IwljUGv1EcuxsaWI4Bw==", "dependencies": { "dateformat": "^3.0.3", "dynamic-dedupe": "^0.3.0", "filewatcher": "~3.0.0", - "minimist": "^1.1.3", - "node-notifier": "^5.4.0", - "resolve": "^1.0.0" + "get-package-type": "^0.1.0", + "minimist": "^1.2.6", + "node-notifier": "^8.0.1", + "resolve": "^1.22.0", + "semver": "^7.3.7" }, "bin": { "node-dev": "bin/node-dev" }, + "engines": { + "node": ">=12" + } + }, + "node_modules/node-dev/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { "node": ">=10" } @@ -4981,16 +6251,45 @@ "semver": "^5.7.0" } }, - "node_modules/node-notifier": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", - "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", + "node_modules/node-notifier": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + } + }, + "node_modules/node-notifier/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-notifier/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/node-pre-gyp": { @@ -5037,6 +6336,12 @@ "node": ">=8" } }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, "node_modules/node-sass-tilde-importer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/node-sass-tilde-importer/-/node-sass-tilde-importer-1.0.2.tgz", @@ -5046,6 +6351,61 @@ "find-parent-dir": "^0.3.0" } }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/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==", + "dev": true + }, "node_modules/nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -5070,6 +6430,15 @@ "validate-npm-package-license": "^3.0.1" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-bundled": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", @@ -5614,6 +6983,24 @@ "node": "*" } }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -5813,6 +7200,15 @@ "node": ">= 0.8.0" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5889,6 +7285,12 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -5911,6 +7313,15 @@ "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", "dev": true }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6069,6 +7480,30 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/referrer-policy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", @@ -6119,6 +7554,148 @@ "node": ">=4" } }, + "node_modules/replace-in-file": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.3.5.tgz", + "integrity": "sha512-arB9d3ENdKva2fxRnSjwBEXfK1npgyci7ZZuwysgAp7ORjHSyxz6oqIjTEv8R0Ydl4Ll7uOAZXL4vbkhGIizCg==", + "dependencies": { + "chalk": "^4.1.2", + "glob": "^7.2.0", + "yargs": "^17.2.1" + }, + "bin": { + "replace-in-file": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/replace-in-file/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/replace-in-file/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/replace-in-file/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/replace-in-file/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/replace-in-file/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/replace-in-file/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/replace-in-file/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/replace-in-file/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/replace-in-file/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/replace-in-file/node_modules/yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/replace-in-file/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, "node_modules/replace-json-property": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/replace-json-property/-/replace-json-property-1.8.0.tgz", @@ -6225,7 +7802,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6251,17 +7827,42 @@ "dev": true }, "node_modules/resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dependencies": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", @@ -6344,6 +7945,55 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -6399,6 +8049,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -6423,6 +8082,18 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -6486,6 +8157,27 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, + "node_modules/simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -6514,6 +8206,12 @@ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -6523,6 +8221,25 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -7081,14 +8798,13 @@ } }, "node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" @@ -7167,12 +8883,11 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -7199,6 +8914,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/superagent": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", @@ -7233,6 +8964,17 @@ "node": ">=4" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/swagger-autogen": { "version": "2.21.3", "resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.21.3.tgz", @@ -7350,6 +9092,15 @@ "node": ">=6" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/tar": { "version": "4.4.19", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", @@ -7386,6 +9137,76 @@ } ] }, + "node_modules/terser": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -7437,6 +9258,18 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -7445,6 +9278,33 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -7536,6 +9396,25 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "node_modules/uglify-js": { + "version": "3.17.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.3.tgz", + "integrity": "sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -7552,6 +9431,32 @@ "node": ">= 0.8" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", @@ -7601,6 +9506,11 @@ "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", "dev": true }, + "node_modules/validate-date": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/validate-date/-/validate-date-2.0.0.tgz", + "integrity": "sha512-DmRIajI6qR/j3JibfDaQsar2IYIUdRUPRBgo/M/kcl6CR5aWb3CsNTX2tdgu2KD3oAMpfXfuJncP30Z3xNHAJg==" + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -7646,10 +9556,192 @@ "node": ">=6.0.0" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-sources/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/webpack/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/which": { "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" }, @@ -7710,6 +9802,12 @@ "node": ">=4" } }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, "node_modules/winston": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", @@ -7763,6 +9861,12 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -8414,6 +10518,26 @@ "kuler": "^2.0.0" } }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@esbuild/android-arm": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", + "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", + "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", + "dev": true, + "optional": true + }, "@eslint/eslintrc": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", @@ -8530,6 +10654,55 @@ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, "@phc/format": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz", @@ -8555,6 +10728,38 @@ "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "dev": true }, + "@types/eslint": { + "version": "8.4.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz", + "integrity": "sha512-ehM7cCt2RSFs42mb+lcmhFT9ouIlV92PuaeRGn8N8c98oMjG4Z5pJHA9b1QiCcuqnbPSHcyfiD3mlhqMaHsQIw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -8585,6 +10790,187 @@ "@types/node": "*" } }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -8666,8 +11052,7 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -8678,58 +11063,67 @@ "color-convert": "^1.9.0" } }, - "apidoc": { - "version": "0.17.7", - "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.7.tgz", - "integrity": "sha512-9Wf4bRPwCuWOIOxR42dDnsXnFw+rhJg5VrMQK+KmNxJwyIh30UqX6gvjjXSG6YO74MqE87F18bbQXUENK9dPGg==", + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { - "apidoc-core": "~0.8.2", - "commander": "^2.19.0", - "fs-extra": "^7.0.0", - "lodash": "^4.17.10", - "markdown-it": "^8.3.1", - "winston": "^3.0.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "apidoc-core": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.8.3.tgz", - "integrity": "sha1-2dY1RYKd8lDSzKBJaDqH53U2S5Y=", + "apidoc": { + "version": "0.53.1", + "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.53.1.tgz", + "integrity": "sha512-ijiLtIVEzTMdF29B/QzkvR4weMatgcElMsYKP1asszrImWYwzlZ9x0ZMLTXZrCe7GVMtkGSwQdugdLTZMZ+lww==", "dev": true, "requires": { - "fs-extra": "^3.0.1", - "glob": "^7.1.1", - "iconv-lite": "^0.4.17", - "klaw-sync": "^2.1.0", - "lodash": "~4.17.4", - "semver": "~5.3.0" + "bootstrap": "3.4.1", + "commander": "^8.3.0", + "diff-match-patch": "^1.0.5", + "esbuild-loader": "^2.16.0", + "expose-loader": "^3.1.0", + "fs-extra": "^10.0.0", + "glob": "^7.2.0", + "handlebars": "^4.7.7", + "iconv-lite": "^0.6.3", + "jquery": "^3.6.0", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "markdown-it": "^12.2.0", + "nodemon": "^2.0.15", + "prismjs": "^1.25.0", + "semver": "^7.3.5", + "style-loader": "^3.3.1", + "webpack": "^5.64.2", + "webpack-cli": "^4.9.1", + "winston": "^3.3.3" }, "dependencies": { - "fs-extra": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", - "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^3.0.0", - "universalify": "^0.1.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -8905,6 +11299,18 @@ "safe-buffer": "5.1.2" } }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "bl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", @@ -8946,6 +11352,12 @@ } } }, + "bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "dev": true + }, "bowser": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", @@ -8960,17 +11372,44 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, "bson": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", @@ -9039,6 +11478,12 @@ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" }, + "caniuse-lite": { + "version": "1.0.30001422", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001422.tgz", + "integrity": "sha512-hSesn02u1QacQHhaxl/kNMZwqVG35Sz/8DgvmgedxSH8z9UUpcDYSPYgsj3x5dQNRcNp6BwpSfQfVzYUTm+fog==", + "dev": true + }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -9123,11 +11568,33 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -9160,6 +11627,17 @@ "wrap-ansi": "^6.2.0" } }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -9196,6 +11674,12 @@ "simple-swizzle": "^0.2.2" } }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -9551,6 +12035,12 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -9583,10 +12073,21 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, "enabled": { @@ -9604,6 +12105,16 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, "enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", @@ -9622,9 +12133,15 @@ } }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, "error-ex": { @@ -9655,22 +12172,217 @@ "string.prototype.trimstart": "^1.0.1" } }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "es-to-primitive": { + "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", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "esbuild": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", + "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.15.12", + "@esbuild/linux-loong64": "0.15.12", + "esbuild-android-64": "0.15.12", + "esbuild-android-arm64": "0.15.12", + "esbuild-darwin-64": "0.15.12", + "esbuild-darwin-arm64": "0.15.12", + "esbuild-freebsd-64": "0.15.12", + "esbuild-freebsd-arm64": "0.15.12", + "esbuild-linux-32": "0.15.12", + "esbuild-linux-64": "0.15.12", + "esbuild-linux-arm": "0.15.12", + "esbuild-linux-arm64": "0.15.12", + "esbuild-linux-mips64le": "0.15.12", + "esbuild-linux-ppc64le": "0.15.12", + "esbuild-linux-riscv64": "0.15.12", + "esbuild-linux-s390x": "0.15.12", + "esbuild-netbsd-64": "0.15.12", + "esbuild-openbsd-64": "0.15.12", + "esbuild-sunos-64": "0.15.12", + "esbuild-windows-32": "0.15.12", + "esbuild-windows-64": "0.15.12", + "esbuild-windows-arm64": "0.15.12" + } + }, + "esbuild-android-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", + "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", + "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", + "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", + "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", + "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", + "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", + "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", + "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", + "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", + "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", + "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", + "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", + "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", + "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", + "dev": true, + "optional": true + }, + "esbuild-loader": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.20.0.tgz", + "integrity": "sha512-dr+j8O4w5RvqZ7I4PPB4EIyVTd679EBQnMm+JBB7av+vu05Zpje2IpK5N3ld1VWa+WxrInIbNFAg093+E1aRsA==", + "dev": true, + "requires": { + "esbuild": "^0.15.6", + "joycon": "^3.0.1", + "json5": "^2.2.0", + "loader-utils": "^2.0.0", + "tapable": "^2.2.0", + "webpack-sources": "^2.2.0" + } + }, + "esbuild-netbsd-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", + "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", + "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", + "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", + "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } + "optional": true }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true + "esbuild-windows-64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", + "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", + "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-html": { "version": "1.0.3", @@ -10142,6 +12854,19 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "expose-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-3.1.0.tgz", + "integrity": "sha512-2RExSo0yJiqP+xiUue13jQa2IHE8kLDzTI7b6kn+vUlBVvlzNSiLDzo4e5Pp5J039usvTUnxZ8sUOhv0Kg15NA==", + "dev": true, + "requires": {} + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -10251,6 +12976,12 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, "feature-policy": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", @@ -10287,6 +13018,15 @@ "debounce": "^1.0.0" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -10424,24 +13164,21 @@ "dev": true }, "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "dependencies": { - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true } } }, @@ -10458,6 +13195,13 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -10526,8 +13270,7 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-func-name": { "version": "2.0.0", @@ -10549,8 +13292,7 @@ "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" }, "get-stdin": { "version": "8.0.0", @@ -10590,6 +13332,12 @@ "is-glob": "^4.0.1" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -10597,9 +13345,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "devOptional": true }, "growl": { @@ -10611,7 +13359,28 @@ "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" + "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==" + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } }, "has": { "version": "1.0.3", @@ -10758,6 +13527,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "ignore-walk": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", @@ -10776,6 +13551,27 @@ "resolve-from": "^3.0.0" } }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "dependencies": { + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -10890,6 +13686,12 @@ "side-channel": "^1.0.4" } }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -10907,6 +13709,15 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-buffer": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", @@ -10920,9 +13731,9 @@ "dev": true }, "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "requires": { "has": "^1.0.3" } @@ -10939,6 +13750,11 @@ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -10948,8 +13764,7 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-glob": { "version": "4.0.1", @@ -10975,6 +13790,21 @@ "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -11017,9 +13847,12 @@ "dev": true }, "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } }, "isarray": { "version": "1.0.0", @@ -11031,6 +13864,12 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -11170,6 +14009,46 @@ "istanbul-lib-report": "^3.0.0" } }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true + }, + "jquery": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", + "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11198,6 +14077,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -11215,12 +14100,21 @@ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } } }, "jsonparse": { @@ -11257,10 +14151,16 @@ "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "klaw-sync": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-2.1.0.tgz", - "integrity": "sha1-PTvNhgDnv971MjHHOf8FOu1WDkQ=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11" @@ -11287,9 +14187,9 @@ } }, "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, "requires": { "uc.micro": "^1.0.1" @@ -11318,6 +14218,23 @@ } } }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -11379,7 +14296,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" }, @@ -11387,8 +14303,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, @@ -11410,22 +14325,30 @@ } }, "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } } }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true }, "media-typer": { @@ -11444,6 +14367,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -11899,6 +14828,12 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -11916,16 +14851,28 @@ "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" }, "node-dev": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-dev/-/node-dev-4.3.0.tgz", - "integrity": "sha512-rKXIUEHCETQWwNu0t0mK2fPxHjdtR0BFH35LjXsGq0e0gJf7z8Lgor348h8WqTVl7P5YWgNu5ZtarOV2uKvlVg==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/node-dev/-/node-dev-7.4.3.tgz", + "integrity": "sha512-o8aYipN28xY+WEunMHHiNc3hpPSkGG8ulHyYBapNbkg4dQxohmhx6jiRbiFhTF6zy+5IwljUGv1EcuxsaWI4Bw==", "requires": { "dateformat": "^3.0.3", "dynamic-dedupe": "^0.3.0", "filewatcher": "~3.0.0", - "minimist": "^1.1.3", - "node-notifier": "^5.4.0", - "resolve": "^1.0.0" + "get-package-type": "^0.1.0", + "minimist": "^1.2.6", + "node-notifier": "^8.0.1", + "resolve": "^1.22.0", + "semver": "^7.3.7" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "node-environment-flags": { @@ -11939,15 +14886,34 @@ } }, "node-notifier": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", - "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "requires": { "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", "shellwords": "^0.1.1", - "which": "^1.3.0" + "uuid": "^8.3.0", + "which": "^2.0.2" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } } }, "node-pre-gyp": { @@ -11986,6 +14952,12 @@ "process-on-spawn": "^1.0.0" } }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, "node-sass-tilde-importer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/node-sass-tilde-importer/-/node-sass-tilde-importer-1.0.2.tgz", @@ -11995,6 +14967,50 @@ "find-parent-dir": "^0.3.0" } }, + "nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, "nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -12016,6 +15032,12 @@ "validate-npm-package-license": "^3.0.1" } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, "npm-bundled": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", @@ -12430,6 +15452,18 @@ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -12582,6 +15616,12 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -12645,6 +15685,12 @@ "ipaddr.js": "1.9.1" } }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -12661,6 +15707,15 @@ "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -12787,6 +15842,24 @@ "util-deprecate": "~1.0.1" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, "referrer-policy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", @@ -12822,6 +15895,105 @@ "es6-error": "^4.0.1" } }, + "replace-in-file": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.3.5.tgz", + "integrity": "sha512-arB9d3ENdKva2fxRnSjwBEXfK1npgyci7ZZuwysgAp7ORjHSyxz6oqIjTEv8R0Ydl4Ll7uOAZXL4vbkhGIizCg==", + "requires": { + "chalk": "^4.1.2", + "glob": "^7.2.0", + "yargs": "^17.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + } + } + }, "replace-json-property": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/replace-json-property/-/replace-json-property-1.8.0.tgz", @@ -12899,8 +16071,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-from-string": { "version": "2.0.2", @@ -12920,12 +16091,30 @@ "dev": true }, "resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, "requires": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } } }, "resolve-from": { @@ -12992,6 +16181,44 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -13045,6 +16272,15 @@ } } }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -13066,6 +16302,15 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -13122,6 +16367,23 @@ } } }, + "simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -13146,12 +16408,36 @@ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -13529,14 +16815,13 @@ } }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "string.prototype.matchall": { @@ -13599,12 +16884,11 @@ } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "strip-bom": { @@ -13619,6 +16903,13 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true, + "requires": {} + }, "superagent": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", @@ -13646,6 +16937,11 @@ "has-flag": "^3.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "swagger-autogen": { "version": "2.21.3", "resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.21.3.tgz", @@ -13740,6 +17036,12 @@ } } }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, "tar": { "version": "4.4.19", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", @@ -13761,6 +17063,45 @@ } } }, + "terser": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -13803,11 +17144,40 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -13886,6 +17256,19 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "uglify-js": { + "version": "3.17.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.3.tgz", + "integrity": "sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==", + "dev": true, + "optional": true + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -13896,6 +17279,16 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", @@ -13936,6 +17329,11 @@ "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", "dev": true }, + "validate-date": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/validate-date/-/validate-date-2.0.0.tgz", + "integrity": "sha512-DmRIajI6qR/j3JibfDaQsar2IYIUdRUPRBgo/M/kcl6CR5aWb3CsNTX2tdgu2KD3oAMpfXfuJncP30Z3xNHAJg==" + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -13972,10 +17370,130 @@ "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==", "dev": true }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "which": { "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" } @@ -14023,6 +17541,12 @@ } } }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, "winston": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", @@ -14066,6 +17590,12 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", diff --git a/package.json b/package.json index 8ab4ec1f1..10261c026 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "cve-services", "author": "Automation Working Group", - "version": "0.0.3", + "version": "2.1.1", "license": "(CC0)", "devDependencies": { - "apidoc": "^0.17.7", + "apidoc": "^0.53.1", "chai": "^4.2.0", "chai-arrays": "^2.0.0", "chai-http": "^4.3.0", @@ -43,13 +43,15 @@ "mongoose": "^5.12.3", "mongoose-aggregate-paginate-v2": "1.0.6", "morgan": "^1.9.1", - "node-dev": "^4.0.0", + "node-dev": "^7.4.3", "prompt-sync": "^4.2.0", "replace-json-property": "^1.8.0", + "replace-in-file": "6.3.5", "swagger-autogen": "^2.19.0", "swagger-ui-express": "^4.3.0", "uuid": "^8.3.2", "uuid-apikey": "^1.5.1", + "validate-date": "^2.0.0", "validator": ">=13.7.0", "winston": "^3.2.1", "yamljs": "^0.3.0" diff --git a/src/constants/index.js b/src/constants/index.js index fc3ce0e34..b87dcbd67 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -1,82 +1,103 @@ const fs = require('fs') const cveSchemaV5 = JSON.parse(fs.readFileSync('src/middleware/5.0_bundled_schema.json')) -module.exports = { - MONGOOSE_VALIDATION: { - Org_policies_id_quota_min: 0, - Org_policies_id_quota_min_message: 'Org.policies.id_quota cannot be a negative number.', - Org_policies_id_quota_max: 100000, - Org_policies_id_quota_max_message: 'Org.policies.id_quota cannot exceed maximum threshold.' - }, - DEFAULT_ID_QUOTA: 1000, - DEFAULT_AVAILABLE_POOL: 100, - NONSEQUENTIAL_MAX_AMOUNT: 10, - CRYPTO_RANDOM_STRING_LENGTH: 36, - AUTH_ROLE_ENUM: { - SECRETARIAT: 'SECRETARIAT', - CNA: 'CNA', - ROOT_CNA: 'ROOT_CNA', - ADP: 'ADP' - }, - ORG_ROLES: [ - 'CNA', - 'SECRETARIAT', - 'ROOT_CNA', - 'ADP' - ], - USER_ROLES: [ - 'ADMIN' - ], - USER_ROLE_ENUM: { - ADMIN: 'ADMIN' - }, - AUTH_HEADERS: { - ORG: 'CVE-API-ORG', - USER: 'CVE-API-USER', - KEY: 'CVE-API-KEY' - }, - CVE_STATES: { - PUBLISHED: 'PUBLISHED', - RESERVED: 'RESERVED', - REJECTED: 'REJECTED', - AVAILABLE: 'AVAILABLE' - }, - QUOTA_HEADER: 'CVE-API-REMAINING-QUOTA', - DEFAULT_CVE_ID_RANGE: { - cve_year: 2020, - ranges: { - priority: { - top_id: 0, - start: 0, - end: 20000 - }, - general: { - top_id: 20000, - start: 20000, - end: 50000000 +/** + * Return default values. + * + * The object is created in this function to prevent accidental + * value re-assignment and still allow IDE type-hints and compiled regex + * + * @return {defaults} + */ +function getConstants () { + /** + * @constant + * @default + * @lends defaults + */ + const defaults = { + MONGOOSE_VALIDATION: { + Org_policies_id_quota_min: 0, + Org_policies_id_quota_min_message: 'Org.policies.id_quota cannot be a negative number.', + Org_policies_id_quota_max: 100000, + Org_policies_id_quota_max_message: 'Org.policies.id_quota cannot exceed maximum threshold.' + }, + DEFAULT_ID_QUOTA: 1000, + DEFAULT_AVAILABLE_POOL: 100, + NONSEQUENTIAL_MAX_AMOUNT: 10, + CRYPTO_RANDOM_STRING_LENGTH: 36, + AUTH_ROLE_ENUM: { + SECRETARIAT: 'SECRETARIAT', + CNA: 'CNA', + ROOT_CNA: 'ROOT_CNA', + ADP: 'ADP' + }, + ORG_ROLES: [ + 'CNA', + 'SECRETARIAT', + 'ROOT_CNA', + 'ADP' + ], + USER_ROLES: [ + 'ADMIN' + ], + USER_ROLE_ENUM: { + ADMIN: 'ADMIN' + }, + AUTH_HEADERS: { + ORG: 'CVE-API-ORG', + USER: 'CVE-API-USER', + KEY: 'CVE-API-KEY' + }, + CVE_STATES: { + PUBLISHED: 'PUBLISHED', + RESERVED: 'RESERVED', + REJECTED: 'REJECTED', + AVAILABLE: 'AVAILABLE' + }, + QUOTA_HEADER: 'CVE-API-REMAINING-QUOTA', + DEFAULT_CVE_ID_RANGE: { + cve_year: 2020, + ranges: { + priority: { + top_id: 0, + start: 0, + end: 20000 + }, + general: { + top_id: 20000, + start: 20000, + end: 50000000 + } + } + }, + PAGINATOR_HEADERS: { + PAGE: 'PAGINATOR-PAGE' + }, + PAGINATOR_PAGE: 1, + PAGINATOR_OPTIONS: { + limit: 500, + useFacet: false, + customLabels: { + totalDocs: 'itemCount', + docs: 'itemsList', + limit: 'itemsPerPage', + page: 'currentPage', + totalPages: 'pageCount', + useFacet: false } - } - }, - PAGINATOR_HEADERS: { - PAGE: 'PAGINATOR-PAGE' - }, - PAGINATOR_PAGE: 1, - PAGINATOR_OPTIONS: { - limit: 500, - useFacet: false, - customLabels: { - totalDocs: 'itemCount', - docs: 'itemsList', - limit: 'itemsPerPage', - page: 'currentPage', - totalPages: 'pageCount', - useFacet: false - } - }, - MAX_SHORTNAME_LENGTH: 32, - MIN_SHORTNAME_LENGTH: 2, - CVE_ID_PATTERN: cveSchemaV5.definitions.cveId.pattern, - // Ajv's pattern validation uses the "u" (unicode) flag: - // https://ajv.js.org/json-schema.html#pattern - CVE_ID_REGEX: new RegExp(cveSchemaV5.definitions.cveId.pattern, 'u') + }, + MAX_SHORTNAME_LENGTH: 32, + MIN_SHORTNAME_LENGTH: 2, + CVE_ID_PATTERN: cveSchemaV5.definitions.cveId.pattern, + // Ajv's pattern validation uses the "u" (unicode) flag: + // https://ajv.js.org/json-schema.html#pattern + CVE_ID_REGEX: new RegExp(cveSchemaV5.definitions.cveId.pattern, 'u') + } + + return defaults } + +module.exports = { + getConstants +} diff --git a/src/controller/cve-id.controller/cve-id.controller.js b/src/controller/cve-id.controller/cve-id.controller.js index bb5d92ca7..e8c06d9f4 100644 --- a/src/controller/cve-id.controller/cve-id.controller.js +++ b/src/controller/cve-id.controller/cve-id.controller.js @@ -1,14 +1,23 @@ require('dotenv').config() const CveId = require('../../model/cve-id') const logger = require('../../middleware/logger') -const CONSTANTS = require('../../constants') +const getConstants = require('../../constants').getConstants const errors = require('./error') const error = new errors.CveIdControllerError() -const options = CONSTANTS.PAGINATOR_OPTIONS -options.sort = { owning_cna: 'asc', cve_id: 'asc' } // Called by GET /api/cve-id async function getFilteredCveId (req, res, next) { + const CONSTANTS = getConstants() + + // temporary measure to allow tests to work after fixing #920 + // tests required changing the global limit to force pagination + if (req.TEST_PAGINATOR_LIMIT) { + CONSTANTS.PAGINATOR_OPTIONS.limit = req.TEST_PAGINATOR_LIMIT + } + + const options = CONSTANTS.PAGINATOR_OPTIONS + options.sort = { owning_cna: 'asc', cve_id: 'asc' } + try { const orgShortName = req.ctx.org let state @@ -180,7 +189,7 @@ async function reserveCveId (req, res, next) { } else if (batchType === 'sequential') { await sequentialReservation(year, amount, shortName, orgShortName, requester, payload.available, false, res, req) } else if (batchType === 'non-sequential' || batchType === 'nonsequential') { - if (amount > CONSTANTS.NONSEQUENTIAL_MAX_AMOUNT) { + if (amount > getConstants().NONSEQUENTIAL_MAX_AMOUNT) { return res.status(403).json(error.overNonSequentialMaxAmount()) } await nonSequentialReservation(year, amount, shortName, orgShortName, requester, payload.available, res, req) @@ -197,7 +206,7 @@ async function reserveCveId (req, res, next) { } /* Expected behavior by role: -Secretariat: can retrieve all information for all CVE IDs +Secretariat: can retrieve full information for all CVE IDs Regular, CNA & Admin Users: Retrieve full information for a CVE ID owned by their organization Unauthenticated users along with Regular, CNA & Admin users requesting ids not owned by their organization retrieve partial information as follows: @@ -205,6 +214,8 @@ Unauthenticated users along with Regular, CNA & Admin users requesting ids not o owning_org not included for ids in the RESERVED state */ async function getCveId (req, res, next) { + const CONSTANTS = getConstants() + try { const auth = req.ctx.authenticated const id = req.ctx.params.id @@ -267,12 +278,19 @@ async function modifyCveId (req, res, next) { const cveIdRepo = req.ctx.repositories.getCveIdRepository() const userRepo = req.ctx.repositories.getUserRepository() const cveRepo = req.ctx.repositories.getCveRepository() + const org = await orgRepo.findOneByShortName(req.ctx.org) + + // Get remaining org quota + const totalReserved = await cveIdRepo.countDocuments({ owning_cna: org.UUID, state: 'RESERVED' }) + const remainingQuota = (org.policies.id_quota - totalReserved) // Check for existing record - await only allowed at top level so cannot // move inside of it statement below const cve = await cveRepo.findOneByCveId(id) - - Object.keys(req.ctx.query).forEach(k => { + const queryKeys = Object.keys(req.ctx.query) + // Object.keys(req.ctx.query).forEach(k => { + for (let i = 0; i < queryKeys.length; i++) { + const k = queryKeys[i] const key = k.toLowerCase() // Ok to change owning_cna if there is an existing record, but not state @@ -281,10 +299,16 @@ async function modifyCveId (req, res, next) { return res.status(403).json(error.cannotChangeCveIdWithRecord(id)) } state = req.ctx.query.state + + // Don't allow state transition to RESERVED if org has no remaining quota + if (state === 'RESERVED' && remainingQuota <= 0) { + return res.status(403).json(error.modifyCveIdNoQuota()) + } } else if (key === 'org') { newOrgShortName = req.ctx.query.org } - }) + } + // }) let result = await cveIdRepo.findOneByCveId(id) if (!result) { @@ -338,6 +362,7 @@ async function modifyCveId (req, res, next) { // Called by POST /cve-id-range/:year async function createCveIdRange (req, res, next) { try { + const CONSTANTS = getConstants() const year = req.ctx.params.year const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const orgRepo = req.ctx.repositories.getOrgRepository() @@ -368,6 +393,7 @@ async function createCveIdRange (req, res, next) { } async function priorityReservation (year, amount, shortName, orgShortName, requester, availableIds, res, req) { + const CONSTANTS = getConstants() const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const reqUUID = req.ctx.uuid let result = await cveIdRangeRepo.findOne({ cve_year: year }) @@ -443,6 +469,7 @@ async function priorityReservation (year, amount, shortName, orgShortName, reque } async function sequentialReservation (year, amount, shortName, orgShortName, requester, availableIds, isPriority, res, req) { + const CONSTANTS = getConstants() const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const reqUUID = req.ctx.uuid let result = await cveIdRangeRepo.findOne({ cve_year: year }) @@ -534,6 +561,7 @@ async function sequentialReservation (year, amount, shortName, orgShortName, req } async function nonSequentialReservation (year, amount, shortName, orgShortName, requester, availableIds, res, req) { + const CONSTANTS = getConstants() const cveIdRepo = req.ctx.repositories.getCveIdRepository() const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const reqUUID = req.ctx.uuid diff --git a/src/controller/cve-id.controller/cve-id.middleware.js b/src/controller/cve-id.controller/cve-id.middleware.js index 560e0dc8e..e81545bb8 100644 --- a/src/controller/cve-id.controller/cve-id.middleware.js +++ b/src/controller/cve-id.controller/cve-id.middleware.js @@ -15,25 +15,6 @@ function parsePostParams (req, res, next) { next() } -// Sanitizer for dates -function toDate (val) { - val = val.toUpperCase() - let value = val.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(|Z|((-|\+|\s)\d{2}:\d{2}))$/) - let result - if (value) { - value[0] = value[0].replace(' ', '+') // Re-add literal '+' which was stripped - result = new Date(value[0]) - } else { - value = val.match(/^\d{4}-\d{2}-\d{2}$/) - if (value) { - result = new Date(`${value[0]}T00:00:00.000+00:00`) - } else { - result = null - } - } - return result -} - function parseError (req, res, next) { const err = validationResult(req).formatWith(({ location, msg, param, value, nestedErrors }) => { return { msg: msg, param: param, location: location } @@ -47,6 +28,5 @@ function parseError (req, res, next) { module.exports = { parseGetParams, parsePostParams, - parseError, - toDate + parseError } diff --git a/src/controller/cve-id.controller/error.js b/src/controller/cve-id.controller/error.js index 76a433305..7433bfb7f 100644 --- a/src/controller/cve-id.controller/error.js +++ b/src/controller/cve-id.controller/error.js @@ -1,5 +1,5 @@ const idrErr = require('../../utils/error') -const CONSTANTS = require('../../constants') +const getConstants = require('../../constants').getConstants class CveIdControllerError extends idrErr.IDRError { invalidState (state) { // cve-id @@ -32,6 +32,7 @@ class CveIdControllerError extends idrErr.IDRError { overNonSequentialMaxAmount () { // cve-id const err = {} + const CONSTANTS = getConstants() err.error = 'OVER_NONSEQUENTIAL_MAX_AMOUNT' err.message = 'The amount query parameter exceeds the maximum amount allowed. Only amounts of ' + CONSTANTS.NONSEQUENTIAL_MAX_AMOUNT + ' ids or less can be reserved at a time.' return err @@ -60,6 +61,7 @@ class CveIdControllerError extends idrErr.IDRError { orgCannotReserveForOther () { // cve-id const err = {} + const CONSTANTS = getConstants() err.error = 'ORG_CANNOT_RESERVE_FOR_OTHER' err.message = 'The organization designated by the ' + CONSTANTS.AUTH_HEADERS.ORG + ' header is not allowed to reserve IDs for the organization specified by the short_name query parameter.' return err @@ -125,6 +127,14 @@ class CveIdControllerError extends idrErr.IDRError { } return err } + + modifyCveIdNoQuota () { + const err = { + error: 'TRANSITION_STATE_RESERVED_NO_QUOTA', + message: 'A CVE ID state cannot be changed to RESERVED if the owning organization has no remaining quota.' + } + return err + } } module.exports = { diff --git a/src/controller/cve-id.controller/index.js b/src/controller/cve-id.controller/index.js index d88012665..03afc0058 100644 --- a/src/controller/cve-id.controller/index.js +++ b/src/controller/cve-id.controller/index.js @@ -4,8 +4,10 @@ const mw = require('../../middleware/middleware') const errorMsgs = require('../../middleware/errorMessages') const controller = require('./cve-id.controller') const { param, query } = require('express-validator') -const { parseGetParams, parsePostParams, parseError, toDate } = require('./cve-id.middleware') -const CONSTANTS = require('../../constants') +const { parseGetParams, parsePostParams, parseError } = require('./cve-id.middleware') +const getConstants = require('../../constants').getConstants +const CONSTANTS = getConstants() +const toDate = require('../../utils/utils').toDate const CHOICES = [CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.PUBLISHED, CONSTANTS.CVE_STATES.RESERVED] const MODIFYTARGETS = [CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.RESERVED] @@ -14,7 +16,7 @@ router.get('/cve-id', /* #swagger.tags = ['CVE ID'] #swagger.operationId = 'cveIdGetFiltered' - #swagger.summary = "Retrieves CVE ID entries after applying the query parameters as filters (accessible to all registered users)" + #swagger.summary = "Retrieves information about CVE IDs after applying the query parameters as filters (accessible to all registered users)" #swagger.description = "All registered users can access this endpoint
@@ -34,7 +36,7 @@ router.get('/cve-id', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'A filtered list of CVE ID entries owned by the organization, along with pagination fields if results span multiple pages of data', + description: 'A filtered list of information about CVE IDs owned by the organization, along with pagination fields if results span multiple pages of data', content: { "application/json": { schema: { $ref: '/schemas/cve-id/list-cve-ids-response.json' } @@ -104,7 +106,7 @@ router.post('/cve-id',User must belong to an organization with the CNA or Secretariat role
CNA: Reserves CVE IDs for the CNA's organization
+CNA: Reserves CVE IDs for the CNA
Secretariat: Reserves CVE IDs for any organization
" #swagger.parameters['$ref'] = [ '#/components/parameters/amount', @@ -187,23 +189,23 @@ router.get('/cve-id/:id', /* #swagger.tags = ['CVE ID'] #swagger.operationId = 'cveIdGetSingle' - #swagger.summary = "Retrieves a CVE ID entry for the specified id (acessible to all users)" + #swagger.summary = "Retrieves information about the specified CVE ID (accessible to all users)" #swagger.description = "Endpoint is accessible to all
Regular, CNA & Admin Users: Retrieves full information for a CVE ID owned by their organization; partial information for a CVE ID owned by other organizations
-Unauthenticated Users: Retrieves partial information for a CVE ID -
Secretariat: Retrieves full information for a CVE ID owned by any organization
+Regular, CNA & Admin Users: Retrieves full information about a CVE ID owned by their organization; partial information about a CVE ID owned by other organizations
+Unauthenticated Users: Retrieves partial information about a CVE ID +
Secretariat: Retrieves full information about a CVE ID owned by any organization
Note - The owning organization of RESERVED CVE IDs is redacted for all users other than those in the owning organization or Secretariat
- #swagger.parameters['id'] = { description: 'The id of CVE ID entry to retrieve' } + #swagger.parameters['id'] = { description: 'The id of the CVE ID information to retrieve' } #swagger.parameters['$ref'] = [ '#/components/parameters/apiEntityHeader', '#/components/parameters/apiUserHeader', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'The requested CVE ID entry is returned', + description: 'The requested CVE ID information is returned', content: { "application/json": { schema: { $ref: '/schemas/cve-id/get-cve-id-response.json' } @@ -262,14 +264,14 @@ router.put('/cve-id/:id', /* #swagger.tags = ['CVE ID'] #swagger.operationId = 'cveIdUpdateSingle' - #swagger.summary = "Updates the CVE ID entry for the specified id (accessible to CNAs and Secretariat)" + #swagger.summary = "Updates information related to the specified CVE ID (accessible to CNAs and Secretariat)" #swagger.description = "User must belong to an organization with the CNA or Secretariat role
CNA: Updates a CVE ID entry owned by the CNA's organization
-Secretariat: Updates a CVE ID entry owned by any organization
" - #swagger.parameters['id'] = { description: 'The id of the CVE ID entry to update' } +CNA: Updates information related to a CVE ID owned by the CNA
+Secretariat: Updates a CVE ID owned by any organization
" + #swagger.parameters['id'] = { description: 'The id of the CVE ID to update' } #swagger.parameters['$ref'] = [ '#/components/parameters/org`, '#/components/parameters/state', @@ -278,7 +280,7 @@ router.put('/cve-id/:id', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'The updated CVE ID entry is returned', + description: 'The updated CVE ID information is returned', content: { "application/json": { schema: { $ref: '/schemas/cve-id/update-cve-id-response.json' } @@ -341,14 +343,14 @@ router.post('/cve-id-range/:year', /* #swagger.tags = ['CVE ID'] #swagger.operationId = 'cveIdRangeCreate' - #swagger.summary = "Creates a CVE-ID-Range entry for the specified year (accessible to Secretariat)" + #swagger.summary = "Creates a CVE-ID-Range for the specified year (accessible to Secretariat)" #swagger.description = "User must belong to an organization with the Secretariat role
Secretariat: Creates a CVE-ID-Range entry for the specified year
" +Secretariat: Creates a CVE-ID-Range for the specified year
" #swagger.parameters['year'] = { - description: 'The year of the CVE-ID-Range entry', + description: 'The year of the CVE-ID-Range', schema: { type: 'integer' } @@ -359,7 +361,7 @@ router.post('/cve-id-range/:year', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'The CVE-ID-Range entity was created', + description: 'The CVE-ID-Range was created', } #swagger.responses[400] = { description: 'Bad Request', diff --git a/src/controller/cve.controller/cna_container_schema.json b/src/controller/cve.controller/cna_container_schema.json index 08515e71f..d77a1d57b 100644 --- a/src/controller/cve.controller/cna_container_schema.json +++ b/src/controller/cve.controller/cna_container_schema.json @@ -143,7 +143,7 @@ "description": "Provides information about the set of products and services affected by this vulnerability.", "allOf": [ { - "oneOf": [ + "anyOf": [ { "required": [ "vendor", diff --git a/src/controller/cve.controller/cve.controller.js b/src/controller/cve.controller/cve.controller.js index 5c4b5c418..908e0d544 100644 --- a/src/controller/cve.controller/cve.controller.js +++ b/src/controller/cve.controller/cve.controller.js @@ -1,10 +1,8 @@ const Cve = require('../../model/cve') const logger = require('../../middleware/logger') const errors = require('./error') +const getConstants = require('../../constants').getConstants const error = new errors.CveControllerError() -const CONSTANTS = require('../../constants') -const options = { ...CONSTANTS.PAGINATOR_OPTIONS } -delete options.sort // Deletes any predefined sort options // Helper function to create providerMetadata object function createProviderMetadata (orgId, shortName, updateDate) { @@ -29,6 +27,15 @@ async function getCve (req, res, next) { // Called by GET /cve async function getFilteredCves (req, res, next) { + const CONSTANTS = getConstants() + const options = CONSTANTS.PAGINATOR_OPTIONS + + // temporary measure to allow tests to work after fixing #920 + // tests required changing the global limit to force pagination + if (req.TEST_PAGINATOR_LIMIT) { + CONSTANTS.PAGINATOR_OPTIONS.limit = req.TEST_PAGINATOR_LIMIT + } + try { options.page = req.ctx.query.page ? parseInt(req.ctx.query.page) : CONSTANTS.PAGINATOR_PAGE // if 'page' query parameter is not defined, set 'page' to the default page value const cveRepo = req.ctx.repositories.getCveRepository() @@ -96,6 +103,14 @@ async function getFilteredCves (req, res, next) { { $match: query }, + // sort before project so DocDB uses the cveId index. + // aggregatePaginate accepts sort separately from the aggregate query + // so need to explicitly specify it here and remove it from the options + { + $sort: { + 'cve.cveMetadata.cveId': 1 + } + }, { $project: { _id: false, @@ -104,6 +119,8 @@ async function getFilteredCves (req, res, next) { } ] + delete options.sort + // check whether user requested count_only for filtered set of records if (req.ctx.query.count_only === '1') { const payload = {} @@ -134,6 +151,8 @@ async function getFilteredCves (req, res, next) { // Creates a new CVE only if it does not exists for the specified CVE ID in the request body. If it exists, it does not // update the CVE. async function submitCve (req, res, next) { + const CONSTANTS = getConstants() + try { const newCve = new Cve({ cve: req.ctx.body }) const id = req.ctx.params.id @@ -165,8 +184,8 @@ async function submitCve (req, res, next) { return res.status(400).json(error.cveRecordExists()) } - await cveIdRepo.updateByCveId(cveId, { state: state }) await cveRepo.updateByCveId(cveId, newCve, { upsert: true }) + await cveIdRepo.updateByCveId(cveId, { state: state }) const responseMessage = { message: cveId + ' record was successfully created.', @@ -192,6 +211,8 @@ async function submitCve (req, res, next) { // Called by PUT /cve/:id // Updates a CVE if one exists for the specified CVE ID async function updateCve (req, res, next) { + const CONSTANTS = getConstants() + try { const newCve = new Cve({ cve: req.ctx.body }) const cveId = req.ctx.params.id @@ -249,6 +270,8 @@ async function updateCve (req, res, next) { // Called by POST /cve/:id/cna async function submitCna (req, res, next) { + const CONSTANTS = getConstants() + try { const id = req.ctx.params.id const cveRepo = req.ctx.repositories.getCveRepository() @@ -284,7 +307,6 @@ async function submitCna (req, res, next) { const dateUpdated = (new Date()).toISOString() const additionalCveMetadataFields = { assignerShortName: assignerShortName, - requesterUserId: cveId.requested_by.user, dateReserved: (cveId.reserved).toISOString(), datePublished: dateUpdated } @@ -295,8 +317,9 @@ async function submitCna (req, res, next) { result = Cve.validateCveRecord(cveModel.cve) - if (!result) { - return res.status(500).json(error.serverError()) + if (!result.isValid) { + logger.error(JSON.stringify({ uuid: req.ctx.uuid, message: 'CVE JSON schema validation FAILED.' })) + return res.status(400).json(error.invalidCnaContainerJsonSchema(result.errors)) } try { @@ -329,6 +352,8 @@ async function submitCna (req, res, next) { // Called by PUT /cve/:id/cna async function updateCna (req, res, next) { + const CONSTANTS = getConstants() + try { const id = req.ctx.params.id const cveRepo = req.ctx.repositories.getCveRepository() @@ -379,10 +404,13 @@ async function updateCna (req, res, next) { cveRecord.containers.cna = cnaContainer const cveModel = new Cve({ cve: cveRecord }) result = Cve.validateCveRecord(cveModel.cve) - if (!result) { - return res.status(500).json(error.serverError()) + + if (!result.isValid) { + logger.error(JSON.stringify({ uuid: req.ctx.uuid, message: 'CVE JSON schema validation FAILED.' })) + return res.status(400).json(error.invalidCnaContainerJsonSchema(result.errors)) } + await cveRepo.updateByCveId(id, cveModel) // change cve id state to publish if (cveId.state === CONSTANTS.CVE_STATES.REJECTED) { result = await cveIdRepo.updateByCveId(id, { state: CONSTANTS.CVE_STATES.PUBLISHED }) @@ -390,7 +418,6 @@ async function updateCna (req, res, next) { return res.status(500).json(error.serverError()) } } - await cveRepo.updateByCveId(id, cveModel) const responseMessage = { message: id + ' record was successfully updated.', @@ -414,6 +441,8 @@ async function updateCna (req, res, next) { // Called by POST /cve/:id/reject async function rejectCVE (req, res, next) { + const CONSTANTS = getConstants() + try { const id = req.ctx.params.id const cveIdRepo = req.ctx.repositories.getCveIdRepository() @@ -448,14 +477,15 @@ async function rejectCVE (req, res, next) { if (!result) { return res.status(500).json(error.serverError()) } - // Update state of CVE ID entry - result = await cveIdRepo.updateByCveId(id, { state: CONSTANTS.CVE_STATES.REJECTED }) + + // Save rejected CVE record object + result = await cveRepo.updateByCveId(id, newCveObj, { upsert: true }) if (!result) { return res.status(500).json(error.serverError()) } - // Save rejected CVE record object - result = await cveRepo.updateByCveId(id, newCveObj, { upsert: true }) + // Update state of CVE ID + result = await cveIdRepo.updateByCveId(id, { state: CONSTANTS.CVE_STATES.REJECTED }) if (!result) { return res.status(500).json(error.serverError()) } @@ -483,6 +513,8 @@ async function rejectCVE (req, res, next) { // Called by PUT /cve/:id/reject async function rejectExistingCve (req, res, next) { + const CONSTANTS = getConstants() + try { const id = req.ctx.params.id const cveIdRepo = req.ctx.repositories.getCveIdRepository() diff --git a/src/controller/cve.controller/cve.middleware.js b/src/controller/cve.controller/cve.middleware.js index 6b8ff3554..7f1372355 100644 --- a/src/controller/cve.controller/cve.middleware.js +++ b/src/controller/cve.controller/cve.middleware.js @@ -25,25 +25,6 @@ function parseGetParams (req, res, next) { next() } -// Sanitizer for dates -function toDate (val) { - val = val.toUpperCase() - let value = val.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(|Z|((-|\+|\s)\d{2}:\d{2}))$/) - let result - if (value) { - value[0] = value[0].replace(' ', '+') // Re-add literal '+' which was stripped - result = new Date(value[0]) - } else { - value = val.match(/^\d{4}-\d{2}-\d{2}$/) - if (value) { - result = new Date(`${value[0]}T00:00:00.000+00:00`) - } else { - result = null - } - } - return result -} - function parseError (req, res, next) { const err = validationResult(req).formatWith(({ location, msg, param, value, nestedErrors }) => { return { msg: msg, param: param, location: location } @@ -55,13 +36,8 @@ function parseError (req, res, next) { } /** - * Custom body validation to check that the array index passed contains - * only 1 unique English language code entry. (Schema validation checks - * a unique combination of lang + text value, so we don't here.) - * - * - Pass: Duplicate non-English codes (fr and fr) - * - Pass: > 1 different English codes (en and en-ca) - * - Fail: > 1 same English codes (en & en, en-gb & en-gb) + * Custom body validation for unique English entries in the value of the array index passed. + * (Schema validation checks a unique combination of lang + text value, so we don't here.) * * @param {String} langsIndex * @returns Result @@ -69,33 +45,53 @@ function parseError (req, res, next) { function validateUniqueEnglishEntry (langsIndex) { // The JSON format itself is enforced in the schema validation, so we only need // to check the fields if they were passed, so can use optional() - return body(langsIndex).optional({ nullable: true }).isArray().custom((langsArr, { req }) => { + return body(langsIndex).optional({ nullable: true }).isArray().custom((langsArr, { req, path }) => { // the passed in keys are ORs, not ANDs if (langsArr === undefined) { return true } - const foundValues = new Set() + if (hasSingleEnglishEntry(langsArr)) { + return true + } else { + // duplicate found so send error + throw new Error(`Cannot have more than one English language entry in '${path}'`) + } + }) +} + +/** + * Check that the array passed contains only 1 unique English language code entry + * + * - Pass: Duplicate non-English codes (fr and fr) + * - Pass: > 1 different English codes (en and en-ca) + * - Fail: > 1 same English codes (en & en, en-gb & en-gb) + * + * @param {Array} langsArr + * @returns true + * @throws Error + */ +function hasSingleEnglishEntry (langsArr) { + const foundValues = new Set() - for (const entry of langsArr) { - const lang = entry.lang.toLowerCase() + for (const entry of langsArr) { + const lang = entry.lang.toLowerCase() - // ignore non-English - if (!lang.startsWith('en')) { - continue - } + // ignore non-English + if (!lang.startsWith('en')) { + continue + } - if (foundValues.has(lang)) { - // duplicate found so send error - // provide error message details in same format as Ajv - throw new Error(`Cannot have more than one English language entry '${lang}'`) - } - // add each unique value to set - foundValues.add(lang) + // return early if a duplicate is found + if (foundValues.has(lang)) { + return false } - return true - }) + // add each unique value to set + foundValues.add(lang) + } + + return true } function validateRejectBody (req, res, next) { @@ -137,8 +133,8 @@ module.exports = { parseGetParams, parsePostParams, parseError, - toDate, validateCveCnaContainerJsonSchema, validateUniqueEnglishEntry, + hasSingleEnglishEntry, validateRejectBody } diff --git a/src/controller/cve.controller/index.js b/src/controller/cve.controller/index.js index 3c37ddb58..a8042a996 100644 --- a/src/controller/cve.controller/index.js +++ b/src/controller/cve.controller/index.js @@ -4,9 +4,11 @@ const mw = require('../../middleware/middleware') const errorMsgs = require('../../middleware/errorMessages') const controller = require('./cve.controller') const { body, param, query } = require('express-validator') -const { parseGetParams, parsePostParams, parseError, toDate, validateCveCnaContainerJsonSchema, validateRejectBody, validateUniqueEnglishEntry } = require('./cve.middleware') -const CONSTANTS = require('../../constants') +const { parseGetParams, parsePostParams, parseError, validateCveCnaContainerJsonSchema, validateRejectBody, validateUniqueEnglishEntry } = require('./cve.middleware') +const getConstants = require('../../constants').getConstants +const CONSTANTS = getConstants() const CHOICES = [CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.PUBLISHED] +const toDate = require('../../utils/utils').toDate router.get('/cve/:id', /* @@ -85,7 +87,7 @@ router.get('/cve',User must belong to an organization with the Secretariat role
Secretariat: Retrieves all CVE entries for all organizations
" +Secretariat: Retrieves all CVE records for all organizations
" #swagger.parameters['$ref'] = [ '#/components/parameters/cveRecordFilteredTimeModifiedLt', '#/components/parameters/cveRecordFilteredTimeModifiedGt', diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js index 4fce328dd..2d942b3b4 100644 --- a/src/controller/org.controller/index.js +++ b/src/controller/org.controller/index.js @@ -5,18 +5,19 @@ const errorMsgs = require('../../middleware/errorMessages') const controller = require('./org.controller') const { body, param, query } = require('express-validator') const { parseGetParams, parsePostParams, parseError, isOrgRole, isUserRole, isValidUsername } = require('./org.middleware') -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() router.get('/org', /* #swagger.tags = ['Organization'] #swagger.operationId = 'orgAll' - #swagger.summary = "Retrieves all organization entries (accessible to Secretariat)" + #swagger.summary = "Retrieves all organizations (accessible to Secretariat)" #swagger.description = "User must belong to an organization with the Secretariat role
Secretariat: Retrieves all organization entries
" +Secretariat: Retrieves information about all organizations
" #swagger.parameters['$ref'] = [ '#/components/parameters/pageQuery', '#/components/parameters/apiEntityHeader', @@ -24,7 +25,7 @@ router.get('/org', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns all organization entries, along with pagination fields if results span multiple pages of data', + description: 'Returns information about all organizations, along with pagination fields if results span multiple pages of data', content: { "application/json": { schema: { $ref: '/schemas/org/list-orgs-response.json' } @@ -83,12 +84,12 @@ router.post('/org', /* #swagger.tags = ['Organization'] #swagger.operationId = 'orgCreateSingle' - #swagger.summary = "Creates an organization entry as specified in the request body (accessible to Secretariat)" + #swagger.summary = "Creates an organization as specified in the request body (accessible to Secretariat)" #swagger.description = "User must belong to an organization with the Secretariat role
Secretariat: Creates an organization entry
+Secretariat: Creates an organization
" #swagger.parameters['$ref'] = [ '#/components/parameters/apiEntityHeader', @@ -104,7 +105,7 @@ router.post('/org', } } #swagger.responses[200] = { - description: 'Returns the organization entry created', + description: 'Returns information about the organization created', content: { "application/json": { schema: { $ref: '/schemas/org/create-org-response.json' } @@ -167,13 +168,13 @@ router.get('/org/:identifier', /* #swagger.tags = ['Organization'] #swagger.operationId = 'orgSingle' - #swagger.summary = "Retrieves the organization entry for the specified short name or UUID (accessible to all registered users)" + #swagger.summary = "Retrieves information about the organization specified by short name or UUID (accessible to all registered users)" #swagger.description = "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves organization record for the specified shortname or UUID if it is the user's organization
-Secretariat: Retrieves any organization entry
" +Secretariat: Retrieves information about any organization
" #swagger.parameters['identifier'] = { description: 'The shortname or UUID of the organization' } #swagger.parameters['$ref'] = [ '#/components/parameters/apiEntityHeader', @@ -181,7 +182,7 @@ router.get('/org/:identifier', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns the organization entry', + description: 'Returns the organization information', content: { "application/json": { schema: { $ref: '/schemas/org/get-org-response.json' } @@ -238,7 +239,7 @@ router.put('/org/:shortname', /* #swagger.tags = ['Organization'] #swagger.operationId = 'orgUpdateSingle' - #swagger.summary = "Updates an organization entry for the specified organization short name (accessible to Secretariat)" + #swagger.summary = "Updates information about the organization specified by short name (accessible to Secretariat)" #swagger.description = "User must belong to an organization with the Secretariat role
@@ -256,7 +257,7 @@ router.put('/org/:shortname', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns the organization entry updated', + description: 'Returns information about the organization updated', content: { "application/json": { schema: { $ref: '/schemas/org/update-org-response.json' } @@ -322,13 +323,13 @@ router.get('/org/:shortname/id_quota', /* #swagger.tags = ['Organization'] #swagger.operationId = 'orgIdQuota' - #swagger.summary = "Retrieves an organization's CVE ID quota information (accessible to all registered users)" + #swagger.summary = "Retrieves an organization's CVE ID quota (accessible to all registered users)" #swagger.description = "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves CVE ID quota information for user's organization
-Secretariat: Retrieves CVE ID quota information of any organization
" +Regular, CNA & Admin Users: Retrieves the CVE ID quota for the user's organization
+Secretariat: Retrieves the CVE ID quota for any organization
" #swagger.parameters['shortname'] = { description: 'The shortname of the organization' } #swagger.parameters['$ref'] = [ '#/components/parameters/apiEntityHeader', @@ -336,7 +337,7 @@ router.get('/org/:shortname/id_quota', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns CVE ID quota details of an organization', + description: 'Returns the CVE ID quota for an organization', content: { "application/json": { schema: { $ref: '/schemas/org/get-org-quota-response.json' } @@ -398,8 +399,8 @@ router.get('/org/:shortname/users',All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves information for users in the same organization
-Secretariat: Retrieves all user information from any organization
" +Regular, CNA & Admin Users: Retrieves information about users in the same organization
+Secretariat: Retrieves all user information for any organization
" #swagger.parameters['shortname'] = { description: 'The shortname of the organization' } #swagger.parameters['$ref'] = [ '#/components/parameters/pageQuery', @@ -408,7 +409,7 @@ router.get('/org/:shortname/users', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns all user entries for the organization, along with pagination fields if results span multiple pages of data', + description: 'Returns all users for the organization, along with pagination fields if results span multiple pages of data', content: { "application/json": { schema: { $ref: '/schemas/user/list-users-response.json' } @@ -466,13 +467,13 @@ router.post('/org/:shortname/user', /* #swagger.tags = ['Users'] #swagger.operationId = 'userCreateSingle' - #swagger.summary = "Create a user entry with the provided short name as the owning organization (accessible to Admins and Secretariats)" + #swagger.summary = "Create a user with the provided short name as the owning organization (accessible to Admins and Secretariats)" #swagger.description = "User must belong to an organization with the Secretariat role or be an Admin of the organization
Admin User: Creates a user entry for the Admin's organization
-Secretariat: Creates a user entry for any organization
" +Admin User: Creates a user for the Admin's organization
+Secretariat: Creates a user for any organization
" #swagger.parameters['shortname'] = { description: 'The shortname of the organization' } #swagger.parameters['$ref'] = [ '#/components/parameters/apiEntityHeader', @@ -488,7 +489,7 @@ router.post('/org/:shortname/user', } } #swagger.responses[200] = { - description: 'Returns the created user entry (with the secret)', + description: 'Returns the new user information (with the secret)', content: { "application/json": { schema: { $ref: '/schemas/user/create-user-response.json' }, @@ -555,12 +556,12 @@ router.get('/org/:shortname/user/:username', /* #swagger.tags = ['Users'] #swagger.operationId = 'userSingle' - #swagger.summary = "Retrieves a user entry for the specified username and organization short name (accessible to all registered users)" + #swagger.summary = "Retrieves information about a user for the specified username and organization short name (accessible to all registered users)" #swagger.description = "All registered users can access this endpoint
Regular, CNA & Admin Users: Retrieves information for a user in the same organization
+Regular, CNA & Admin Users: Retrieves information about a user in the same organization
Secretariat: Retrieves any user's information
" #swagger.parameters['shortname'] = { description: 'The shortname of the organization' } #swagger.parameters['username'] = { description: 'The username of the user' } @@ -570,7 +571,7 @@ router.get('/org/:shortname/user/:username', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns user entry details', + description: 'Returns information about the specified user', content: { "application/json": { schema: { $ref: '/schemas/user/get-user-response.json' } @@ -628,14 +629,14 @@ router.put('/org/:shortname/user/:username', /* #swagger.tags = ['Users'] #swagger.operationId = 'userUpdateSingle' - #swagger.summary = "Updates a user entry for the specified username and organization shortname (accessible to all registered users)" + #swagger.summary = "Updates information about a user for the specified username and organization shortname (accessible to all registered users)" #swagger.description = "All registered users can access this endpoint
Regular User: Updates the user's own user entry. Only name fields may be changed.
-Admin User: Updates a user entry for users in the Admin's organization. Allowed to change all fields except org_short_name.
-Secretariat: Updates a user entry in any organization. Allowed to change all fields.
" +Regular User: Updates the user's own information. Only name fields may be changed.
+Admin User: Updates information about a user in the Admin's organization. Allowed to change all fields except org_short_name.
+Secretariat: Updates information about a user in any organization. Allowed to change all fields.
" #swagger.parameters['shortname'] = { description: 'The shortname of the organization' } #swagger.parameters['username'] = { description: 'The username of the user' } #swagger.parameters['$ref'] = [ @@ -653,7 +654,7 @@ router.put('/org/:shortname/user/:username', '#/components/parameters/apiSecretHeader' ] #swagger.responses[200] = { - description: 'Returns the updated user entry', + description: 'Returns the updated user information', content: { "application/json": { schema: { $ref: '/schemas/user/update-user-response.json' } diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js index 958d1f095..b9d6728a7 100644 --- a/src/controller/org.controller/org.controller.js +++ b/src/controller/org.controller/org.controller.js @@ -3,7 +3,7 @@ const User = require('../../model/user') const Org = require('../../model/org') const logger = require('../../middleware/logger') const argon2 = require('argon2') -const CONSTANTS = require('../../constants') +const getConstants = require('../../constants').getConstants const cryptoRandomString = require('crypto-random-string') const uuid = require('uuid') const errors = require('./error') @@ -16,6 +16,14 @@ const uuidAPIKey = require('uuid-apikey') **/ async function getOrgs (req, res, next) { try { + const CONSTANTS = getConstants() + + // temporary measure to allow tests to work after fixing #920 + // tests required changing the global limit to force pagination + if (req.TEST_PAGINATOR_LIMIT) { + CONSTANTS.PAGINATOR_OPTIONS.limit = req.TEST_PAGINATOR_LIMIT + } + const options = CONSTANTS.PAGINATOR_OPTIONS options.sort = { short_name: 'asc' } options.page = req.ctx.query.page ? parseInt(req.ctx.query.page) : CONSTANTS.PAGINATOR_PAGE // if 'page' query parameter is not defined, set 'page' to the default page value @@ -87,6 +95,14 @@ async function getOrg (req, res, next) { **/ async function getUsers (req, res, next) { try { + const CONSTANTS = getConstants() + + // temporary measure to allow tests to work after fixing #920 + // tests required changing the global limit to force pagination + if (req.TEST_PAGINATOR_LIMIT) { + CONSTANTS.PAGINATOR_OPTIONS.limit = req.TEST_PAGINATOR_LIMIT + } + const options = CONSTANTS.PAGINATOR_OPTIONS options.sort = { username: 'asc' } options.page = req.ctx.query.page ? parseInt(req.ctx.query.page) : CONSTANTS.PAGINATOR_PAGE // if 'page' query parameter is not defined, set 'page' to the default page value @@ -197,7 +213,7 @@ async function getOrgIdQuota (req, res, next) { const query = { owning_cna: await repo.getOrgUUID(shortName), - state: CONSTANTS.CVE_STATES.RESERVED + state: getConstants().CVE_STATES.RESERVED } const cveIdRepo = req.ctx.repositories.getCveIdRepository() result = await cveIdRepo.countDocuments(query) @@ -217,6 +233,8 @@ async function getOrgIdQuota (req, res, next) { * Called by POST /api/org/ **/ async function createOrg (req, res, next) { + const CONSTANTS = getConstants() + try { const newOrg = new Org() const orgRepo = req.ctx.repositories.getOrgRepository() @@ -451,7 +469,7 @@ async function createUser (req, res, next) { newUser.org_UUID = orgUUID newUser.UUID = uuid.v4() newUser.active = true - const randomKey = cryptoRandomString({ length: CONSTANTS.CRYPTO_RANDOM_STRING_LENGTH }) + const randomKey = cryptoRandomString({ length: getConstants().CRYPTO_RANDOM_STRING_LENGTH }) newUser.secret = await argon2.hash(randomKey) let result = await userRepo.findOneByUserNameAndOrgUUID(newUser.username, newUser.org_UUID) // Find user in MongoDB @@ -658,8 +676,15 @@ async function updateUser (req, res, next) { result = await userRepo.aggregate(agt) result = result.length > 0 ? result[0] : null + let msgStr = '' + if (Object.keys(req.ctx.query).length > 0) { + msgStr = username + ' was successfully updated.' + } else { + msgStr = 'No updates were specified for ' + username + '.' + } + const responseMessage = { - message: username + ' was successfully updated.', + message: msgStr, updated: result } @@ -715,7 +740,7 @@ async function resetSecret (req, res, next) { } } - const randomKey = cryptoRandomString({ length: CONSTANTS.CRYPTO_RANDOM_STRING_LENGTH }) + const randomKey = cryptoRandomString({ length: getConstants().CRYPTO_RANDOM_STRING_LENGTH }) oldUser.secret = await argon2.hash(randomKey) // store in db const user = await userRepo.updateByUserNameAndOrgUUID(oldUser.username, orgUUID, oldUser) if (user.n === 0) { diff --git a/src/controller/org.controller/org.middleware.js b/src/controller/org.controller/org.middleware.js index b2b792c00..c20e4915a 100644 --- a/src/controller/org.controller/org.middleware.js +++ b/src/controller/org.controller/org.middleware.js @@ -1,10 +1,12 @@ -const CONSTANTS = require('../../constants') +const getConstants = require('../../constants').getConstants const { validationResult } = require('express-validator') const errors = require('./error') const error = new errors.OrgControllerError() const utils = require('../../utils/utils') function isOrgRole (val) { + const CONSTANTS = getConstants() + val.forEach(role => { if (!CONSTANTS.ORG_ROLES.includes(role)) { throw new Error('Organization role does not exist.') @@ -15,6 +17,8 @@ function isOrgRole (val) { } function isUserRole (val) { + const CONSTANTS = getConstants() + val.forEach(role => { if (!CONSTANTS.USER_ROLES.includes(role)) { throw new Error('User role does not exist.') diff --git a/src/controller/user.controller/index.js b/src/controller/user.controller/index.js index 1ec42b696..6b7517798 100644 --- a/src/controller/user.controller/index.js +++ b/src/controller/user.controller/index.js @@ -4,18 +4,19 @@ const mw = require('../../middleware/middleware') const { query } = require('express-validator') const controller = require('./user.controller') const { parseGetParams, parseError } = require('./user.middleware') -const CONSTANTS = require('../../constants') +const getConstants = require('../../constants').getConstants +const CONSTANTS = getConstants() router.get('/users', /* #swagger.tags = ['Users'] #swagger.operationId = 'userAll' - #swagger.summary = "Retrieves information for all registered users (accessible to Secretariat)" + #swagger.summary = "Retrieves information about all registered users (accessible to Secretariat)" #swagger.description = "User must belong to an organization with the Secretariat role
Secretariat: Retrieves information of all users from any organization
" +Secretariat: Retrieves information about all users for all organizations
" #swagger.parameters['$ref'] = [ '#/components/parameters/pageQuery', '#/components/parameters/apiEntityHeader', @@ -43,7 +44,6 @@ router.get('/users', content: { "application/json": { schema: { $ref: '/schemas/errors/generic.json' }, - examples:{ errorGeneric: { $ref: '#/components/examples/errorGeneric' }} } } } diff --git a/src/controller/user.controller/user.controller.js b/src/controller/user.controller/user.controller.js index 3f21c6f7a..fb4429ef6 100644 --- a/src/controller/user.controller/user.controller.js +++ b/src/controller/user.controller/user.controller.js @@ -1,6 +1,6 @@ require('dotenv').config() const logger = require('../../middleware/logger') -const CONSTANTS = require('../../constants') +const getConstants = require('../../constants').getConstants /** * Get the details of all users @@ -8,6 +8,14 @@ const CONSTANTS = require('../../constants') **/ async function getAllUsers (req, res, next) { try { + const CONSTANTS = getConstants() + + // temporary measure to allow tests to work after fixing #920 + // tests required changing the global limit to force pagination + if (req.TEST_PAGINATOR_LIMIT) { + CONSTANTS.PAGINATOR_OPTIONS.limit = req.TEST_PAGINATOR_LIMIT + } + const options = CONSTANTS.PAGINATOR_OPTIONS options.sort = { short_name: 'asc' } options.page = req.ctx.query.page ? parseInt(req.ctx.query.page) : CONSTANTS.PAGINATOR_PAGE // if 'page' query parameter is not defined, set 'page' to the default page value @@ -26,7 +34,7 @@ async function getAllUsers (req, res, next) { payload.nextPage = pg.nextPage } - logger.info({ uuid: req.ctx.uuid, message: 'The users information was sent to the secretariat user.' }) + logger.info({ uuid: req.ctx.uuid, message: 'The user information was sent to the secretariat user.' }) return res.status(200).json(payload) } catch (err) { next(err) diff --git a/src/controller/user.controller/user.middleware.js b/src/controller/user.controller/user.middleware.js index d8dcb0bd4..95a900313 100644 --- a/src/controller/user.controller/user.middleware.js +++ b/src/controller/user.controller/user.middleware.js @@ -1,4 +1,3 @@ -// const CONSTANTS = require('../../constants') const { validationResult } = require('express-validator') const errors = require('./error') const error = new errors.UserControllerError() diff --git a/src/middleware/errorMessages.js b/src/middleware/errorMessages.js index 760910e0a..394cc5ae1 100644 --- a/src/middleware/errorMessages.js +++ b/src/middleware/errorMessages.js @@ -2,5 +2,5 @@ module.exports = { ID_QUOTA: 'The id_quota does not comply with CVE id quota limitations', - TIMESTAMP_FORMAT: 'Valid timestamp format is yyyy-MM-ddTHH:mm:ss or yyyy-MM-ddTHH:mm:ss.ZZZZ' + TIMESTAMP_FORMAT: 'Bad date, or invalid timestamp format: valid format is yyyy-MM-ddTHH:mm:ss or yyyy-MM-ddTHH:mm:ss.ZZZZ' } diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index c70a816a5..b5653984e 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -1,4 +1,4 @@ -const CONSTANTS = require('../constants') +const getConstants = require('../constants').getConstants const fs = require('fs') const cveSchemaV5 = JSON.parse(fs.readFileSync('src/middleware/5.0_bundled_schema.json')) const argon2 = require('argon2') @@ -20,6 +20,8 @@ function setCacheControl (req, res, next) { } function createCtxAndReqUUID (req, res, next) { + const CONSTANTS = getConstants() + try { req.ctx = { authenticated: false, @@ -87,6 +89,7 @@ async function validateUser (req, res, next) { const key = req.ctx.key const userRepo = req.ctx.repositories.getUserRepository() const orgRepo = req.ctx.repositories.getOrgRepository() + const CONSTANTS = getConstants() try { if (!org) { @@ -136,6 +139,7 @@ async function validateUser (req, res, next) { async function onlySecretariat (req, res, next) { const org = req.ctx.org const orgRepo = req.ctx.repositories.getOrgRepository() + const CONSTANTS = getConstants() try { const isSec = await orgRepo.isSecretariat(org) @@ -157,6 +161,7 @@ async function onlySecretariatOrAdmin (req, res, next) { const username = req.ctx.user const orgRepo = req.ctx.repositories.getOrgRepository() const userRepo = req.ctx.repositories.getUserRepository() + const CONSTANTS = getConstants() try { const isSec = await orgRepo.isSecretariat(org) @@ -177,6 +182,7 @@ async function onlySecretariatOrAdmin (req, res, next) { async function onlyCnas (req, res, next) { const shortName = req.ctx.org const orgRepo = req.ctx.repositories.getOrgRepository() + const CONSTANTS = getConstants() try { const org = await orgRepo.findOneByShortName(shortName) // org exists @@ -223,7 +229,8 @@ async function onlyOrgWithRole (req, res, next) { function validateQueryParameterNames (queryParamNames, validNames) { Object.keys(queryParamNames).forEach(k => { if (!validNames.includes(k)) { - throw new Error(`'${k}' is not a valid parameter name.`) + const filteredMessage = k.replace(/[^A-Z0-9_ -]+/gi, ' ') + throw new Error("'" + filteredMessage.trim() + "'" + ' is not a valid parameter name.') } }) return true @@ -299,7 +306,11 @@ function validateJsonSyntax (err, req, res, next) { } else if (err.status === 400) { console.warn('Request failed validation because JSON syntax is incorrect') console.info((JSON.stringify(err))) - return res.status(400).json(error.invalidJsonSyntax(err.message)) + let filteredMessage = err.message + if (filteredMessage.includes('Failed to decode param')) { + filteredMessage = filteredMessage.replace(/[^A-Z0-9_ -]+/gi, '') + } + return res.status(400).json(error.invalidJsonSyntax(filteredMessage)) } else { console.warn('Request failed') console.info((JSON.stringify(err))) diff --git a/src/model/cve.js b/src/model/cve.js index d0aa67293..34e2ab1a3 100644 --- a/src/model/cve.js +++ b/src/model/cve.js @@ -9,7 +9,7 @@ addFormats(ajv) const validate = ajv.compile(cveSchemaV5) const rejectedContainerSchema = JSON.parse(fs.readFileSync('src/middleware/schemas/cnaContainer.json')) const validateCnaRejectedContainer = ajv.compile(rejectedContainerSchema) -const CONSTANTS = require('../constants') +const getConstants = require('../constants').getConstants const schema = { _id: false, @@ -30,11 +30,13 @@ CveSchema.index({ 'cve.cveMetadata.cveId': 1 }) CveSchema.index({ 'cve.cveMetadata.dateUpdated': 1 }) CveSchema.statics.validateCveRecord = function (record) { - const result = validate(record) - if (result) { - return true + const validateObject = {} + validateObject.isValid = validate(record) + + if (!validateObject.isValid) { + validateObject.errors = validate.errors } - return false + return validateObject } function createBaseCveMetadata (id, assignerOrgId, state) { @@ -51,6 +53,7 @@ function createBaseCveMetadata (id, assignerOrgId, state) { } CveSchema.statics.newPublishedCve = function (id, assignerOrgId, cnaContainer, sysProvidedCveMetadata = {}, sysProvidedProviderMetadata = {}) { + const CONSTANTS = getConstants() const baseRecord = createBaseCveMetadata(id, assignerOrgId, CONSTANTS.CVE_STATES.PUBLISHED) const newCveMetadata = { @@ -79,6 +82,7 @@ function createCnaRejectContainer (providerMetadata, rejectedReasons, replacedBy } CveSchema.statics.newRejectedCve = function (cveIdObj, reqBody, owningCnaShortName, providerMetadata) { + const CONSTANTS = getConstants() const rejectedRecord = createBaseCveMetadata(cveIdObj.cve_id, cveIdObj.owning_cna, CONSTANTS.CVE_STATES.REJECTED) // Might be able to move these into createBaseCveMetadata, but will need to update other calling functions rejectedRecord.cveMetadata.dateReserved = new Date(cveIdObj.reserved).toISOString() @@ -105,6 +109,8 @@ CveSchema.statics.validateRejected = function (record) { } CveSchema.statics.updateCveToRejected = function (id, providerMetadata, record, newCnaContainer) { + const CONSTANTS = getConstants() + record.containers.cna = newCnaContainer.cnaContainer // replace cna field on existing record record.cveMetadata.dateUpdated = providerMetadata.dateUpdated record.containers.cna.providerMetadata = providerMetadata diff --git a/src/model/org.js b/src/model/org.js index 8d4116426..07e0b9146 100644 --- a/src/model/org.js +++ b/src/model/org.js @@ -1,7 +1,8 @@ require('dotenv').config() const mongoose = require('mongoose') const aggregatePaginate = require('mongoose-aggregate-paginate-v2') -const CONSTANTS = require('../constants') +const getConstants = require('../constants').getConstants +const CONSTANTS = getConstants() const schema = { _id: false, diff --git a/src/routes.config.js b/src/routes.config.js index 9d77e1973..e1fc27835 100644 --- a/src/routes.config.js +++ b/src/routes.config.js @@ -20,7 +20,8 @@ var setupOptions = { .swagger-ui .parameters-col_description input { display: none } .swagger-ui .parameters-col_description select { display: none } .swagger-ui .parameter__in { font-weight: bold; color: black } - .swagger-ui .parameters-col_name { width: 20% }` + .swagger-ui .parameters-col_name { width: 20% } + .swagger-ui .renderedMarkdown a {text-decoration: none;}` } module.exports = async function configureRoutes (app) { diff --git a/src/scripts/updateOpenapiHost.js b/src/scripts/updateOpenapiHost.js index efeb2ecfe..4a2c57a17 100644 --- a/src/scripts/updateOpenapiHost.js +++ b/src/scripts/updateOpenapiHost.js @@ -1,17 +1,33 @@ -const replaceJSONProperty = require('replace-json-property') +const replaceInFile = require('replace-in-file') if (process.env.NODE_ENV === 'development') { - replaceJSONProperty.replace('api-docs/openapi.json', 'url', 'https://cveawg-dev.mitre.org/api') + replaceInFile.sync({ + files: 'api-docs/openapi.json', + from: 'urlplaceholder', + to: 'https://cveawg-dev.mitre.org/api' + }) } if (process.env.NODE_ENV === 'staging') { - replaceJSONProperty.replace('api-docs/openapi.json', 'url', 'https://cveawg-test.mitre.org/api') + replaceInFile.sync({ + files: 'api-docs/openapi.json', + from: 'urlplaceholder', + to: 'https://cveawg-test.mitre.org/api' + }) } if (process.env.NODE_ENV === 'integration') { - replaceJSONProperty.replace('api-docs/openapi.json', 'url', 'https://cveawg-int.mitre.org/api') + replaceInFile.sync({ + files: 'api-docs/openapi.json', + from: 'urlplaceholder', + to: 'https://cveawg-int.mitre.org/api' + }) } if (process.env.NODE_ENV === 'production') { - replaceJSONProperty.replace('api-docs/openapi.json', 'url', 'https://cveawg.mitre.org/api') + replaceInFile.sync({ + files: 'api-docs/openapi.json', + from: 'urlplaceholder', + to: 'https://cveawg.mitre.org/api' + }) } diff --git a/src/swagger.js b/src/swagger.js index 87c575408..2260212ce 100644 --- a/src/swagger.js +++ b/src/swagger.js @@ -14,7 +14,7 @@ const rejectedCreateCVERecord = require('../schemas/cve/rejected-create-cve-exam /* eslint-disable no-multi-str */ const doc = { info: { - version: '2.1.0', + version: '2.1.1', title: 'CVE Services API', description: "The CVE Services API supports automation tooling for the CVE Program. Credentials are \ required for most service endpoints. Representatives of \ @@ -28,13 +28,21 @@ const doc = { Red Hat) or \ Top-Level Root (CISA ICS \ or MITRE) to request credentials \ - ", + \ +CVE data is to be in the JSON 5.0 CVE Record format. Details of the JSON 5.0 schema are \ + located here.
\ + Contact the CVE Services team", contact: { - name: 'CVE Services', - url: 'https://github.com/CVEProject/cve-services', - email: 'cve-board-auto-list@mitre.org' + name: 'CVE Services Overview', + url: 'https://cveproject.github.io/automation-cve-services#services-overview' + } }, + servers: [ + { + url: 'urlplaceholder' + } + ], basePath: '/api', host: 'localhost:3000', schemes: [ @@ -227,7 +235,7 @@ const doc = { cveIdGetFilteredTimeReservedLt: { in: 'query', name: 'time_reserved.lt', - description: 'Most recent CVE ID reserved timestamp to retrieve', + description: 'Most recent reserved timestamp to retrieve. Include with all requests potentially returning multiple pages of CVE IDs to avoid issues if new IDs are reserved during use.', required: false, schema: { type: 'string', @@ -247,7 +255,7 @@ const doc = { cveIdGetFilteredTimeModifiedLt: { in: 'query', name: 'time_modified.lt', - description: 'Most recent CVE ID modified timestamp to retrieve', + description: 'Most recent modified timestamp to retrieve. Include with all requests using a time_modified.gt filter potentially returning multiple pages of CVE IDs. This will avoid issues if IDs are reserved or modified during use.', required: false, schema: { type: 'string', @@ -267,7 +275,7 @@ const doc = { cveRecordFilteredTimeModifiedLt: { in: 'query', name: 'time_modified.lt', - description: 'Most recent CVE entry modified timestamp to retrieve', + description: 'Most recent CVE record modified timestamp to retrieve', required: false, schema: { type: 'string', @@ -277,7 +285,7 @@ const doc = { cveRecordFilteredTimeModifiedGt: { in: 'query', name: 'time_modified.gt', - description: 'Earliest CVE entry modified timestamp to retrieve', + description: 'Earliest CVE record modified timestamp to retrieve', required: false, schema: { type: 'string', @@ -362,7 +370,7 @@ const doc = { org: { in: 'query', name: 'org', - description: 'The new owning_cna for the CVE ID entry', + description: 'The new owning_cna for the CVE ID', required: false, schema: { type: 'string' @@ -409,7 +417,7 @@ const doc = { state: { in: 'query', name: 'state', - description: 'The new state for the CVE ID entry', + description: 'The new state for the CVE ID', required: false, schema: { type: 'string' diff --git a/src/utils/data.js b/src/utils/data.js index f6f1b660c..2cbfac177 100644 --- a/src/utils/data.js +++ b/src/utils/data.js @@ -18,7 +18,7 @@ const uuid = require('uuid') const errors = require('../utils/error') const logger = require('../middleware/logger') const utils = require('../utils/utils') -const CONSTANTS = require('../constants') +const getConstants = require('../constants').getConstants const apiKeyFile = 'user-secret.txt' @@ -68,6 +68,7 @@ async function newUserTransform (user, hash) { if (process.env.NODE_ENV === 'development') { user.secret = hash } else if (process.env.NODE_ENV === 'integration') { + const CONSTANTS = getConstants() const randomKey = cryptoRandomString({ length: CONSTANTS.CRYPTO_RANDOM_STRING_LENGTH }) user.secret = await argon2.hash(randomKey) diff --git a/src/utils/utils.js b/src/utils/utils.js index 9c4569a6a..b6e7fbee4 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,6 +1,7 @@ const Org = require('../model/org') const User = require('../model/user') -const CONSTANTS = require('../constants') +const getConstants = require('../constants').getConstants +const validateDate = require('validate-date') async function getOrgUUID (shortName) { const org = await Org.findOne().byShortName(shortName) @@ -22,6 +23,7 @@ async function getUserUUID (userName, orgUUID) { async function isSecretariat (shortName) { let result = false + const CONSTANTS = getConstants() const orgUUID = await getOrgUUID(shortName) // may be null if org does not exists const secretariats = await Org.find({ 'authority.active_roles': { $in: [CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT] } }) @@ -38,6 +40,7 @@ async function isSecretariat (shortName) { async function isSecretariatUUID (orgUUID) { let result = false + const CONSTANTS = getConstants() const secretariats = await Org.find({ 'authority.active_roles': { $in: [CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT] } }) if (orgUUID) { @@ -53,6 +56,7 @@ async function isSecretariatUUID (orgUUID) { async function isAdmin (requesterUsername, requesterShortName) { let result = false + const CONSTANTS = getConstants() const requesterOrgUUID = await getOrgUUID(requesterShortName) // may be null if org does not exists if (requesterOrgUUID) { @@ -68,6 +72,7 @@ async function isAdmin (requesterUsername, requesterShortName) { async function isAdminUUID (requesterUsername, requesterOrgUUID) { let result = false + const CONSTANTS = getConstants() if (requesterOrgUUID) { const user = await User.findOne().byUserNameAndOrgUUID(requesterUsername, requesterOrgUUID) @@ -100,6 +105,30 @@ function reqCtxMapping (req, keyType, keys) { } } +// Sanitizer for dates +function toDate (val) { + val = val.toUpperCase() + let value = val.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(|Z|((-|\+|\s)\d{2}:\d{2}))$/) + let result = null + if (value) { + value[0] = value[0].replace(' ', '+') // Re-add literal '+' which was stripped + const dateStr = value[0] + // Make sure that the string passed is a valid date + // eslint doesn't like that responseType is not defined, but it is needed as is + /* eslint-disable-next-line */ + const valid = validateDate(dateStr.toString().substring(0, 10), responseType = 'boolean') + if (valid) { + result = new Date(dateStr) + } + } else { + value = val.match(/^\d{4}-\d{2}-\d{2}$/) + if (value) { + result = new Date(`${value[0]}T00:00:00.000+00:00`) + } + } + return result +} + module.exports = { isSecretariat, isAdmin, @@ -107,5 +136,6 @@ module.exports = { isSecretariatUUID, getOrgUUID, getUserUUID, - reqCtxMapping + reqCtxMapping, + toDate } diff --git a/test-http/src/test/cve_tests/cve.py b/test-http/src/test/cve_tests/cve.py index 7d183a3c1..280eabaad 100644 --- a/test-http/src/test/cve_tests/cve.py +++ b/test-http/src/test/cve_tests/cve.py @@ -358,6 +358,26 @@ def test_create_existent_cve(): response_contains_json(res, 'error', 'CVE_RECORD_EXISTS') +def test_create_unique_eng_cve(): + """ the cve record cannot be created because it already exists """ + with open('./src/test/cve_tests/cve_record_fixtures/CVE-2021-0004_published.json') as json_file: + data = json.load(json_file) + data['containers']['cna']['descriptions'].append({ + "lang": "en", + "value": "A second en entry" + }) + + res = requests.post( + f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004', + headers=utils.BASE_HEADERS, + json=data + ) + + res_json = json.loads(res.content.decode()) + + response_contains_json(res, 'error', 'BAD_INPUT') + assert res_json['details'][0]['param'] == "containers.cna.descriptions" + assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'containers.cna.descriptions'" #### POST /cve/:id/reject #### @@ -548,7 +568,7 @@ def test_submit_record_rejection_multiple_English_lang_entries(): # assert res_json['details']['errors'][0]['message'] == 'Cannot have more than one English language entry: en-gb.' response_contains_json(res, 'error', 'BAD_INPUT') assert res_json['details'][0]['param'] == "cnaContainer.rejectedReasons" - assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry 'en-gb'" + assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.rejectedReasons'" def test_update_record_rejection_multiple_English_lang_entries(): @@ -590,7 +610,7 @@ def test_update_record_rejection_multiple_English_lang_entries(): response_contains_json(res, 'error', 'BAD_INPUT') assert res_json['details'][0]['param'] == "cnaContainer.rejectedReasons" - assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry 'en-gb'" + assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.rejectedReasons'" #### PUT /cve/:id #### @@ -764,7 +784,7 @@ def get_res(test_filename): else: response_contains_json(res, 'error', 'BAD_INPUT', test_filename) assert res_json['details'][0]['param'] == "cnaContainer.descriptions" - assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry 'en'" + assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.descriptions'" @@ -842,7 +862,7 @@ def get_res(test_filename): else: response_contains_json(res, 'error', 'BAD_INPUT', test_filename) assert res_json['details'][0]['param'] == "cnaContainer.descriptions" - assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry 'en'" + assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.descriptions'" @@ -944,4 +964,21 @@ def test_cve_get_bad_page(): ) assert res.status_code == 400 response_contains_json(res, 'error', 'BAD_INPUT') - response_contains_json(res, 'details', utils.BAD_PAGE_ERROR_DETAILS) \ No newline at end of file + response_contains_json(res, 'details', utils.BAD_PAGE_ERROR_DETAILS) + + + +def test_get_cve_ensure_sorted(): + """ Should be ordered by CVE ID asc. """ + res = requests.get( + f'{env.AWG_BASE_URL}{CVE_URL}/', + headers=utils.BASE_HEADERS, + ) + + assert res.status_code == 200 + records = json.loads(res.content.decode())['cveRecords'] + + prev_id = "CVE-1900-0000" + for record in records: + assert record['cveMetadata']['cveId'] > prev_id + prev_id = record['cveMetadata']['cveId'] \ No newline at end of file diff --git a/test-utils/reserveCaseA.non-sequential.js b/test-utils/reserveCaseA.non-sequential.js index bb17850f3..b01f73956 100644 --- a/test-utils/reserveCaseA.non-sequential.js +++ b/test-utils/reserveCaseA.non-sequential.js @@ -2,7 +2,7 @@ require('dotenv').config() const CveId = require('../src/model/cve-id') const logger = require('../src/middleware/logger') -const CONSTANTS = require('../src/constants') +const getConstants = require('../src/constants').getConstants const errors = require('../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() const CONSOLE_OUTPUT = false @@ -51,6 +51,7 @@ async function nonSequentialReservation (year, amount, shortName, cnaShortName, const cveIdRepo = req.ctx.repositories.getCveIdRepository() const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const reqUUID = req.ctx.uuid + const CONSTANTS = getConstants() let isFull = false let available amount = parseInt(amount) diff --git a/test-utils/reserveCaseB.non-sequential.js b/test-utils/reserveCaseB.non-sequential.js index ee28c541c..709074263 100644 --- a/test-utils/reserveCaseB.non-sequential.js +++ b/test-utils/reserveCaseB.non-sequential.js @@ -2,7 +2,7 @@ require('dotenv').config() const CveId = require('../src/model/cve-id') const logger = require('../src/middleware/logger') -const CONSTANTS = require('../src/constants') +const getConstants = require('../src/constants').getConstants const errors = require('../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() const reservedByOther = [] @@ -52,6 +52,7 @@ async function nonSequentialReservation (year, amount, shortName, cnaShortName, const cveIdRepo = req.ctx.repositories.getCveIdRepository() const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const reqUUID = req.ctx.uuid + const CONSTANTS = getConstants() let isFull = false let available amount = parseInt(amount) diff --git a/test-utils/reserveCaseE.non-sequential.js b/test-utils/reserveCaseE.non-sequential.js index 1af681a4d..fd02b82fb 100644 --- a/test-utils/reserveCaseE.non-sequential.js +++ b/test-utils/reserveCaseE.non-sequential.js @@ -2,7 +2,7 @@ require('dotenv').config() const CveId = require('../src/model/cve-id') const logger = require('../src/middleware/logger') -const CONSTANTS = require('../src/constants') +const getConstants = require('../src/constants').getConstants const errors = require('../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() const reservedByOther = [] @@ -52,6 +52,7 @@ async function nonSequentialReservation (year, amount, shortName, cnaShortName, const cveIdRepo = req.ctx.repositories.getCveIdRepository() const cveIdRangeRepo = req.ctx.repositories.getCveIdRangeRepository() const reqUUID = req.ctx.uuid + const CONSTANTS = getConstants() let isFull = false let available amount = parseInt(amount) diff --git a/test-utils/reserveCaseF.non-sequential.js b/test-utils/reserveCaseF.non-sequential.js index f5cff4ef2..abc638b44 100644 --- a/test-utils/reserveCaseF.non-sequential.js +++ b/test-utils/reserveCaseF.non-sequential.js @@ -2,7 +2,7 @@ require('dotenv').config() const CveId = require('../src/model/cve-id') const logger = require('../src/middleware/logger') -const CONSTANTS = require('../src/constants') +const getConstants = require('../src/constants').getConstants const errors = require('../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() const reservedByOther = [] @@ -52,6 +52,7 @@ async function nonSequentialReservation (year, amount, shortName, cnaShortName, const orgRepo = req.ctx.repositories.getOrgRepository() const userRepo = req.ctx.repositories.getUserRepository() const reqUUID = req.ctx.uuid + const CONSTANTS = getConstants() let isFull = false let available amount = parseInt(amount) diff --git a/test-utils/reserveCaseG.non-sequential.js b/test-utils/reserveCaseG.non-sequential.js index b480e9c55..aec65bc43 100644 --- a/test-utils/reserveCaseG.non-sequential.js +++ b/test-utils/reserveCaseG.non-sequential.js @@ -2,7 +2,7 @@ require('dotenv').config() const CveId = require('../src/model/cve-id') const logger = require('../src/middleware/logger') -const CONSTANTS = require('../src/constants') +const getConstants = require('../src/constants').getConstants const errors = require('../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() const reservedByOther = [] @@ -52,6 +52,7 @@ async function nonSequentialReservation (year, amount, shortName, cnaShortName, const orgRepo = req.ctx.repositories.getOrgRepository() const userRepo = req.ctx.repositories.getUserRepository() const reqUUID = req.ctx.uuid + const CONSTANTS = getConstants() let isFull = false let available amount = parseInt(amount) diff --git a/test/unit-tests/cve-id/cveIdGetAllTest.js b/test/unit-tests/cve-id/cveIdGetAllTest.js index f3a8bc71f..a8ebd25a7 100644 --- a/test/unit-tests/cve-id/cveIdGetAllTest.js +++ b/test/unit-tests/cve-id/cveIdGetAllTest.js @@ -10,7 +10,6 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') const cveIdFixtures = require('./mockObjects.cve-id') const cveIdController = require('../../../src/controller/cve-id.controller/cve-id.controller') const cveIdParams = require('../../../src/controller/cve-id.controller/cve-id.middleware') @@ -535,7 +534,8 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { }) it('The secretariat gets a list of non-paginated cve ids', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 + const itemsPerPage = 3 + class MyOrgRepo { async getOrgUUID () { return cveIdFixtures.secretariatOrg.UUID @@ -562,7 +562,7 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { const res = { itemsList: [this.testRes1, this.testRes2], itemCount: 2, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 1, pagingCounter: 1, @@ -609,7 +609,8 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { }) it('The secretariat gets a list of paginated cve ids with "page" query param undefined', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 3 + const itemsPerPage = 3 + class MyOrgRepo { async getOrgUUID () { return cveIdFixtures.secretariatOrg.UUID @@ -648,7 +649,7 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { const res = { itemsList: [this.testRes1, this.testRes2, this.testRes3], itemCount: 5, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 2, pagingCounter: 1, @@ -668,6 +669,8 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { getOrgRepository: () => { return new MyOrgRepo() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, cveIdParams.parseGetParams, cveIdController.CVEID_GET_FILTER) @@ -684,7 +687,7 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(3) expect(res.body).to.have.property('totalCount').and.to.equal(5) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(1) expect(res.body).to.have.property('prevPage').and.to.equal(null) @@ -694,7 +697,8 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { }) it('The secretariat gets a list of paginated cve ids with "page" query param defined', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 3 + const itemsPerPage = 3 + class MyOrgRepo { async getOrgUUID () { return cveIdFixtures.secretariatOrg.UUID @@ -733,7 +737,7 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { const res = { itemsList: [this.testRes4, this.testRes3], itemCount: 5, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 2, pageCount: 2, pagingCounter: 1, @@ -753,6 +757,8 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { getOrgRepository: () => { return new MyOrgRepo() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, cveIdParams.parseGetParams, cveIdController.CVEID_GET_FILTER) @@ -769,7 +775,7 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(2) expect(res.body).to.have.property('totalCount').and.to.equal(5) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(2) expect(res.body).to.have.property('prevPage').and.to.equal(1) @@ -779,7 +785,8 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { }) it('The secretariat gets an empty list of cve ids because there are no cve ids in the database', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 + const itemsPerPage = 3 + class MyOrgRepo { async getOrgUUID () { return cveIdFixtures.secretariatOrg.UUID @@ -795,7 +802,7 @@ describe('Testing the GET /cve-id endpoint in CveId Controller', () => { const res = { itemsList: [], itemCount: 0, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 1, pagingCounter: 1, diff --git a/test/unit-tests/cve-id/cveIdRangeCreateTest.js b/test/unit-tests/cve-id/cveIdRangeCreateTest.js index 14cc25638..9782333c2 100644 --- a/test/unit-tests/cve-id/cveIdRangeCreateTest.js +++ b/test/unit-tests/cve-id/cveIdRangeCreateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const year22 = 2022 const errors = require('../../../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() @@ -60,6 +60,7 @@ describe('Testing the POST /cve-id-range/:year endpoint in CveId Controller', () it(`CveId Range already exists for year ${year22}`, (done) => { class CveIdRange2022Exists { constructor () { + const CONSTANTS = getConstants() this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) this.cveIdRange.cve_year = '2022' } diff --git a/test/unit-tests/cve-id/cveIdRegex.js b/test/unit-tests/cve-id/cveIdRegex.js index 0ab06366c..a82e93efb 100644 --- a/test/unit-tests/cve-id/cveIdRegex.js +++ b/test/unit-tests/cve-id/cveIdRegex.js @@ -1,39 +1,39 @@ const chai = require('chai') const expect = chai.expect -const constants = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants // #789 - don't allow lowercase CVE describe('CVE IDs should be well formed', () => { context('Negative tests', () => { it('should not match lowercase', () => { - expect('cve-2022-1234567890').to.not.match(constants.CVE_ID_REGEX) + expect('cve-2022-1234567890').to.not.match(getConstants().CVE_ID_REGEX) }) it('should not match invalid prefix', () => { - expect('abc-2022-1234567890').to.not.match(constants.CVE_ID_REGEX) + expect('abc-2022-1234567890').to.not.match(getConstants().CVE_ID_REGEX) }) it('should not match non-digit year', () => { - expect('CVE-abcd-1234567890').to.not.match(constants.CVE_ID_REGEX) + expect('CVE-abcd-1234567890').to.not.match(getConstants().CVE_ID_REGEX) }) it('should not match non-digit ID', () => { - expect('CVE-2022-abcdefghij').to.not.match(constants.CVE_ID_REGEX) + expect('CVE-2022-abcdefghij').to.not.match(getConstants().CVE_ID_REGEX) }) it("should not match years that aren't exactly 4 digits", () => { - expect('CVE-22-1234567890').to.not.match(constants.CVE_ID_REGEX) - expect('CVE-20222-1234567890').to.not.match(constants.CVE_ID_REGEX) + expect('CVE-22-1234567890').to.not.match(getConstants().CVE_ID_REGEX) + expect('CVE-20222-1234567890').to.not.match(getConstants().CVE_ID_REGEX) }) it("should not match IDs that aren't 4-19 digits", () => { - expect('CVE-2022-123').to.not.match(constants.CVE_ID_REGEX) - expect('CVE-2022-12345678901234567890').to.not.match(constants.CVE_ID_REGEX) + expect('CVE-2022-123').to.not.match(getConstants().CVE_ID_REGEX) + expect('CVE-2022-12345678901234567890').to.not.match(getConstants().CVE_ID_REGEX) }) it('should not match without dashes', () => { - expect('CVE20221234567890').to.not.match(constants.CVE_ID_REGEX) + expect('CVE20221234567890').to.not.match(getConstants().CVE_ID_REGEX) }) }) context('Positive tests', () => { it('should match uppercase', () => { - expect('CVE-2022-1234567890').to.match(constants.CVE_ID_REGEX) + expect('CVE-2022-1234567890').to.match(getConstants().CVE_ID_REGEX) }) it('should match IDs that are 4-19 digits', () => { const cveId = 'CVE-2022-' @@ -42,7 +42,7 @@ describe('CVE IDs should be well formed', () => { for (let i = 4; i < 20; i++) { // pad the end with a random number up to i const fullId = cveId.padEnd(cveId.length + i, Math.floor(Math.random() * 9)) - expect(fullId).to.match(constants.CVE_ID_REGEX, `Failed with ${fullId}`) + expect(fullId).to.match(getConstants().CVE_ID_REGEX, `Failed with ${fullId}`) } }) }) diff --git a/test/unit-tests/cve-id/cveIdUpdateTest.js b/test/unit-tests/cve-id/cveIdUpdateTest.js index a866c1585..5ac4cbfe2 100644 --- a/test/unit-tests/cve-id/cveIdUpdateTest.js +++ b/test/unit-tests/cve-id/cveIdUpdateTest.js @@ -48,6 +48,10 @@ class OrgModifyCveIdOrgAndStateModified { async getOrgUUID () { return cveIdFixtures.org.UUID } + + async findOneByShortName (shortName) { + return cveIdFixtures.org + } } class CveIdModifyCveIdOrgAndStateModified { @@ -69,6 +73,11 @@ class CveIdModifyCveIdOrgAndStateModified { async aggregate () { return [this.testRes1] } + + // Returns count less than quota for testing + async countDocuments (uuid, state) { + return 200 + } } describe('Testing the PUT /cve-id/:id endpoint in CveId Controller', () => { @@ -78,12 +87,21 @@ describe('Testing the PUT /cve-id/:id endpoint in CveId Controller', () => { async findOneByCveId () { return null } + + // Returns count less than quota for testing + async countDocuments (uuid, state) { + return 200 + } } class OrgModifyCveIdDoesntExist { async getOrgUUID () { return null } + + async findOneByShortName (shortName) { + return cveIdFixtures.org + } } app.route('/cve-id-modify-secretariat-cve-id-doesnt-exist/:id') @@ -120,6 +138,10 @@ describe('Testing the PUT /cve-id/:id endpoint in CveId Controller', () => { async getOrgUUID () { return null } + + async findOneByShortName (shortName) { + return cveIdFixtures.org + } } app.route('/cve-id-modify-org-doesnt-exist/:id') @@ -242,6 +264,11 @@ describe('Testing the PUT /cve-id/:id endpoint in CveId Controller', () => { async aggregate () { return [this.testRes1] } + + // Returns count less than quota for testing + async countDocuments (uuid, state) { + return 200 + } } app.route('/cve-id-modify-no-query/:id') diff --git a/test/unit-tests/cve-id/mockObjects.cve-id.js b/test/unit-tests/cve-id/mockObjects.cve-id.js index e59f09d24..7c81f6f23 100644 --- a/test/unit-tests/cve-id/mockObjects.cve-id.js +++ b/test/unit-tests/cve-id/mockObjects.cve-id.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const cveIdYear = '2017' const cveId = `CVE-${cveIdYear}-4024` diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/mockObjects.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/mockObjects.non-sequential.js index 664a274c6..7fe1279fb 100644 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/mockObjects.non-sequential.js +++ b/test/unit-tests/cve-id/reserveCveId.non-sequential/mockObjects.non-sequential.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../../src/constants') +const getConstants = require('../../../../src/constants').getConstants +const CONSTANTS = getConstants() const year = '3000' const secretariatHeader = { diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.non-sequential.js index 992860e8f..7d3c45968 100644 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.non-sequential.js +++ b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.non-sequential.js @@ -11,7 +11,7 @@ const middleware = require('../../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) const ids = [] -const CONSTANTS = require('../../../../src/constants') +const getConstants = require('../../../../src/constants').getConstants const errors = require('../../../../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() @@ -76,6 +76,8 @@ class CveIdReservePoolIncremented10Ids { class CveIdRangeReserveNonSequentialSuccess { constructor () { + const CONSTANTS = getConstants() + this.year = '3000' this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) this.cveIdRange.cve_year = this.year @@ -106,7 +108,6 @@ class CveIdRangeReserveNonSequentialSuccess { } const cveIdTestRepo = new CveIdReservePoolIncremented10Ids() -const cveIdRangeTestRepo = new CveIdRangeReserveNonSequentialSuccess() describe('Testing the non sequential reservation (Base Case) of POST /cve-id endpoint in CveId Controller', () => { context('Negative Tests', () => { @@ -222,13 +223,18 @@ describe('Testing the non sequential reservation (Base Case) of POST /cve-id end } } + const cveIdRepo = new CveIdReservePoolIncremented10Ids() + const cveIdRangeRepo = new CveIdRangeReserveNonSequentialSuccess() + const userRepo = new UserReserveNonSequentialSuccess() + const orgRepo = new OrgReserveNonSequentialSuccess() + app.route('/cve-id-reserve-nonsequential-3000-10-ids') .post((req, res, next) => { const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10Ids() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccess() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccess() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccess() } + getCveIdRepository: () => { return cveIdRepo }, + getCveIdRangeRepository: () => { return cveIdRangeRepo }, + getUserRepository: () => { return userRepo }, + getOrgRepository: () => { return orgRepo } } req.ctx.repositories = factory next() @@ -291,7 +297,7 @@ describe('Testing the non sequential reservation (Base Case) of POST /cve-id end expect(availableCounter).to.equal(100) // check that unreserved ids by userA are available - const rangeDoc = cveIdRangeTestRepo.getCveIdRange() + const rangeDoc = cveIdRangeRepo.getCveIdRange() const topId = rangeDoc.ranges.general.top_id const availableDocs = [] for (let i = 0; i < docs.length; i++) { diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.usersA_B.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.usersA_B.non-sequential.js index 9e8121d8f..fee9b72eb 100644 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.usersA_B.non-sequential.js +++ b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTest.usersA_B.non-sequential.js @@ -12,7 +12,7 @@ app.use(middleware.createCtxAndReqUUID) const idsA = [] const idsB = [] -const CONSTANTS = require('../../../../src/constants') +const getConstants = require('../../../../src/constants').getConstants const errors = require('../../../../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() @@ -77,6 +77,8 @@ class CveIdReservePoolIncremented10IdsCaseAB1 { class CveIdRangeReserveNonSequentialSuccessCaseAB1 { constructor () { + const CONSTANTS = getConstants() + this.year = '3000' this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) this.cveIdRange.cve_year = this.year @@ -169,6 +171,8 @@ class CveIdReservePoolIncremented10IdsCaseAB2 { class CveIdRangeReserveNonSequentialSuccessCaseAB2 { constructor () { + const CONSTANTS = getConstants() + this.year = '3000' this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) this.cveIdRange.cve_year = this.year @@ -253,20 +257,24 @@ class OrgReserveNonSequentialSuccessCaseAB { } const cveIdTestRepoAB1 = new CveIdReservePoolIncremented10IdsCaseAB1() -const cveIdRangeTestRepoAB1 = new CveIdRangeReserveNonSequentialSuccessCaseAB1() const cveIdTestRepoAB2 = new CveIdReservePoolIncremented10IdsCaseAB2() const cveIdRangeTestRepoAB2 = new CveIdRangeReserveNonSequentialSuccessCaseAB2() describe('Testing the non sequential reservation (Case AB) of POST /cve-id endpoint in CveId Controller', () => { context('Positive Tests', () => { it('User A reserves 10 ids', (done) => { + const cveIdRepo = new CveIdReservePoolIncremented10IdsCaseAB1() + const cveIdRangeRepo = new CveIdRangeReserveNonSequentialSuccessCaseAB1() + const userRepo = new UserReserveNonSequentialSuccessCaseAB() + const orgRepo = new OrgReserveNonSequentialSuccessCaseAB() + app.route('/cve-id-reserve-user-a-10-ids') .post((req, res, next) => { const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseAB1() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseAB1() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseAB() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseAB() } + getCveIdRepository: () => { return cveIdRepo }, + getCveIdRangeRepository: () => { return cveIdRangeRepo }, + getUserRepository: () => { return userRepo }, + getOrgRepository: () => { return orgRepo } } req.ctx.repositories = factory next() @@ -329,7 +337,7 @@ describe('Testing the non sequential reservation (Case AB) of POST /cve-id endpo expect(availableCounter).to.equal(15) // check that unreserved ids by userA are available - const rangeDoc = cveIdRangeTestRepoAB1.getCveIdRange() + const rangeDoc = cveIdRangeRepo.getCveIdRange() const topId = rangeDoc.ranges.general.top_id const availableDocs = [] for (let i = 0; i < docs.length; i++) { @@ -527,6 +535,8 @@ describe('Testing the non sequential reservation (Case AB) of POST /cve-id endpo class CveIdRangeReserveNonSequentialSuccessCaseAB3 { constructor () { + const CONSTANTS = getConstants() + this.year = '3000' this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) this.cveIdRange.cve_year = this.year diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestA.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestA.non-sequential.js deleted file mode 100644 index 2df6a888e..000000000 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestA.non-sequential.js +++ /dev/null @@ -1,225 +0,0 @@ -const express = require('express') -const app = express() -const chai = require('chai') -const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const ids = [] -const CONSTANTS = require('../../../../src/constants') -const cveIdNonSeqFixtures = require('./mockObjects.non-sequential') -const cveIdControllerA = require('../../../../test-utils/reserveCaseA.non-sequential') -const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware') - -class CveIdReservePoolIncremented10IdsCaseA { - constructor () { - this.docs = cveIdNonSeqFixtures.availableCveIdsA - } - - getCveIdDocuments () { - return this.docs - } - - async insertMany (documents) { - documents.forEach(doc => { - this.docs.push(doc) - }) - return documents - } - - async countDocuments () { - return 0 - } - - async find (query, options) { - const res = [] - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) { - if (res.length < options.limit) { - res.push(this.docs[i]) - } - } - } - - if (res.length === 0) { - return [] - } - - return res - } - - async findOneAndUpdate (query, updatedCveId) { - let index = -1 - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) { - index = i - break - } - } - - if (index >= 0) { - this.docs[index] = updatedCveId - return this.docs[index] - } - - return null - } -} - -class CveIdRangeReserveNonSequentialSuccessCaseA { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 20005 - this.cveIdRange.ranges.general.end = 30000 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne () { - return this.cveIdRange - } - - async findOneAndUpdate (query, set) { - if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined && - this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) { - this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id'] - return this.cveIdRange - } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - - return null - } -} - -const cveIdTestRepo = new CveIdReservePoolIncremented10IdsCaseA() -const cveIdRangeTestRepo = new CveIdRangeReserveNonSequentialSuccessCaseA() - -describe('Testing the non sequential reservation (Case A) of POST /cve-id endpoint in CveId Controller', () => { - context('Positive Tests', () => { - it('Pool is incremented, reservation fails, pool is updated, and 10 ids are reserved', (done) => { - class UserReserveNonSequentialSuccessCaseA { - async findOneByUserNameAndOrgUUID () { - return cveIdNonSeqFixtures.userA - } - } - - class OrgReserveNonSequentialSuccessCaseA { - async findOneByShortName () { - return cveIdNonSeqFixtures.orgA - } - - async getOrgUUID () { - return cveIdNonSeqFixtures.orgA.UUID - } - } - - app.route('/cve-id-reserve-a-pool-incremented-reservation-fails') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseA() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseA() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseA() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseA() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdControllerA.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-a-pool-incremented-reservation-fails?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userAHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10) - - // check that the reserved cve ids were reserved by userA - res.body.cve_ids.forEach(obj => { - ids.push(obj.cve_id) - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.greaterThan(20000).and.lessThan(20111) // Available id range: CVE-YYYY-20001 to CVE-YYYY-20110 - expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username) - }) - - // check that no duplicate cve ids were reserved - res.body.cve_ids.forEach(id1 => { - let counter = 0 - res.body.cve_ids.forEach(id2 => { - if (id1 === id2) { - counter++ - } - }) - expect(counter).to.equal(1) - }) - - // check total count of reserved ids by userA - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(10) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(100) - - // check that unreserved ids by userA are available - const rangeDoc = cveIdRangeTestRepo.getCveIdRange() - const topId = rangeDoc.ranges.general.top_id - const availableDocs = [] - for (let i = 0; i < docs.length; i++) { - let contains = false - for (let j = 0; j < ids.length; j++) { - if (docs[i].cve_id === ids[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) { - contains = true - break - } - } - if (!contains) { - availableDocs.push(docs[i]) - } - } - expect(availableDocs).to.have.lengthOf(100) - availableDocs.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id - expect(obj).to.have.property('state').and.to.equal('AVAILABLE') - expect(obj).to.have.property('owning_cna').and.to.equal('N/A') - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal('N/A') - expect(obj).to.have.nested.property('requested_by.user').and.to.equal('N/A') - }) - - done() - }) - }) - }) -}) diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestB.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestB.non-sequential.js deleted file mode 100644 index 84a0045db..000000000 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestB.non-sequential.js +++ /dev/null @@ -1,267 +0,0 @@ -const express = require('express') -const app = express() -const chai = require('chai') -const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const ids = [] -const CONSTANTS = require('../../../../src/constants') -const cveIdNonSeqFixtures = require('./mockObjects.non-sequential') -const cveIdControllerB = require('../../../../test-utils/reserveCaseB.non-sequential') -const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware') - -class CveIdReservePoolIncremented10IdsCaseB { - constructor () { - this.docs = cveIdNonSeqFixtures.availableCveIdsB - } - - getCveIdDocuments () { - return this.docs - } - - async insertMany (documents) { - documents.forEach(doc => { - this.docs.push(doc) - }) - return documents - } - - async countDocuments () { - return 0 - } - - async find (query, options) { - const res = [] - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) { - if (res.length < options.limit) { - res.push(this.docs[i]) - } - } - } - - if (res.length === 0) { - return [] - } - - return res - } - - async findOneAndUpdate (query, updatedCveId) { - let index = -1 - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) { - index = i - break - } - } - - if (index >= 0) { - this.docs[index] = updatedCveId - return this.docs[index] - } - - return null - } -} - -class CveIdRangeReserveNonSequentialSuccessCaseB { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 20005 - this.cveIdRange.ranges.general.end = 30000 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne () { - return this.cveIdRange - } - - async findOneAndUpdate (query, set) { - if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined && - this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) { - this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id'] - return this.cveIdRange - } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - - return null - } -} - -const cveIdTestRepo = new CveIdReservePoolIncremented10IdsCaseB() -const cveIdRangeTestRepo = new CveIdRangeReserveNonSequentialSuccessCaseB() - -describe('Testing the non sequential reservation (Case B) of POST /cve-id endpoint in CveId Controller', () => { - context('Positive Tests', () => { - it('Pool is incremented, reservation fails, pool is updated, pool is incremented, and 10 ids are reserved', (done) => { - class UserReserveNonSequentialSuccessCaseB { - async findOneByUserNameAndOrgUUID (username) { - if (username === cveIdNonSeqFixtures.secretariatUser.username) { - return cveIdNonSeqFixtures.secretariatUser - } - - return cveIdNonSeqFixtures.userA - } - } - - class OrgReserveNonSequentialSuccessCaseB { - async findOneByShortName () { - return cveIdNonSeqFixtures.orgA - } - - async getOrgUUID (shortname) { - if (shortname === cveIdNonSeqFixtures.secretariatOrg.short_name) { - return cveIdNonSeqFixtures.secretariatOrg.UUID - } - - return cveIdNonSeqFixtures.orgA.UUID - } - } - - app.route('/cve-id-reserve-b-pool-incremented-reservation-fails') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseB() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseB() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseB() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseB() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdControllerB.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-b-pool-incremented-reservation-fails?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userAHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10) - - // check that the reserved cve ids were reserved by userA - res.body.cve_ids.forEach(obj => { - ids.push(obj.cve_id) - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.greaterThan(20000).and.lessThan(20131) // Available id range: CVE-YYYY-20001 to CVE-YYYY-20130 - expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username) - }) - - // check that no duplicate cve ids were reserved - res.body.cve_ids.forEach(id1 => { - let counter = 0 - res.body.cve_ids.forEach(id2 => { - if (id1 === id2) { - counter++ - } - }) - expect(counter).to.equal(1) - }) - - // check total count of reserved ids by userA - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(10) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(100) - - // check that reserved ids by secretariat are reserved - const rangeDoc = cveIdRangeTestRepo.getCveIdRange() - const topId = rangeDoc.ranges.general.top_id - const reservedDocs = [] - - for (let i = 0; i < docs.length; i++) { - for (let j = 0; j < cveIdControllerB.reservedByOther.length; j++) { - if (docs[i].cve_id === cveIdControllerB.reservedByOther[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) { - reservedDocs.push(docs[i]) - break - } - } - } - expect(reservedDocs).to.have.lengthOf(20) - reservedDocs.forEach(obj => { - ids.push(obj.cve_id) - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id - expect(obj).to.have.property('state').and.to.equal('RESERVED') - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.secretariatOrg.UUID) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.secretariatUser.org_UUID) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.secretariatUser.UUID) - }) - - // check that no duplicate cve ids were reserved - reservedDocs.forEach(id1 => { - let counter = 0 - reservedDocs.forEach(id2 => { - if (id1 === id2) { - counter++ - } - }) - expect(counter).to.equal(1) - }) - - // check that unreserved ids by userA and secretariat are available - const availableDocs = [] - for (let i = 0; i < docs.length; i++) { - let contains = false - for (let j = 0; j < ids.length; j++) { - if (docs[i].cve_id === ids[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) { - contains = true - break - } - } - if (!contains) { - availableDocs.push(docs[i]) - } - } - - expect(availableDocs).to.have.lengthOf(100) - availableDocs.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id - expect(obj).to.have.property('state').and.to.equal('AVAILABLE') - expect(obj).to.have.property('owning_cna').and.to.equal('N/A') - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal('N/A') - expect(obj).to.have.nested.property('requested_by.user').and.to.equal('N/A') - }) - - done() - }) - }) - }) -}) diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestC_D.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestC_D.non-sequential.js deleted file mode 100644 index fb470fc88..000000000 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestC_D.non-sequential.js +++ /dev/null @@ -1,320 +0,0 @@ -const express = require('express') -const app = express() -const chai = require('chai') -const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const CONSTANTS = require('../../../../src/constants') -const errors = require('../../../../src/controller/cve-id.controller/error') -const error = new errors.CveIdControllerError() - -const cveIdNonSeqFixtures = require('./mockObjects.non-sequential') -const cveIdController = require('../../../../src/controller/cve-id.controller/cve-id.controller') -const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware') - -class CveIdReservePoolIncremented10IdsCaseCD { - constructor () { - this.docs = cveIdNonSeqFixtures.availableCveIdsC - } - - getCveIdDocuments () { - return this.docs - } - - async insertMany (documents) { - documents.forEach(doc => { - this.docs.push(doc) - }) - return documents - } - - async countDocuments () { - return 0 - } - - async find (query, options) { - const res = [] - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) { - if (res.length < options.limit) { - res.push(this.docs[i]) - } - } - } - - if (res.length === 0) { - return [] - } - - return res - } - - async findOneAndUpdate (query, updatedCveId) { - let index = -1 - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) { - index = i - break - } - } - - if (index >= 0) { - this.docs[index] = updatedCveId - return this.docs[index] - } - - return null - } -} - -const cveIdTestRepo = new CveIdReservePoolIncremented10IdsCaseCD() - -describe('Testing the non sequential reservation (Case C and D) of POST /cve-id endpoint in CveId Controller', () => { - context('Positive Tests (Case C)', () => { - it('Pool is incremented and 10 ids are reserved', (done) => { - class CveIdRangeReserveNonSequentialSuccessCaseC { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 1 - this.cveIdRange.ranges.general.start = 0 - this.cveIdRange.ranges.general.end = 10 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne () { - return this.cveIdRange - } - - async findOneAndUpdate (query, set) { - if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined && - this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) { - this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id'] - return this.cveIdRange - } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - - return null - } - } - - class UserReserveNonSequentialSuccess { - async findOneByUserNameAndOrgUUID () { - return cveIdNonSeqFixtures.userA - } - } - - class OrgReserveNonSequentialSuccess { - async isSecretariat () { - return false - } - - async findOneByShortName () { - return cveIdNonSeqFixtures.orgA - } - - async findOneAndUpdate (query) { - if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === false) { - cveIdNonSeqFixtures.orgA.inUse = true - return cveIdNonSeqFixtures.orgA - } else if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === true) { - cveIdNonSeqFixtures.orgA.inUse = false - return null - } - } - - async getOrgUUID () { - return cveIdNonSeqFixtures.orgA.UUID - } - } - - app.route('/cve-id-reserve-c-pool-incremented-10-ids') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseCD() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseC() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccess() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccess() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-c-pool-incremented-10-ids?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userAHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10) - - // check that the reserved cve ids were reserved by userA - res.body.cve_ids.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.greaterThan(0).and.lessThan(11) // Available id range: CVE-YYYY-20001 to CVE-YYYY-20010 - expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username) - }) - - // check that no duplicate cve ids were reserved - res.body.cve_ids.forEach(id1 => { - let counter = 0 - res.body.cve_ids.forEach(id2 => { - if (id1 === id2) { - counter++ - } - }) - expect(counter).to.equal(1) - }) - - // check total count of reserved ids by userA - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(10) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year.toString() && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(0) - done() - }) - }) - }) - - context('Negative Tests (Case D)', () => { - it(`CveId Range document for year ${cveIdNonSeqFixtures.year} is full`, (done) => { - class CveIdRangeReserveNonSequentialSuccessCaseD { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 10 - this.cveIdRange.ranges.general.start = 0 - this.cveIdRange.ranges.general.end = 10 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne () { - return this.cveIdRange - } - } - - class NullUserRepo { - async getUserUUID () { - return null - } - - async findOneByUserNameAndOrgUUID () { - return null - } - - async isAdmin () { - return null - } - } - - class OrgReserveNonSequentialSuccessCaseD { - async isSecretariat () { - return false - } - - async findOneByShortName () { - return cveIdNonSeqFixtures.orgB - } - - async findOneAndUpdate (query) { - if (query.short_name === cveIdNonSeqFixtures.orgB.short_name && cveIdNonSeqFixtures.orgB.inUse === false) { - cveIdNonSeqFixtures.orgB.inUse = true - return cveIdNonSeqFixtures.orgB - } else if (query.short_name === cveIdNonSeqFixtures.orgB.short_name && cveIdNonSeqFixtures.orgB.inUse === true) { - cveIdNonSeqFixtures.orgB.inUse = false - return null - } - } - } - - app.route('/cve-id-reserve-d-year-full') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseCD() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseD() }, - getUserRepository: () => { return new NullUserRepo() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseD() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-d-year-full?short_name=${cveIdNonSeqFixtures.orgB.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=5&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userBHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = cveIdNonSeqFixtures.orgB.policies.id_quota.toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(403) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.yearRangeFull(cveIdNonSeqFixtures.year) - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - - // check total count of reserved ids by userB - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgB.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(0) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(0) - done() - }) - }) - }) -}) diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestE.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestE.non-sequential.js deleted file mode 100644 index 938954c88..000000000 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestE.non-sequential.js +++ /dev/null @@ -1,215 +0,0 @@ -const express = require('express') -const app = express() -const chai = require('chai') -const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const CONSTANTS = require('../../../../src/constants') -const errors = require('../../../../src/controller/cve-id.controller/error') -const error = new errors.CveIdControllerError() - -const cveIdNonSeqFixtures = require('./mockObjects.non-sequential') -const cveIdControllerE = require('../../../../test-utils/reserveCaseE.non-sequential') -const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware') - -class CveIdReservePoolIncremented10IdsCaseE { - constructor () { - this.docs = cveIdNonSeqFixtures.cveIdsE - } - - getCveIdDocuments () { - return this.docs - } - - async countDocuments () { - return 0 - } - - async find (query, options) { - const res = [] - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) { - if (res.length < options.limit) { - res.push(this.docs[i]) - } - } - } - - if (res.length === 0) { - return [] - } - - return res - } - - async findOneAndUpdate (query, updatedCveId) { - let index = -1 - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) { - index = i - break - } - } - - if (index >= 0) { - this.docs[index] = updatedCveId - return this.docs[index] - } - - return null - } -} - -class CveIdRangeReserveNonSequentialSuccessCaseE { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 10 - this.cveIdRange.ranges.general.start = 0 - this.cveIdRange.ranges.general.end = 10 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne () { - return this.cveIdRange - } -} - -const cveIdTestRepo = new CveIdReservePoolIncremented10IdsCaseE() -const cveIdRangeTestRepo = new CveIdRangeReserveNonSequentialSuccessCaseE() - -describe('Testing the non sequential reservation (Case E) of POST /cve-id endpoint in CveId Controller', () => { - context('Negative Tests', () => { - it('Pool is incremented and 3 ids are reserved (partial error)', (done) => { - class UserReserveNonSequentialSuccessCaseE { - async findOneByUserNameAndOrgUUID (username) { - if (username === cveIdNonSeqFixtures.secretariatUser.username) { - return cveIdNonSeqFixtures.secretariatUser - } - - return cveIdNonSeqFixtures.userA - } - } - - class OrgReserveNonSequentialSuccessCaseE { - async findOneByShortName () { - return cveIdNonSeqFixtures.orgA - } - - async getOrgUUID (shortname) { - if (shortname === cveIdNonSeqFixtures.secretariatOrg.short_name) { - return cveIdNonSeqFixtures.secretariatOrg.UUID - } - - return cveIdNonSeqFixtures.orgA.UUID - } - } - - app.route('/cve-id-reserve-e-pool-incremented-3-ids') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseE() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseE() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseE() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseE() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdControllerE.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-e-pool-incremented-3-ids?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=5&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userAHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 3).toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(206) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.reservedPartialAmount(3, res.body.cve_ids) - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(3) - - // check that the reserved cve ids were reserved by userA - res.body.cve_ids.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.greaterThan(0).and.lessThan(8) // Available id range: CVE-YYYY-20001 to CVE-YYYY-20007 - expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username) - }) - - // check that no duplicate cve ids were reserved - res.body.cve_ids.forEach(id1 => { - let counter = 0 - res.body.cve_ids.forEach(id2 => { - if (id1 === id2) { - counter++ - } - }) - expect(counter).to.equal(1) - }) - - // check total count of reserved ids by userA - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(3) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(0) - - // check that unreserved ids by userA are reserved - const rangeDoc = cveIdRangeTestRepo.getCveIdRange() - const topId = rangeDoc.ranges.general.top_id - const reservedDocs = [] - - for (let i = 0; i < docs.length; i++) { - for (let j = 0; j < cveIdControllerE.reservedByOther.length; j++) { - if (docs[i].cve_id === cveIdControllerE.reservedByOther[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) { - reservedDocs.push(docs[i]) - break - } - } - } - expect(reservedDocs).to.have.lengthOf(4) - reservedDocs.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id - expect(obj).to.have.property('state').and.to.equal('RESERVED') - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.secretariatOrg.UUID) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.secretariatUser.org_UUID) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.secretariatUser.UUID) - }) - - done() - }) - }) - }) -}) diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestF.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestF.non-sequential.js deleted file mode 100644 index e7ce3de6f..000000000 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestF.non-sequential.js +++ /dev/null @@ -1,217 +0,0 @@ -const express = require('express') -const app = express() -const chai = require('chai') -const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const CONSTANTS = require('../../../../src/constants') -const errors = require('../../../../src/controller/cve-id.controller/error') -const error = new errors.CveIdControllerError() - -const cveIdNonSeqFixtures = require('./mockObjects.non-sequential') -const cveIdControllerF = require('../../../../test-utils/reserveCaseF.non-sequential') -const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware') - -class CveIdReservePoolIncremented10IdsCaseF { - constructor () { - this.docs = cveIdNonSeqFixtures.availableCveIdsF - } - - getCveIdDocuments () { - return this.docs - } - - async insertMany (documents) { - documents.forEach(doc => { - this.docs.push(doc) - }) - return documents - } - - async countDocuments () { - return 0 - } - - async find (query, options) { - const res = [] - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) { - if (res.length < options.limit) { - res.push(this.docs[i]) - } - } - } - - if (res.length === 0) { - return [] - } - - return res - } - - async findOneAndUpdate (query, updatedCveId) { - let index = -1 - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) { - index = i - break - } - } - - if (index >= 0) { - this.docs[index] = updatedCveId - return this.docs[index] - } - - return null - } -} - -class CveIdRangeReserveNonSequentialCaseF { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 15 - this.cveIdRange.ranges.general.end = 20 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne () { - return this.cveIdRange - } - - async findOneAndUpdate (query, set) { - if (query.$and !== undefined) { - if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined && - this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) { - this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id'] - return this.cveIdRange - } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - } else if (query.cve_year === this.year) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - - return null - } -} - -const cveIdTestRepo = new CveIdReservePoolIncremented10IdsCaseF() -const cveIdRangeTestRepo = new CveIdRangeReserveNonSequentialCaseF() - -describe('Testing the non sequential reservation (Case F) of POST /cve-id endpoint in CveId Controller', () => { - context('Negative Tests', () => { - it(`CveId Range document for year ${cveIdNonSeqFixtures.year} is full after race condition in pool increment`, (done) => { - class UserReserveNonSequentialCaseF { - async findOneByUserNameAndOrgUUID (username) { - if (username === cveIdNonSeqFixtures.secretariatUser.username) { - return cveIdNonSeqFixtures.secretariatUser - } - - return cveIdNonSeqFixtures.userA - } - } - - class OrgReserveNonSequentialCaseF { - async findOneByShortName () { - return cveIdNonSeqFixtures.orgA - } - - async getOrgUUID (shortname) { - if (shortname === cveIdNonSeqFixtures.secretariatOrg.short_name) { - return cveIdNonSeqFixtures.secretariatOrg.UUID - } - - return cveIdNonSeqFixtures.orgA.UUID - } - } - - app.route('/cve-id-reserve-f-year-full-after-race-condition') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseF() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialCaseF() }, - getUserRepository: () => { return new UserReserveNonSequentialCaseF() }, - getOrgRepository: () => { return new OrgReserveNonSequentialCaseF() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdControllerF.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-f-year-full-after-race-condition?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userAHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = cveIdNonSeqFixtures.orgA.policies.id_quota.toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(403) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.yearRangeFull(cveIdNonSeqFixtures.year) - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - - // check total count of reserved ids by userA - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(0) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(0) - - // check that unreserved ids by userA are reserved - const rangeDoc = cveIdRangeTestRepo.getCveIdRange() - const topId = rangeDoc.ranges.general.top_id - const reservedDocs = [] - - for (let i = 0; i < docs.length; i++) { - for (let j = 0; j < cveIdControllerF.reservedByOther.length; j++) { - if (docs[i].cve_id === cveIdControllerF.reservedByOther[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) { - reservedDocs.push(docs[i]) - break - } - } - } - expect(reservedDocs).to.have.lengthOf(20) - reservedDocs.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id - expect(obj).to.have.property('state').and.to.equal('RESERVED') - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.secretariatOrg.UUID) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.secretariatUser.org_UUID) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.secretariatUser.UUID) - }) - - done() - }) - }) - }) -}) diff --git a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestG.non-sequential.js b/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestG.non-sequential.js deleted file mode 100644 index 9dbe81a60..000000000 --- a/test/unit-tests/cve-id/reserveCveId.non-sequential/reserveCveIdTestG.non-sequential.js +++ /dev/null @@ -1,235 +0,0 @@ - -const express = require('express') -const app = express() -const chai = require('chai') -const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const CONSTANTS = require('../../../../src/constants') -const cveIdNonSeqFixtures = require('./mockObjects.non-sequential') -const cveIdControllerG = require('../../../../test-utils/reserveCaseG.non-sequential') -const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware') - -class CveIdReservePoolIncremented10IdsCaseG { - constructor () { - this.docs = cveIdNonSeqFixtures.availableCveIdsG - } - - getCveIdDocuments () { - return this.docs - } - - async insertMany (documents) { - documents.forEach(doc => { - this.docs.push(doc) - }) - return documents - } - - async countDocuments () { - return 0 - } - - async find (query, options) { - const res = [] - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) { - if (res.length < options.limit) { - res.push(this.docs[i]) - } - } - } - - if (res.length === 0) { - return [] - } - - return res - } - - async findOneAndUpdate (query, updatedCveId) { - let index = -1 - for (let i = 0; i < this.docs.length; i++) { - if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) { - index = i - break - } - } - - if (index >= 0) { - this.docs[index] = updatedCveId - return this.docs[index] - } - - return null - } -} - -class CveIdRangeReserveNonSequentialSuccessCaseG { - constructor () { - this.year = '3000' - this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE) - this.cveIdRange.cve_year = this.year - this.cveIdRange.ranges.general.top_id = 15 - this.cveIdRange.ranges.general.end = 20 - } - - getCveIdRange () { - return this.cveIdRange - } - - async findOne (query) { - expect(query).to.have.property('cve_year').and.to.be.a('string') - return this.cveIdRange - } - - async findOneAndUpdate (query, set) { - if (query.$and !== undefined) { - if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined && - this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) { - this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id'] - return this.cveIdRange - } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - } else if (query.cve_year === this.year) { - this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id'] - return this.cveIdRange - } - - return null - } -} - -const cveIdTestRepo = new CveIdReservePoolIncremented10IdsCaseG() -const cveIdRangeTestRepo = new CveIdRangeReserveNonSequentialSuccessCaseG() - -describe('Testing the non sequential reservation (Case G) of POST /cve-id endpoint in CveId Controller', () => { - context('Positive Tests', () => { - it('Pool is incremented and 10 ids are reserved', (done) => { - class UserReserveNonSequentialSuccessCaseG { - async findOneByUserNameAndOrgUUID (username) { - if (username === cveIdNonSeqFixtures.secretariatUser.username) { - return cveIdNonSeqFixtures.secretariatUser - } - - return cveIdNonSeqFixtures.userA - } - } - - class OrgReserveNonSequentialSuccessCaseG { - async findOneByShortName () { - return cveIdNonSeqFixtures.orgA - } - - async getOrgUUID (shortname) { - if (shortname === cveIdNonSeqFixtures.secretariatOrg.short_name) { - return cveIdNonSeqFixtures.secretariatOrg.UUID - } - - return cveIdNonSeqFixtures.orgA.UUID - } - } - - app.route('/cve-id-reserve-g-pool-incremented-10-ids') - .post((req, res, next) => { - const factory = { - getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseG() }, - getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseG() }, - getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseG() }, - getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseG() } - } - req.ctx.repositories = factory - next() - }, cveIdParams.parsePostParams, cveIdControllerG.CVEID_RESERVE) - - chai.request(app) - .post(`/cve-id-reserve-g-pool-incremented-10-ids?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) - .set(cveIdNonSeqFixtures.userAHeader) - .end((err, res) => { - if (err) { - done(err) - } - - const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString() - expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader) - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10) - - // check that the reserved cve ids were reserved by userA - res.body.cve_ids.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.greaterThan(0).and.lessThan(21) // Available id range: CVE-YYYY-0001 to CVE-YYYY-0020 - expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username) - }) - - // check that no duplicate cve ids were reserved - res.body.cve_ids.forEach(id1 => { - let counter = 0 - res.body.cve_ids.forEach(id2 => { - if (id1 === id2) { - counter++ - } - }) - expect(counter).to.equal(1) - }) - - // check total count of reserved ids by userA - const docs = cveIdTestRepo.getCveIdDocuments() - let reservedCounter = 0 - docs.forEach(doc => { - if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') { - reservedCounter++ - } - }) - expect(reservedCounter).to.equal(10) - - // check count of available ids - let availableCounter = 0 - docs.forEach(doc => { - if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') { - availableCounter++ - } - }) - expect(availableCounter).to.equal(0) - - // check that unreserved ids by userA are reserved - const rangeDoc = cveIdRangeTestRepo.getCveIdRange() - const topId = rangeDoc.ranges.general.top_id - const reservedDocs = [] - - for (let i = 0; i < docs.length; i++) { - for (let j = 0; j < cveIdControllerG.reservedByOther.length; j++) { - if (docs[i].cve_id === cveIdControllerG.reservedByOther[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) { - reservedDocs.push(docs[i]) - break - } - } - } - expect(reservedDocs).to.have.lengthOf(10) - reservedDocs.forEach(obj => { - const index = parseInt(obj.cve_id.match(/\d+$/g)) - expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id - expect(obj).to.have.property('state').and.to.equal('RESERVED') - expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.secretariatOrg.UUID) - expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.secretariatUser.org_UUID) - expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.secretariatUser.UUID) - }) - - done() - }) - }) - }) -}) diff --git a/test/unit-tests/cve-id/reserveCveId/cveIdReserveGeneralLogicTest.js b/test/unit-tests/cve-id/reserveCveId/cveIdReserveGeneralLogicTest.js index 9ff359a9e..ba156fa76 100644 --- a/test/unit-tests/cve-id/reserveCveId/cveIdReserveGeneralLogicTest.js +++ b/test/unit-tests/cve-id/reserveCveId/cveIdReserveGeneralLogicTest.js @@ -11,7 +11,7 @@ const middleware = require('../../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) const year20 = 2020 -const CONSTANTS = require('../../../../src/constants') +const getConstants = require('../../../../src/constants').getConstants const errors = require('../../../../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() @@ -287,6 +287,8 @@ describe('Testing the general logic of POST /cve-id endpoint in CveId Controller }) it('Amount query parameter is greater than max nonsequential amount allowed', (done) => { + const CONSTANTS = getConstants() + app.route('/cve-id-reserve-amount-greater-nonsequential') .post((req, res, next) => { const factory = { diff --git a/test/unit-tests/cve-id/reserveCveId/cveIdReservePriorityTest.js b/test/unit-tests/cve-id/reserveCveId/cveIdReservePriorityTest.js index 2dfec782d..3fa3727e1 100644 --- a/test/unit-tests/cve-id/reserveCveId/cveIdReservePriorityTest.js +++ b/test/unit-tests/cve-id/reserveCveId/cveIdReservePriorityTest.js @@ -12,7 +12,7 @@ app.use(middleware.createCtxAndReqUUID) const year20 = 2020 const year21 = 2021 -const CONSTANTS = require('../../../../src/constants') +const getConstants = require('../../../../src/constants').getConstants const errors = require('../../../../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() @@ -142,6 +142,8 @@ describe('Testing the priority reservation of POST /cve-id endpoint in CveId Con }) it('CveId Range document for year 2021 is full', (done) => { + const CONSTANTS = getConstants() + class CveIdRangeReserveSequentialIsFull { constructor () { this.year = '2021' @@ -215,6 +217,8 @@ describe('Testing the priority reservation of POST /cve-id endpoint in CveId Con context('Positive Tests', () => { it('Cve ID is reserved in the sequential block because the priority block for year 2021 is full', (done) => { + const CONSTANTS = getConstants() + class CveIdRangeReserveSequentialPriorityIsFull { constructor () { this.year = '2021' @@ -284,6 +288,8 @@ describe('Testing the priority reservation of POST /cve-id endpoint in CveId Con }) it('Cve ID is reserved in the priority block', (done) => { + const CONSTANTS = getConstants() + class CveIdRangeReserveSequentialPriority { constructor () { this.year = '2020' diff --git a/test/unit-tests/cve-id/reserveCveId/cveIdReserveSequentialTest.js b/test/unit-tests/cve-id/reserveCveId/cveIdReserveSequentialTest.js index 8a0759512..fb5f3385c 100644 --- a/test/unit-tests/cve-id/reserveCveId/cveIdReserveSequentialTest.js +++ b/test/unit-tests/cve-id/reserveCveId/cveIdReserveSequentialTest.js @@ -12,7 +12,7 @@ app.use(middleware.createCtxAndReqUUID) const year20 = 2020 const year21 = 2021 -const CONSTANTS = require('../../../../src/constants') +const getConstants = require('../../../../src/constants').getConstants const errors = require('../../../../src/controller/cve-id.controller/error') const error = new errors.CveIdControllerError() @@ -102,6 +102,8 @@ describe('Testing the sequential reservation of POST /cve-id endpoint in CveId C }) it('CveId Range document for year 2021 is full', (done) => { + const CONSTANTS = getConstants() + class CveIdReserveSequentialIsFull { async countDocuments () { return 2 @@ -161,6 +163,8 @@ describe('Testing the sequential reservation of POST /cve-id endpoint in CveId C context('Positive Tests', () => { it('Cve IDs are reserved for year 2020', (done) => { + const CONSTANTS = getConstants() + class CveIdReserveSequential { async insertMany () { return null diff --git a/test/unit-tests/cve/cveCnaContainerCreateTest.js b/test/unit-tests/cve/cveCnaContainerCreateTest.js index f4843bf1c..39e0b48ff 100644 --- a/test/unit-tests/cve/cveCnaContainerCreateTest.js +++ b/test/unit-tests/cve/cveCnaContainerCreateTest.js @@ -196,7 +196,7 @@ describe('Testing the POST /cve/:id/cna endpoint in Cve Controller', () => { }) }) - it('should return 500 when cve record is not valid', (done) => { + it('should return 400 when cve record is not valid', (done) => { chai.request(app) .post(`/cve-cna-negative-tests/${cveIdReserved}`) .set(cveFixtures.secretariatHeader) @@ -206,9 +206,9 @@ describe('Testing the POST /cve/:id/cna endpoint in Cve Controller', () => { done(err) } - expect(res).to.have.status(500) + expect(res).to.have.status(400) expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.serverError() + const errObj = error.invalidCnaContainerJsonSchema() expect(res.body.error).to.equal(errObj.error) expect(res.body.message).to.equal(errObj.message) done() diff --git a/test/unit-tests/cve/cveCnaContainerUpdateTest.js b/test/unit-tests/cve/cveCnaContainerUpdateTest.js index a0a232608..93497104c 100644 --- a/test/unit-tests/cve/cveCnaContainerUpdateTest.js +++ b/test/unit-tests/cve/cveCnaContainerUpdateTest.js @@ -19,7 +19,7 @@ const cveRecordPublished = require('../../schemas/5.0/CVE-2017-4024_published.js const errors = require('../../../src/controller/cve.controller/error') const error = new errors.CveControllerError() -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const cveFixtures = require('./mockObjects.cve') const cveController = require('../../../src/controller/cve.controller/cve.controller') const cveParams = require('../../../src/controller/cve.controller/cve.middleware') @@ -54,6 +54,8 @@ class MyUser { class MyCveIdNegativeTests { async findOneByCveId (id) { + const CONSTANTS = getConstants() + if (id === cveIdPublished5) { const fixture = Object.assign({}, cveFixtures.cvePublished5) fixture.state = CONSTANTS.CVE_STATES.REJECTED @@ -206,7 +208,7 @@ describe('Testing the PUT /cve/:id/cna endpoint in Cve Controller', () => { }) }) - it('should return 500 when cve record is not valid', (done) => { + it('should return 400 when cve record is not valid', (done) => { chai.request(app) .put(`/cve-cna-negative-tests/${cveIdPublished5}`) .set(cveFixtures.secretariatHeader) @@ -216,9 +218,9 @@ describe('Testing the PUT /cve/:id/cna endpoint in Cve Controller', () => { done(err) } - expect(res).to.have.status(500) + expect(res).to.have.status(400) expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.serverError() + const errObj = error.invalidCnaContainerJsonSchema() expect(res.body.error).to.equal(errObj.error) expect(res.body.message).to.equal(errObj.message) done() diff --git a/test/unit-tests/cve/cveCreateTest.js b/test/unit-tests/cve/cveCreateTest.js index 1631dad4c..728558df5 100644 --- a/test/unit-tests/cve/cveCreateTest.js +++ b/test/unit-tests/cve/cveCreateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const nonExistentCveId = 'CVE-2020-1425' const cveIdPublished5 = 'CVE-2017-4024' const cveIdReserved5 = 'CVE-2017-5833' @@ -157,6 +157,8 @@ describe('Testing the POST /cve/:id endpoint in Cve Controller', () => { }) it('should return 400 bad request because the cve record cannot be created in the RESERVED state', (done) => { + const CONSTANTS = getConstants() + chai.request(app) .post(`/cve-create-record-negative-tests/${cveIdReserved5}`) .set(cveFixtures.secretariatHeader) @@ -241,6 +243,7 @@ describe('Testing the POST /cve/:id endpoint in Cve Controller', () => { context('Positive Tests', () => { it('State PUBLISHED: should return the cve record because the cve record was created', (done) => { + const CONSTANTS = getConstants() const cveIdTestRepo = new MyCveIdPositiveTests() const doc = cveIdTestRepo.getCveIdPublished() // get internal state of cveId document expect(doc).to.have.property('cve_id').and.to.equal(cveIdPublished5) @@ -267,6 +270,7 @@ describe('Testing the POST /cve/:id endpoint in Cve Controller', () => { }) it('STATE REJECTED: should return the cve record because the cve record was created', (done) => { + const CONSTANTS = getConstants() const cveIdTestRepo = new MyCveIdPositiveTests() const doc = cveIdTestRepo.getCveIdRejected() // get internal state of cveId document expect(doc).to.have.property('cve_id').and.to.equal(cveIdRejected5) diff --git a/test/unit-tests/cve/cveGetAllTest.js b/test/unit-tests/cve/cveGetAllTest.js index f216fdda9..fea354ce6 100644 --- a/test/unit-tests/cve/cveGetAllTest.js +++ b/test/unit-tests/cve/cveGetAllTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const cveList = require('../../schemas/5.0/cveRecordList.json') const cveFixtures = require('./mockObjects.cve') @@ -20,13 +20,14 @@ const cveParams = require('../../../src/controller/cve.controller/cve.middleware describe('Testing the GET /cve endpoint in Cve Controller', () => { context('Positive Tests', () => { it('JSON schema v5.0 returned: The secretariat gets a list of non-paginated cve records', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 + const itemsPerPage = 500 + class MyCvePositiveTests { async aggregatePaginate () { const res = { itemsList: cveList, itemCount: cveList.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 1, pagingCounter: 1, @@ -67,6 +68,7 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { expect(res.body).to.not.have.property('prevPage') expect(res.body).to.not.have.property('nextPage') res.body.cveRecords.forEach(obj => { + const CONSTANTS = getConstants() // only cve records with state 'PUBLISHED' or 'REJECTED' are stored in the db expect(obj).to.have.nested.property('cveMetadata.state').and.to.be.oneOf([CONSTANTS.CVE_STATES.PUBLISHED, CONSTANTS.CVE_STATES.REJECTED]) }) @@ -75,13 +77,14 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { }) it('JSON schema v5.0 returned: The secretariat gets a list of paginated cve records with "page" query param undefined', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 3 + const itemsPerPage = 3 + class MyCvePositiveTests { async aggregatePaginate () { const res = { itemsList: [cveList[0], cveList[1], cveList[2]], itemCount: cveList.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 2, pagingCounter: 1, @@ -101,6 +104,8 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { getCveRepository: () => { return new MyCvePositiveTests() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, cveParams.parseGetParams, cveController.CVE_GET_FILTERED) @@ -112,11 +117,13 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { done(err) } + const CONSTANTS = getConstants() + expect(res).to.have.status(200) expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('cveRecords').and.to.be.a('array').and.to.have.lengthOf(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('cveRecords').and.to.be.a('array').and.to.have.lengthOf(itemsPerPage) expect(res.body).to.have.property('totalCount').and.to.equal(cveList.length) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(1) expect(res.body).to.have.property('prevPage').and.to.equal(null) @@ -130,13 +137,14 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { }) it('JSON schema v5.0 returned: The secretariat gets a list of paginated cve records with "page" query param defined', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 3 + const itemsPerPage = 3 + class MyCvePositiveTests { async aggregatePaginate () { const res = { itemsList: [cveList[3], cveList[4]], itemCount: cveList.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 2, pageCount: 2, pagingCounter: 1, @@ -156,6 +164,8 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { getCveRepository: () => { return new MyCvePositiveTests() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, cveParams.parseGetParams, cveController.CVE_GET_FILTERED) @@ -171,12 +181,13 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('cveRecords').and.to.be.a('array').and.to.have.lengthOf(2) expect(res.body).to.have.property('totalCount').and.to.equal(cveList.length) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(2) expect(res.body).to.have.property('prevPage').and.to.equal(1) expect(res.body).to.have.property('nextPage').and.to.equal(null) res.body.cveRecords.forEach(obj => { + const CONSTANTS = getConstants() // only cve records with state 'PUBLISHED' or 'REJECTED' are stored in the db expect(obj).to.have.nested.property('cveMetadata.state').and.to.be.oneOf([CONSTANTS.CVE_STATES.PUBLISHED, CONSTANTS.CVE_STATES.REJECTED]) }) @@ -185,13 +196,14 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { }) it('JSON schema v5.0 returned: The secretariat gets an empty list of cve records because there are no cve records in the database', (done) => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 + const itemsPerPage = 500 + class MyCvePositiveTests { async aggregatePaginate () { const res = { itemsList: [], itemCount: 0, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 1, pagingCounter: 1, @@ -265,6 +277,7 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { expect(res).to.have.status(200) expect(res).to.have.property('body').and.to.be.a('object') res.body.cveRecords.forEach(obj => { + const CONSTANTS = getConstants() // only cve records with state 'PUBLISHED' or 'REJECTED' are stored in the db expect(obj).to.have.nested.property('cveMetadata.state').and.to.be.oneOf([CONSTANTS.CVE_STATES.RESERVED, CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.PUBLISHED]) }) @@ -302,6 +315,7 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { expect(res).to.have.status(200) expect(res).to.have.property('body').and.to.be.a('object') res.body.cveRecords.forEach(obj => { + const CONSTANTS = getConstants() // only cve records with state 'PUBLISHED' or 'REJECTED' are stored in the db expect(obj).to.have.nested.property('cveMetadata.state').and.to.be.oneOf([CONSTANTS.CVE_STATES.RESERVED, CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.PUBLISHED]) }) @@ -339,6 +353,7 @@ describe('Testing the GET /cve endpoint in Cve Controller', () => { expect(res).to.have.status(200) expect(res).to.have.property('body').and.to.be.a('object') res.body.cveRecords.forEach(obj => { + const CONSTANTS = getConstants() // only cve records with state 'PUBLISHED' or 'REJECTED' are stored in the db expect(obj).to.have.nested.property('cveMetadata.state').and.to.be.oneOf([CONSTANTS.CVE_STATES.RESERVED, CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.PUBLISHED]) }) diff --git a/test/unit-tests/cve/cveGetSingleTest.js b/test/unit-tests/cve/cveGetSingleTest.js index 2502c584c..48c32fec5 100644 --- a/test/unit-tests/cve/cveGetSingleTest.js +++ b/test/unit-tests/cve/cveGetSingleTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const nonExistentCveRecord = 'CVE-2020-1425' const cveIdPublished5 = 'CVE-2017-4024' const cveIdRejected5 = 'CVE-2017-5835' @@ -86,6 +86,8 @@ describe('Testing the GET /cve/:id endpoint in Cve Controller', () => { done(err) } + const CONSTANTS = getConstants() + expect(res).to.have.status(200) expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.nested.property('cveMetadata.cveId').and.to.equal(cveIdPublished5) @@ -103,6 +105,8 @@ describe('Testing the GET /cve/:id endpoint in Cve Controller', () => { done(err) } + const CONSTANTS = getConstants() + expect(res).to.have.status(200) expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.nested.property('cveMetadata.cveId').and.to.equal(cveIdRejected5) diff --git a/test/unit-tests/cve/cveRecordRejectionTest.js b/test/unit-tests/cve/cveRecordRejectionTest.js index 0122872b0..e16e61577 100644 --- a/test/unit-tests/cve/cveRecordRejectionTest.js +++ b/test/unit-tests/cve/cveRecordRejectionTest.js @@ -17,7 +17,6 @@ const cveController = require('../../../src/controller/cve.controller/cve.contro const cveMiddleware = require('../../../src/controller/cve.controller/cve.middleware') const rejectedBody = require('../../../test-http/src/test/cve_tests/cve_record_fixtures/rejectBody.json') -const multipleEngDescriptions = require('../../../test-http/src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleSameEngValues.json') const nonExistentId = 'CVE-1800-0001' const cveIdReserved = 'CVE-2019-1421' @@ -138,25 +137,6 @@ describe('Testing the POST /cve/:id/reject endpoint in Cve Controller', () => { done() }) }) - - it('Submit a reject request for with multiple English descriptions, returns 400', (done) => { - chai.request(app) - .post(`/cve-reject-negative-tests/${cveIdReserved}`) - .set(cveFixtures.secretariatHeader) - .send(multipleEngDescriptions) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(400) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.cveDne() - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - done() - }) - }) }) context('Positive Tests', () => { diff --git a/test/unit-tests/cve/cveUniqueEnglishDescriptionTest.js b/test/unit-tests/cve/cveUniqueEnglishDescriptionTest.js new file mode 100644 index 000000000..48692b6ea --- /dev/null +++ b/test/unit-tests/cve/cveUniqueEnglishDescriptionTest.js @@ -0,0 +1,24 @@ +/* eslint-disable no-unused-expressions */ +// https://github.com/standard/standard/issues/690#issuecomment-278533482 +const chai = require('chai') +const expect = chai.expect + +const cveMiddleware = require('../../../src/controller/cve.controller/cve.middleware') +const rejectedBody = require('../../../test-http/src/test/cve_tests/cve_record_fixtures/rejectBody.json') +const multipleEngDescriptions = require('../../../test-http/src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleSameEngValues.json') + +describe('Testing the uniqueEnglishDescription middleware', () => { + context('Negative Tests', () => { + it('Submit a reject request with multiple English descriptions', () => { + const result = cveMiddleware.hasSingleEnglishEntry(multipleEngDescriptions.cnaContainer.rejectedReasons) + expect(result).to.be.false + }) + }) + + context('Positive Tests', () => { + it('Submit a reject request with single English descriptions', () => { + const result = cveMiddleware.hasSingleEnglishEntry(rejectedBody.cnaContainer.rejectedReasons) + expect(result).to.be.true + }) + }) +}) diff --git a/test/unit-tests/cve/cveUpdateTest.js b/test/unit-tests/cve/cveUpdateTest.js index 290f55cd0..356c9ed41 100644 --- a/test/unit-tests/cve/cveUpdateTest.js +++ b/test/unit-tests/cve/cveUpdateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const nonExistentCveId = 'CVE-2020-1425' const cveIdPublished5 = 'CVE-2017-4024' const cveIdReserved5 = 'CVE-2017-5833' @@ -259,6 +259,7 @@ describe('Testing the PUT /cve/:id endpoint in Cve Controller', () => { expect(res).to.have.status(400) expect(res).to.have.property('body').and.to.be.a('object') + const CONSTANTS = getConstants() const errObj = error.cveUpdateUnsupportedState(CONSTANTS.CVE_STATES.RESERVED) expect(res.body.error).to.equal(errObj.error) expect(res.body.message).to.equal(errObj.message) diff --git a/test/unit-tests/cve/mockObjects.cve.js b/test/unit-tests/cve/mockObjects.cve.js index 2282c07c3..6c8640408 100644 --- a/test/unit-tests/cve/mockObjects.cve.js +++ b/test/unit-tests/cve/mockObjects.cve.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const cveIdPublished5 = 'CVE-2017-4024' const cveIdRejected5 = 'CVE-2017-5835' const cvePublishedPass5 = require('../../schemas/5.0/' + cveIdPublished5 + '_published.json') diff --git a/test/unit-tests/middleware/cnaMustOwnId.fixtures.js b/test/unit-tests/middleware/cnaMustOwnId.fixtures.js index 4a6d4f3d2..b850dd66e 100644 --- a/test/unit-tests/middleware/cnaMustOwnId.fixtures.js +++ b/test/unit-tests/middleware/cnaMustOwnId.fixtures.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const owningOrgHeader = { 'content-type': 'application/json', diff --git a/test/unit-tests/middleware/mockObjects.middleware.js b/test/unit-tests/middleware/mockObjects.middleware.js index ebf8cb8ec..81fdfd9ce 100644 --- a/test/unit-tests/middleware/mockObjects.middleware.js +++ b/test/unit-tests/middleware/mockObjects.middleware.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const secretariatHeaders = { 'content-type': 'application/json', diff --git a/test/unit-tests/middleware/onlyCnas.fixtures.js b/test/unit-tests/middleware/onlyCnas.fixtures.js index 755a8f177..0ca3e04b5 100644 --- a/test/unit-tests/middleware/onlyCnas.fixtures.js +++ b/test/unit-tests/middleware/onlyCnas.fixtures.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const secretariatHeaders = { 'content-type': 'application/json', diff --git a/test/unit-tests/middleware/onlySecretariat.fixtures.js b/test/unit-tests/middleware/onlySecretariat.fixtures.js index cce14e119..c8c0d7087 100644 --- a/test/unit-tests/middleware/onlySecretariat.fixtures.js +++ b/test/unit-tests/middleware/onlySecretariat.fixtures.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const secretariatHeaders = { 'content-type': 'application/json', diff --git a/test/unit-tests/middleware/onlySecretariatMiddlewareTest.js b/test/unit-tests/middleware/onlySecretariatMiddlewareTest.js index eb86744d5..0435e10b4 100644 --- a/test/unit-tests/middleware/onlySecretariatMiddlewareTest.js +++ b/test/unit-tests/middleware/onlySecretariatMiddlewareTest.js @@ -11,7 +11,7 @@ const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) const mwFixtures = require('./onlySecretariat.fixtures') -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/middleware/error') const error = new errors.MiddlewareError() @@ -73,6 +73,8 @@ describe('Test only Secretariat middleware', () => { }) const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) + const CONSTANTS = getConstants() + testHeaders[CONSTANTS.AUTH_HEADERS.USER] = mwFixtures.notSecretariatUser.username testHeaders[CONSTANTS.AUTH_HEADERS.ORG] = mwFixtures.notSecretariatOrg.short_name diff --git a/test/unit-tests/middleware/onlySecretariatOrAdmin.fixtures.js b/test/unit-tests/middleware/onlySecretariatOrAdmin.fixtures.js index cee3daa4c..b92dbc149 100644 --- a/test/unit-tests/middleware/onlySecretariatOrAdmin.fixtures.js +++ b/test/unit-tests/middleware/onlySecretariatOrAdmin.fixtures.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const secretariatHeaders = { 'content-type': 'application/json', diff --git a/test/unit-tests/middleware/validateUserTest.js b/test/unit-tests/middleware/validateUserTest.js index 81cca3ba5..61a41d62b 100644 --- a/test/unit-tests/middleware/validateUserTest.js +++ b/test/unit-tests/middleware/validateUserTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/middleware/error') const error = new errors.MiddlewareError() @@ -81,6 +81,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) testHeaders[CONSTANTS.AUTH_HEADERS.ORG] = 'jpmorgan' @@ -115,6 +116,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) testHeaders[CONSTANTS.AUTH_HEADERS.USER] = 'morgan' @@ -149,6 +151,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) testHeaders[CONSTANTS.AUTH_HEADERS.KEY] = 'wrong secret' @@ -189,6 +192,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const deactivatedHeaders = {} deactivatedHeaders[CONSTANTS.AUTH_HEADERS.ORG] = 'mitre' deactivatedHeaders[CONSTANTS.AUTH_HEADERS.KEY] = 'S96E4QT-SMT4YE3-KX03X6K-4615CED' @@ -226,6 +230,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) delete testHeaders[CONSTANTS.AUTH_HEADERS.ORG] @@ -260,6 +265,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) delete testHeaders[CONSTANTS.AUTH_HEADERS.USER] @@ -294,6 +300,7 @@ describe('Testing the user validation middleware', () => { return res.status(200).json({ message: 'Success! You have reached the target endpoint.' }) }) + const CONSTANTS = getConstants() const testHeaders = Object.assign({}, mwFixtures.secretariatHeaders) delete testHeaders[CONSTANTS.AUTH_HEADERS.KEY] diff --git a/test/unit-tests/org/mockObjects.org.js b/test/unit-tests/org/mockObjects.org.js index 790def2fd..427415625 100644 --- a/test/unit-tests/org/mockObjects.org.js +++ b/test/unit-tests/org/mockObjects.org.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const secretariatHeader = { 'content-type': 'application/json', diff --git a/test/unit-tests/org/orgCreateTest.js b/test/unit-tests/org/orgCreateTest.js index 5678fd6ad..d884745d0 100644 --- a/test/unit-tests/org/orgCreateTest.js +++ b/test/unit-tests/org/orgCreateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -94,6 +94,8 @@ class OrgCreatedIdQuotaNullUndefined { } async aggregate () { + const CONSTANTS = getConstants() + this.testRes1 = JSON.parse(JSON.stringify(orgFixtures.nonExistentOrg)) this.testRes1.policies.id_quota = CONSTANTS.DEFAULT_ID_QUOTA @@ -203,6 +205,7 @@ describe('Testing the POST /org endpoint in Org Controller', () => { next() }, orgParams.parsePostParams, orgController.ORG_CREATE_SINGLE) + const CONSTANTS = getConstants() const testOrg = JSON.parse(JSON.stringify(orgFixtures.existentOrg)) delete testOrg.UUID @@ -233,6 +236,7 @@ describe('Testing the POST /org endpoint in Org Controller', () => { next() }, orgParams.parsePostParams, orgController.ORG_CREATE_SINGLE) + const CONSTANTS = getConstants() const testOrg = JSON.parse(JSON.stringify(orgFixtures.nonExistentOrg)) delete testOrg.UUID delete testOrg.authority.active_roles @@ -270,6 +274,7 @@ describe('Testing the POST /org endpoint in Org Controller', () => { next() }, orgParams.parsePostParams, orgController.ORG_CREATE_SINGLE) + const CONSTANTS = getConstants() const testOrg = JSON.parse(JSON.stringify(orgFixtures.nonExistentOrg)) delete testOrg.UUID delete testOrg.policies.id_quota @@ -301,6 +306,7 @@ describe('Testing the POST /org endpoint in Org Controller', () => { next() }, orgParams.parsePostParams, orgController.ORG_CREATE_SINGLE) + const CONSTANTS = getConstants() const testOrg = JSON.parse(JSON.stringify(orgFixtures.nonExistentOrg)) delete testOrg.UUID testOrg.policies.id_quota = null diff --git a/test/unit-tests/org/orgGetAllTest.js b/test/unit-tests/org/orgGetAllTest.js index deb408ba8..ac125d857 100644 --- a/test/unit-tests/org/orgGetAllTest.js +++ b/test/unit-tests/org/orgGetAllTest.js @@ -10,7 +10,6 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') const orgFixtures = require('./mockObjects.org') const orgController = require('../../../src/controller/org.controller/org.controller') const orgParams = require('../../../src/controller/org.controller/org.middleware') @@ -18,13 +17,14 @@ const orgParams = require('../../../src/controller/org.controller/org.middleware describe('Testing the GET /org endpoint in Org Controller', () => { context('Positive Tests', () => { it('Page query param not provided: should list non-paginated orgs because orgs fit in one page', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 + const itemsPerPage = 500 + class GetAllOrgs { async aggregatePaginate () { const res = { itemsList: orgFixtures.allOrgs, itemCount: orgFixtures.allOrgs.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 1, pagingCounter: 1, @@ -63,13 +63,14 @@ describe('Testing the GET /org endpoint in Org Controller', () => { }) it('Page query param not provided: should list the users in two pages (page 1/2)', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 5 + const itemsPerPage = 5 + class GetAllOrgs { async aggregatePaginate () { const res = { itemsList: [orgFixtures.allOrgs[0], orgFixtures.allOrgs[1], orgFixtures.allOrgs[3], orgFixtures.allOrgs[3], orgFixtures.allOrgs[4]], itemCount: orgFixtures.allOrgs.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 2, pagingCounter: 1, @@ -88,6 +89,8 @@ describe('Testing the GET /org endpoint in Org Controller', () => { getOrgRepository: () => { return new GetAllOrgs() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, orgParams.parseGetParams, orgController.ORG_ALL) @@ -100,7 +103,7 @@ describe('Testing the GET /org endpoint in Org Controller', () => { expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('organizations').and.to.be.a('array').and.to.have.lengthOf(5) expect(res.body).to.have.property('totalCount').and.to.equal(orgFixtures.allOrgs.length) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(1) expect(res.body).to.have.property('prevPage').and.to.equal(null) @@ -108,13 +111,14 @@ describe('Testing the GET /org endpoint in Org Controller', () => { }) it('Page query param provided: should list the users in two pages (page 2/2)', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 5 + const itemsPerPage = 5 + class GetAllOrgs { async aggregatePaginate () { const res = { itemsList: [orgFixtures.allOrgs[5], orgFixtures.allOrgs[6], orgFixtures.allOrgs[7], orgFixtures.allOrgs[8]], itemCount: orgFixtures.allOrgs.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 2, pageCount: 2, pagingCounter: 1, @@ -133,6 +137,8 @@ describe('Testing the GET /org endpoint in Org Controller', () => { getOrgRepository: () => { return new GetAllOrgs() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, orgParams.parseGetParams, orgController.ORG_ALL) @@ -145,7 +151,7 @@ describe('Testing the GET /org endpoint in Org Controller', () => { expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('organizations').and.to.be.a('array').and.to.have.lengthOf(4) expect(res.body).to.have.property('totalCount').and.to.equal(orgFixtures.allOrgs.length) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(2) expect(res.body).to.have.property('prevPage').and.to.equal(1) @@ -153,13 +159,14 @@ describe('Testing the GET /org endpoint in Org Controller', () => { }) it('Page query param provided: should return an empty list because no org exists', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 + const itemsPerPage = 5 + class GetAllOrgs { async aggregatePaginate () { const res = { itemsList: [], itemCount: 0, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 1, pagingCounter: 1, diff --git a/test/unit-tests/org/orgGetIdQuotaTest.js b/test/unit-tests/org/orgGetIdQuotaTest.js index c3197cfe2..cd3f84326 100644 --- a/test/unit-tests/org/orgGetIdQuotaTest.js +++ b/test/unit-tests/org/orgGetIdQuotaTest.js @@ -11,7 +11,7 @@ const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) const Org = require('../../../src/model/org') -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -25,6 +25,8 @@ describe('Testing the GET /org/:shortname/id_quota endpoint in Org Controller', const org = new Org(orgFixtures.orgWithNegativeIdQuota) org.validate((err) => { + const CONSTANTS = getConstants() + expect(err.errors['policies.id_quota'].message).to.equal(CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min_message) done() }) @@ -34,6 +36,8 @@ describe('Testing the GET /org/:shortname/id_quota endpoint in Org Controller', const org = new Org(orgFixtures.orgExceedingMaxIdQuota) org.validate((err) => { + const CONSTANTS = getConstants() + expect(err.errors['policies.id_quota'].message).to.equal(CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max_message) done() }) diff --git a/test/unit-tests/org/orgUpdateTest.js b/test/unit-tests/org/orgUpdateTest.js index a772b77e9..f723e542d 100644 --- a/test/unit-tests/org/orgUpdateTest.js +++ b/test/unit-tests/org/orgUpdateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -133,6 +133,8 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { context('Positive Tests', () => { it('Org is updated: Adding a role', (done) => { + const CONSTANTS = getConstants() + app.route('/org-updated-adding-role-1/:shortname') .put((req, res, next) => { const factory = { @@ -166,6 +168,8 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { }) it('Org is unchanged: Adding a role that the org already have', (done) => { + const CONSTANTS = getConstants() + app.route('/org-updated-adding-role-2/:shortname') .put((req, res, next) => { const factory = { @@ -199,6 +203,8 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { }) it('Org is updated: Removing a role', (done) => { + const CONSTANTS = getConstants() + app.route('/org-updated-removing-role-1/:shortname') .put((req, res, next) => { const factory = { @@ -231,6 +237,8 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { }) it('Org is unchanged: Removing a role that the org does not have', (done) => { + const CONSTANTS = getConstants() + app.route('/org-updated-removing-role-2/:shortname') .put((req, res, next) => { const factory = { diff --git a/test/unit-tests/user/mockObjects.user.js b/test/unit-tests/user/mockObjects.user.js index 790def2fd..427415625 100644 --- a/test/unit-tests/user/mockObjects.user.js +++ b/test/unit-tests/user/mockObjects.user.js @@ -1,4 +1,5 @@ -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants +const CONSTANTS = getConstants() const secretariatHeader = { 'content-type': 'application/json', diff --git a/test/unit-tests/user/userCreateTest.js b/test/unit-tests/user/userCreateTest.js index 38e5e57db..576586952 100644 --- a/test/unit-tests/user/userCreateTest.js +++ b/test/unit-tests/user/userCreateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -80,6 +80,8 @@ class OrgCreatedUserWithRole { class UserCreatedAdminWithRole { constructor () { + const CONSTANTS = getConstants() + this.testRes1 = JSON.parse(JSON.stringify(userFixtures.userC)) this.testRes1.authority.active_roles[0] = CONSTANTS.USER_ROLE_ENUM.ADMIN } @@ -318,6 +320,8 @@ describe('Testing the POST /org/:shortname/user endpoint in Org Controller', () it('Requester is secretariat and not Admin: User is created with the "ADMIN" role', done => { class UserCreatedWithRole { constructor () { + const CONSTANTS = getConstants() + this.testRes1 = JSON.parse(JSON.stringify(userFixtures.userA)) this.testRes1.authority.active_roles[0] = CONSTANTS.USER_ROLE_ENUM.ADMIN } diff --git a/test/unit-tests/user/userGetAllTest.js b/test/unit-tests/user/userGetAllTest.js index d0c9db4af..a8d02cb21 100644 --- a/test/unit-tests/user/userGetAllTest.js +++ b/test/unit-tests/user/userGetAllTest.js @@ -10,7 +10,6 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -221,7 +220,6 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () }) it('Page query param not provided: should list non-paginated users because users fit in one page', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 class GetOrgUUID { async getOrgUUID () { return orgFixtures.owningOrg.UUID @@ -237,7 +235,7 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () const res = { itemsList: orgFixtures.allOwningOrgUsers, itemCount: orgFixtures.allOwningOrgUsers.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: 500, currentPage: 1, pageCount: 1, pagingCounter: 1, @@ -277,7 +275,8 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () }) it('Page query param not provided: should list the users for cisco org in two pages (page 1/2)', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 3 + const itemsPerPage = 3 + class GetOrgUUID { async getOrgUUID () { return orgFixtures.owningOrg.UUID @@ -293,7 +292,7 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () const res = { itemsList: [orgFixtures.allOwningOrgUsers[0], orgFixtures.allOwningOrgUsers[1], orgFixtures.allOwningOrgUsers[2]], itemCount: orgFixtures.allOwningOrgUsers.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: itemsPerPage, currentPage: 1, pageCount: 2, pagingCounter: 1, @@ -313,6 +312,8 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () getUserRepository: () => { return new GetAllOrgUsers() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = itemsPerPage next() }, orgParams.parseGetParams, orgController.USER_ALL) @@ -325,7 +326,7 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('users').and.to.be.a('array').and.to.have.lengthOf(3) expect(res.body).to.have.property('totalCount').and.to.equal(orgFixtures.allOwningOrgUsers.length) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(itemsPerPage) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(1) expect(res.body).to.have.property('prevPage').and.to.equal(null) @@ -333,7 +334,6 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () }) it('Page query param provided: should list the users for cisco org in two pages (page 2/2)', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 3 class GetOrgUUID { async getOrgUUID () { return orgFixtures.owningOrg.UUID @@ -349,7 +349,7 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () const res = { itemsList: [orgFixtures.allOwningOrgUsers[3], orgFixtures.allOwningOrgUsers[4]], itemCount: orgFixtures.allOwningOrgUsers.length, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: 3, currentPage: 2, pageCount: 2, pagingCounter: 1, @@ -369,6 +369,8 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () getUserRepository: () => { return new GetAllOrgUsers() } } req.ctx.repositories = factory + // temporary fix for #920: force pagnation + req.TEST_PAGINATOR_LIMIT = 3 next() }, orgParams.parseGetParams, orgController.USER_ALL) @@ -381,7 +383,7 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () expect(res).to.have.property('body').and.to.be.a('object') expect(res.body).to.have.property('users').and.to.be.a('array').and.to.have.lengthOf(2) expect(res.body).to.have.property('totalCount').and.to.equal(orgFixtures.allOwningOrgUsers.length) - expect(res.body).to.have.property('itemsPerPage').and.to.equal(CONSTANTS.PAGINATOR_OPTIONS.limit) + expect(res.body).to.have.property('itemsPerPage').and.to.equal(3) expect(res.body).to.have.property('pageCount').and.to.equal(2) expect(res.body).to.have.property('currentPage').and.to.equal(2) expect(res.body).to.have.property('prevPage').and.to.equal(1) @@ -389,7 +391,6 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () }) it('Page query param provided: should return an empty list because no user exist for stark org', async () => { - CONSTANTS.PAGINATOR_OPTIONS.limit = 500 class GetOrgUUID { async getOrgUUID () { return orgFixtures.owningOrg.UUID @@ -405,7 +406,7 @@ describe('Testing the GET /org/:shortname/users endpoint in Org Controller', () const res = { itemsList: [], itemCount: 0, - itemsPerPage: CONSTANTS.PAGINATOR_OPTIONS.limit, + itemsPerPage: 500, currentPage: 1, pageCount: 1, pagingCounter: 1, diff --git a/test/unit-tests/user/userResetSecretTest.js b/test/unit-tests/user/userResetSecretTest.js index 54883d931..27a48ef7d 100644 --- a/test/unit-tests/user/userResetSecretTest.js +++ b/test/unit-tests/user/userResetSecretTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -414,6 +414,7 @@ describe('Testing the PUT /org/:shortname/user/:username/reset_secret endpoint i next() }, orgParams.parsePostParams, orgController.USER_RESET_SECRET) + const CONSTANTS = getConstants() userFixtures.userA.authority.active_roles = [CONSTANTS.USER_ROLE_ENUM.ADMIN] chai.request(app) diff --git a/test/unit-tests/user/userUpdateTest.js b/test/unit-tests/user/userUpdateTest.js index 890eae3c0..80b5d400a 100644 --- a/test/unit-tests/user/userUpdateTest.js +++ b/test/unit-tests/user/userUpdateTest.js @@ -10,7 +10,7 @@ app.use(express.urlencoded({ extended: false })) // Allows us to handle url enco const middleware = require('../../../src/middleware/middleware') app.use(middleware.createCtxAndReqUUID) -const CONSTANTS = require('../../../src/constants') +const getConstants = require('../../../src/constants').getConstants const errors = require('../../../src/controller/org.controller/error') const error = new errors.OrgControllerError() @@ -55,11 +55,15 @@ class UserUpdatedAddingRole { secret: userFixtures.existentUserDummy.secret } + const CONSTANTS = getConstants() + this.testRes1 = JSON.parse(JSON.stringify(userFixtures.existentUserDummy)) this.testRes1.authority.active_roles = [CONSTANTS.USER_ROLE_ENUM.ADMIN] } getUser () { + const CONSTANTS = getConstants() + this.user.authority.active_roles.push(CONSTANTS.USER_ROLE_ENUM.ADMIN) return this.user } @@ -438,6 +442,7 @@ describe('Testing the PUT /org/:shortname/user/:username endpoint in Org Control next() }, orgParams.parsePostParams, orgController.USER_UPDATE_SINGLE) + const CONSTANTS = getConstants() const testUser = Object.assign({}, userFixtures.existentUserDummy) testUser.authority = { active_roles: [CONSTANTS.USER_ROLE_ENUM.ADMIN] @@ -472,6 +477,8 @@ describe('Testing the PUT /org/:shortname/user/:username endpoint in Org Control it('User is unchanged: Adding a user role that the user already have', (done) => { class UserUpdatedAddingRoleAlreadyExists { constructor () { + const CONSTANTS = getConstants() + this.user = { org_UUID: userFixtures.existentUserDummy.org_UUID, username: userFixtures.existentUserDummy.username, @@ -523,6 +530,7 @@ describe('Testing the PUT /org/:shortname/user/:username endpoint in Org Control next() }, orgParams.parsePostParams, orgController.USER_UPDATE_SINGLE) + const CONSTANTS = getConstants() const testUser = Object.assign({}, userFixtures.existentUserDummy) testUser.authority = { active_roles: [CONSTANTS.USER_ROLE_ENUM.ADMIN] @@ -557,6 +565,8 @@ describe('Testing the PUT /org/:shortname/user/:username endpoint in Org Control it('User is updated: Removing a user role', (done) => { class UserUpdatedRemovingRole { constructor () { + const CONSTANTS = getConstants() + this.user = { org_UUID: userFixtures.existentUserDummy.org_UUID, username: userFixtures.existentUserDummy.username, @@ -609,6 +619,7 @@ describe('Testing the PUT /org/:shortname/user/:username endpoint in Org Control next() }, orgParams.parsePostParams, orgController.USER_UPDATE_SINGLE) + const CONSTANTS = getConstants() const testUser = Object.assign({}, userFixtures.existentUserDummy) testUser.authority = { active_roles: [CONSTANTS.USER_ROLE_ENUM.ADMIN] @@ -688,6 +699,8 @@ describe('Testing the PUT /org/:shortname/user/:username endpoint in Org Control next() }, orgParams.parsePostParams, orgController.USER_UPDATE_SINGLE) + const CONSTANTS = getConstants() + chai.request(app) .put(`/user-updated-removing-role-2/${userFixtures.owningOrg.short_name}/${userFixtures.existentUserDummy.username}?active_roles.remove=${CONSTANTS.USER_ROLE_ENUM.ADMIN}&active_roles.remove=${CONSTANTS.USER_ROLE_ENUM.ADMIN}`) .set(userFixtures.secretariatHeader)