diff --git a/app/package-lock.json b/app/package-lock.json index edbdde5fe..36de17ad4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,12 +1,12 @@ { "name": "attack-workbench-frontend", - "version": "2.0.1", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "attack-workbench-frontend", - "version": "2.0.1", + "version": "2.1.0", "license": "Apache-2.0", "dependencies": { "@angular/animations": "^14.3.0", @@ -22,6 +22,7 @@ "@angular/router": "^14.3.0", "jdenticon": "^3.2.0", "moment": "^2.29.4", + "ngx-autosize": "^2.0.4", "ngx-jdenticon": "^2.0.0", "ngx-logger": "^5.0.12", "ngx-markdown": "^14.0.1", @@ -34,7 +35,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "^14.2.12", + "@angular-devkit/build-angular": "^14.2.13", "@angular/cli": "^14.2.12", "@angular/compiler-cli": "^14.3.0", "@types/jasmine": "^4.3.5", @@ -73,12 +74,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1402.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.12.tgz", - "integrity": "sha512-LuK26pyaqyClEbY0n4/WIh3irUuA8wwmMmEj8uW4boziuJWv7U42lJJRF3VwkchiyOIp8qiKg995K6IoeXkWgA==", + "version": "0.1402.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.13.tgz", + "integrity": "sha512-n0ISBuvkZHoOpAzuAZql1TU9VLHUE9e/a9g4VNOPHewjMzpN02VqeGKvJfOCKtzkCs6gVssIlILm2/SXxkIFxQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.12", + "@angular-devkit/core": "14.2.13", "rxjs": "6.6.7" }, "engines": { @@ -88,15 +89,15 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "14.2.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.12.tgz", - "integrity": "sha512-ei8/FaL80Q6si/aF6FLZgtT4Kr2rudlyGMqQM4Rd2Zvt8mCh3TgM7QdLhoI11t9A0LWz6RIdROlDimMyyOEF6Q==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.13.tgz", + "integrity": "sha512-FJZKQ3xYFvEJ807sxVy4bCVyGU2NMl3UUPNfLIdIdzwwDEP9tx/cc+c4VtVPEZZfU8jVenu8XOvL6L0vpjt3yg==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1402.12", - "@angular-devkit/build-webpack": "0.1402.12", - "@angular-devkit/core": "14.2.12", + "@angular-devkit/architect": "0.1402.13", + "@angular-devkit/build-webpack": "0.1402.13", + "@angular-devkit/core": "14.2.13", "@babel/core": "7.18.10", "@babel/generator": "7.18.12", "@babel/helper-annotate-as-pure": "7.18.6", @@ -107,7 +108,7 @@ "@babel/runtime": "7.18.9", "@babel/template": "7.18.10", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "14.2.12", + "@ngtools/webpack": "14.2.13", "ansi-colors": "4.1.3", "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", @@ -132,7 +133,7 @@ "ora": "5.4.1", "parse5-html-rewriting-stream": "6.0.1", "piscina": "3.2.0", - "postcss": "8.4.16", + "postcss": "8.4.31", "postcss-import": "15.0.0", "postcss-loader": "7.0.1", "postcss-preset-env": "7.8.0", @@ -195,111 +196,19 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { - "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" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/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/@angular-devkit/build-angular/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/@angular-devkit/build-angular/node_modules/tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, - "node_modules/@angular-devkit/build-angular/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 - }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1402.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.12.tgz", - "integrity": "sha512-xBkbSwOhHgUsJk1tTtITqbHHiA0OdjwdrYZYceyfDASAglyRX6rT4Q9/Ppf7TSck6M1tUR76efYOn3D3ial29w==", + "version": "0.1402.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.13.tgz", + "integrity": "sha512-K27aJmuw86ZOdiu5PoGeGDJ2v7g2ZCK0bGwc8jzkjTLRfvd4FRKIIZumGv3hbQ3vQRLikiU6WMDRTFyCZky/EA==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1402.12", + "@angular-devkit/architect": "0.1402.13", "rxjs": "6.6.7" }, "engines": { @@ -313,9 +222,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "14.2.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.12.tgz", - "integrity": "sha512-tg1+deEZdm3fgk2BQ6y7tujciL6qhtN5Ums266lX//kAZeZ4nNNXTBT+oY5xgfjvmLbW+xKg0XZrAS0oIRKY5g==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.13.tgz", + "integrity": "sha512-aIefeZcbjghQg/V6U9CTLtyB5fXDJ63KwYqVYkWP+i0XriS5A9puFgq2u/OVsWxAfYvqpDqp5AdQ0g0bi3CAsA==", "dev": true, "dependencies": { "ajv": "8.11.0", @@ -338,35 +247,13 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@angular-devkit/schematics": { - "version": "14.2.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.12.tgz", - "integrity": "sha512-MN5yGR+SSSPPBBVMf4cifDJn9u0IYvxiHst+HWokH2AkBYy+vB1x8jYES2l1wkiISD7nvjTixfqX+Y95oMBoLg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.13.tgz", + "integrity": "sha512-2zczyeNzeBcrT2HOysv52X9SH3tZoHfWJvVf6H0SIa74rfDKEl7hFpKNXnh3x8sIMLj5mZn05n5RCqGxCczcIg==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.12", + "@angular-devkit/core": "14.2.13", "jsonc-parser": "3.1.0", "magic-string": "0.26.2", "ora": "5.4.1", @@ -408,22 +295,16 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/cdk/node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "optional": true - }, "node_modules/@angular/cli": { - "version": "14.2.12", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.12.tgz", - "integrity": "sha512-G/785b6jIIX7J+zS8RHaCT1OYzqANw5hJlnLf8tLgmaadLMVNQvIrvHTYtmD86pbqCYyVDLoMxefxRIwMHJuqw==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.13.tgz", + "integrity": "sha512-I5EepRem2CCyS3GDzQxZ2ZrqQwVqoGoLY+ZQhsK1QGWUnUyFOjbv3OlUGxRUYwcedu19V1EBAKjmQ96HzMIcVQ==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1402.12", - "@angular-devkit/core": "14.2.12", - "@angular-devkit/schematics": "14.2.12", - "@schematics/angular": "14.2.12", + "@angular-devkit/architect": "0.1402.13", + "@angular-devkit/core": "14.2.13", + "@angular-devkit/schematics": "14.2.13", + "@schematics/angular": "14.2.13", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "debug": "4.3.4", @@ -450,33 +331,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/lru-cache": { - "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" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/cli/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -486,12 +340,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/@angular/cli/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 - }, "node_modules/@angular/common": { "version": "14.3.0", "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.3.0.tgz", @@ -693,9 +541,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -926,22 +774,22 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -974,12 +822,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", - "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -998,16 +846,16 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.15.tgz", - "integrity": "sha512-l1UiX4UyHSFsYt17iQ3Se5pQQZZHa22zyIXURmvkmLCD4t/aU+dvNWHatKac/D9Vm9UES7nvIqHs4jZqKviUmQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.15" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1038,14 +886,14 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz", - "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-wrap-function": "^7.22.9" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1067,13 +915,13 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", - "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { @@ -1129,9 +977,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1147,14 +995,14 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz", - "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "dev": true, "dependencies": { "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, "engines": { "node": ">=6.9.0" @@ -1175,14 +1023,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", - "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -1203,12 +1051,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -1217,9 +1065,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz", - "integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1764,9 +1612,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz", - "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz", + "integrity": "sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1844,9 +1692,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz", - "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz", + "integrity": "sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1968,12 +1816,12 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", - "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz", + "integrity": "sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -1984,12 +1832,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz", - "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz", + "integrity": "sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, @@ -2001,15 +1849,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", - "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz", + "integrity": "sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.9", + "@babel/helper-module-transforms": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -2082,9 +1930,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz", - "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz", + "integrity": "sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -2442,19 +2290,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.15.tgz", - "integrity": "sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2463,12 +2311,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -2492,13 +2340,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.15.tgz", - "integrity": "sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3035,9 +2883,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3051,9 +2899,9 @@ "dev": true }, "node_modules/@ngtools/webpack": { - "version": "14.2.12", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.12.tgz", - "integrity": "sha512-d/NRQAjS3BsMDUpLrhza+bvI7HKIV+lyRAvD3LYj5FE9kMoEGw4zRo9JG8ookCzvT2FjNiXQ7DWDZSAeMOy+WQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.13.tgz", + "integrity": "sha512-RQx/rGX7K/+R55x1R6Ax1JzyeHi8cW11dEXpzHWipyuSpusQLUN53F02eMB4VTakXsL3mFNWWy4bX3/LSq8/9w==", "dev": true, "engines": { "node": "^14.15.0 || >=16.10.0", @@ -3143,18 +2991,6 @@ "node": ">=12" } }, - "node_modules/@npmcli/git/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@npmcli/git/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3200,18 +3036,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@npmcli/node-gyp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", @@ -3275,13 +3099,13 @@ } }, "node_modules/@schematics/angular": { - "version": "14.2.12", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.12.tgz", - "integrity": "sha512-nCxoFzH/uh5vqhaAjAfQIBgGuCdV3RMjdSwD0VQ+GFiFvTe8rqFyDl+qpNCgETz4LwmGHb5HNjDH9+VyVLgfZQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.13.tgz", + "integrity": "sha512-MLxTpTU3E8QACQ/5c0sENMR2gRiMXpGaKeD5IHY+3wyU2fUSJVB0QPU/l1WhoyZbX8N9ospBgf5UEG7taVF9rg==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.12", - "@angular-devkit/schematics": "14.2.12", + "@angular-devkit/core": "14.2.13", + "@angular-devkit/schematics": "14.2.13", "jsonc-parser": "3.1.0" }, "engines": { @@ -3330,9 +3154,9 @@ "dev": true }, "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz", + "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==", "dev": true, "dependencies": { "@types/connect": "*", @@ -3340,27 +3164,27 @@ } }, "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.12.tgz", + "integrity": "sha512-ky0kWSqXVxSqgqJvPIkgFkcn4C8MnRog308Ou8xBBIVo39OmUFy+jqNe0nPwLCDFxUpmT9EvT91YzOJgkDRcFg==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect": { - "version": "3.4.36", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", - "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz", + "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz", - "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.2.tgz", + "integrity": "sha512-gX2j9x+NzSh4zOhnRPSdPPmTepS4DfxES0AvIFv3jGv5QyeAJf6u6dY5/BAoAJU9Qq1uTvwOku8SSC2GnCRl6Q==", "dev": true, "dependencies": { "@types/express-serve-static-core": "*", @@ -3374,18 +3198,18 @@ "dev": true }, "node_modules/@types/cors": { - "version": "2.8.14", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", - "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.15.tgz", + "integrity": "sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/eslint": { - "version": "8.44.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", - "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==", + "version": "8.44.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", + "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -3393,9 +3217,9 @@ } }, "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==", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", + "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -3409,9 +3233,9 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", + "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -3421,9 +3245,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.36", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz", - "integrity": "sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q==", + "version": "4.17.38", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.38.tgz", + "integrity": "sha512-hXOtc0tuDHZPFwwhuBJXPbjemWtXnJjbvuuyNH2Y5Z6in+iXc63c4eXYDc7GGGqHy+iwYqAJMdaItqdnbcBKmg==", "dev": true, "dependencies": { "@types/node": "*", @@ -3433,50 +3257,50 @@ } }, "node_modules/@types/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz", + "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==", "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "version": "1.17.13", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.13.tgz", + "integrity": "sha512-GkhdWcMNiR5QSQRYnJ+/oXzu0+7JJEPC8vkWXK351BkhjraZF+1W13CUYARUvX9+NqIU2n6YHA4iwywsc/M6Sw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/jasmine": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.5.tgz", - "integrity": "sha512-9YHUdvuNDDRJYXZwHqSsO72Ok0vmqoJbNn73ttyITQp/VA60SarnZ+MPLD37rJAhVoKp+9BWOvJP5tHIRfZylQ==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.6.1.tgz", + "integrity": "sha512-Q00+pqd3WGt3xLmbIV6w9cP2uncjzIld+NOE4dl1ETQEut7RACj3QdAE8nD+n2ubPHneeGYsqXK//ORvH2m6eQ==", "dev": true }, "node_modules/@types/jasminewd2": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", - "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.12.tgz", + "integrity": "sha512-C4rXKMnGqLqTw4mgfiT0fL91g5oFAUhreR8jeeYk4xYcgh1/CImqgn5pWcErnpJJS43XFUfHGit0sSPQ39G1Pg==", "dev": true, "dependencies": { "@types/jasmine": "*" } }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", "dev": true }, "node_modules/@types/marked": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.1.tgz", - "integrity": "sha512-vSSbKZFbNktrQ15v7o1EaH78EbWV+sPQbPjHG+Cp8CaNcPFUEfjZ0Iml/V0bFDwsTlYe8o6XC5Hfdp91cqPV2g==" + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.2.tgz", + "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==" }, "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz", + "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==", "dev": true }, "node_modules/@types/node": { @@ -3485,21 +3309,21 @@ "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" }, "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.1.tgz", + "integrity": "sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==", "dev": true }, "node_modules/@types/qs": { - "version": "6.9.8", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", - "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "version": "6.9.9", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", + "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==", "dev": true }, "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz", + "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==", "dev": true }, "node_modules/@types/retry": { @@ -3509,9 +3333,9 @@ "dev": true }, "node_modules/@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz", + "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==", "dev": true, "dependencies": { "@types/mime": "^1", @@ -3519,18 +3343,18 @@ } }, "node_modules/@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.3.tgz", + "integrity": "sha512-4KG+yMEuvDPRrYq5fyVm/I2uqAJSAwZK9VSa+Zf+zUq9/oxSSvy3kkIqyL+jjStv6UCVi8/Aho0NHtB1Fwosrg==", "dev": true, "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", - "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz", + "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==", "dev": true, "dependencies": { "@types/http-errors": "*", @@ -3539,18 +3363,18 @@ } }, "node_modules/@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "version": "0.3.35", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.35.tgz", + "integrity": "sha512-tIF57KB+ZvOBpAQwSaACfEu7htponHXaFzP7RfKYgsOS0NoYnn+9+jzp7bbq4fWerizI3dTB4NfAZoyeQKWJLw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.8.tgz", + "integrity": "sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==", "dev": true, "dependencies": { "@types/node": "*" @@ -3848,14 +3672,14 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -3880,35 +3704,16 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "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" + "ajv": "^8.8.2" } }, "node_modules/ansi-colors": { @@ -4024,6 +3829,12 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/aria-query": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", @@ -4047,9 +3858,9 @@ "dev": true }, "node_modules/autoprefixer": { - "version": "10.4.15", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz", - "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "dev": true, "funding": [ { @@ -4067,8 +3878,8 @@ ], "dependencies": { "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001520", - "fraction.js": "^4.2.0", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -4125,34 +3936,10 @@ "node": ">=8.9.0" } }, - "node_modules/babel-loader/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -4284,13 +4071,13 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -4298,7 +4085,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -4307,15 +4094,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -4370,13 +4148,12 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -4392,9 +4169,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "dev": true, "funding": [ { @@ -4411,10 +4188,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -4448,15 +4225,15 @@ } }, "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "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": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4472,9 +4249,9 @@ } }, "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "engines": { "node": ">= 0.8" @@ -4509,34 +4286,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/cacache/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -4546,30 +4295,6 @@ "node": ">=12" } }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -4602,9 +4327,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001527", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001527.tgz", - "integrity": "sha512-YkJi7RwPgWtXVSgK4lG9AHH57nSzvvOp9MesgXmw4Q7n0C3H04L0foHqfxcmSAm5AcWb8dW9AYj2tR7/5GnddQ==", + "version": "1.0.30001551", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz", + "integrity": "sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg==", "dev": true, "funding": [ { @@ -4728,9 +4453,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", - "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", "dev": true, "engines": { "node": ">=6" @@ -4848,12 +4573,6 @@ "node": ">=0.10.0" } }, - "node_modules/codelyzer/node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "dev": true - }, "node_modules/codelyzer/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -4886,7 +4605,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/color-support": { @@ -4955,6 +4674,15 @@ "node": ">= 0.8.0" } }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5015,51 +4743,12 @@ "ms": "2.0.0" } }, - "node_modules/connect/node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/connect/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -5094,9 +4783,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, "engines": { "node": ">= 0.6" @@ -5144,34 +4833,6 @@ "webpack": "^5.1.0" } }, - "node_modules/copy-webpack-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, "node_modules/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -5184,12 +4845,6 @@ "node": ">=10.13.0" } }, - "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/copy-webpack-plugin/node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -5210,12 +4865,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.32.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz", - "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==", + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.0.tgz", + "integrity": "sha512-0w4LcLXsVEuNkIqwjjf9rjCoPhK8uqA4tMRh4Ge26vfLtUutshn+aRJU21I9LCJlh2QQHfisNToLjw1XEJLTWw==", "dev": true, "dependencies": { - "browserslist": "^4.21.10" + "browserslist": "^4.22.1" }, "funding": { "type": "opencollective", @@ -5354,6 +5009,12 @@ "node": ">=8" } }, + "node_modules/critters/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/critters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5520,9 +5181,9 @@ } }, "node_modules/cssdb": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.7.2.tgz", - "integrity": "sha512-pQPYP7/kch4QlkTcLuUNiNL2v/E+O+VIdotT+ug62/+2B2/jkzs5fMM6RHCzGCZ9C82pODEMSIzRRUzJOrl78g==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.8.0.tgz", + "integrity": "sha512-SkeezZOQr5AHt9MgJgSFNyiuJwg1p8AwoVln6JwaQJsyxduRW9QJ+HP/gAQzbsz8SIqINtYvpJKjxTRI67zxLg==", "dev": true, "funding": [ { @@ -6014,9 +5675,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.9", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", - "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { "version": "4.3.4", @@ -6251,9 +5912,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.508", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz", - "integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==", + "version": "1.4.559", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.559.tgz", + "integrity": "sha512-iS7KhLYCSJbdo3rUSkhDTVuFNCV34RKs2UaB9Ecr7VlqzjjWW//0nfsFF5dtDmyXlZQaDYYtID5fjtC/6lpRug==", "dev": true }, "node_modules/elkjs": { @@ -6314,9 +5975,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", - "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.3.tgz", + "integrity": "sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -6343,36 +6004,6 @@ "node": ">=10.0.0" } }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -6831,7 +6462,7 @@ "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { "node": ">=0.8.0" @@ -7009,6 +6640,39 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "dev": true }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7018,13 +6682,55 @@ "ms": "2.0.0" } }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/extend": { + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", @@ -7127,17 +6833,17 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.3.0", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~1.5.0", "unpipe": "~1.0.0" }, "engines": { @@ -7159,6 +6865,18 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -7176,30 +6894,6 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, - "node_modules/find-cache-dir/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -7214,15 +6908,15 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "dev": true, "funding": [ { @@ -7285,9 +6979,9 @@ } }, "node_modules/fraction.js": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz", - "integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, "engines": { "node": "*" @@ -7306,6 +7000,20 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -7319,15 +7027,15 @@ } }, "node_modules/fs-monkey": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", - "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", "dev": true }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { @@ -7345,10 +7053,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gauge": { "version": "4.0.4", @@ -7424,20 +7135,19 @@ } }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -7510,13 +7220,10 @@ "dev": true }, "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, "engines": { "node": ">= 0.4.0" } @@ -7524,7 +7231,7 @@ "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { "node": ">=4" @@ -7695,6 +7402,15 @@ "node": ">= 0.8" } }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-parser-js": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", @@ -7849,27 +7565,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -7941,7 +7636,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -8290,9 +7985,9 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, "engines": { "node": ">=8" @@ -8314,15 +8009,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-instrument/node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -8333,17 +8019,17 @@ } }, "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/istanbul-lib-report/node_modules/has-flag": { @@ -8356,29 +8042,20 @@ } }, "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "dependencies": { - "semver": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8407,6 +8084,36 @@ "node": ">=6" } }, + "node_modules/istanbul-lib-source-maps/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", @@ -8416,6 +8123,40 @@ "node": ">=6" } }, + "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-lib-source-maps/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -8428,6 +8169,15 @@ "rimraf": "bin.js" } }, + "node_modules/istanbul-lib-source-maps/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/istanbul-lib-source-maps/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8438,9 +8188,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -8451,9 +8201,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.3.tgz", - "integrity": "sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -8548,9 +8298,9 @@ "dev": true }, "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "dependencies": { "argparse": "^1.0.7", @@ -8579,9 +8329,9 @@ "dev": true }, "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==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "node_modules/json5": { @@ -8683,6 +8433,28 @@ "url": "https://github.com/sponsors/mattlewis92" } }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma-coverage-istanbul-reporter/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/karma-jasmine": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", @@ -8724,10 +8496,20 @@ "source-map-support": "^0.5.5" } }, - "node_modules/karma/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/karma/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -8744,16 +8526,28 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/karma/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "node_modules/karma/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, - "bin": { - "mime": "cli.js" + "dependencies": { + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=4.0.0" + "node": "*" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, "node_modules/karma/node_modules/source-map": { @@ -8805,9 +8599,9 @@ } }, "node_modules/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==", + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.9.tgz", + "integrity": "sha512-fsSYjWS0EEOwvy81j3vRA8TEAhQhKiqO+FQaKWp0m39qwOzHVBgAUBIXWj1pB+O2W3fIpNa6Y9KSKCVbfPhyAQ==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -8828,9 +8622,9 @@ } }, "node_modules/khroma": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", - "integrity": "sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" }, "node_modules/kind-of": { "version": "6.0.3", @@ -8901,6 +8695,53 @@ "webpack": "^5.0.0" } }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/less/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9104,25 +8945,27 @@ } }, "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "semver": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/make-dir/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" } }, "node_modules/make-error": { @@ -9169,15 +9012,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/make-fetch-happen/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/make-fetch-happen/node_modules/cacache": { "version": "17.1.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", @@ -9202,9 +9036,9 @@ } }, "node_modules/make-fetch-happen/node_modules/cacache/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -9223,28 +9057,28 @@ } }, "node_modules/make-fetch-happen/node_modules/fs-minipass/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/make-fetch-happen/node_modules/glob": { - "version": "10.3.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz", - "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", + "jackspeak": "^2.3.5", "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" }, "bin": { - "glob": "dist/cjs/src/bin.js" + "glob": "dist/esm/bin.mjs" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9299,9 +9133,9 @@ } }, "node_modules/make-fetch-happen/node_modules/ssri/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -9430,15 +9264,15 @@ } }, "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, "bin": { "mime": "cli.js" }, "engines": { - "node": ">=4" + "node": ">=4.0.0" } }, "node_modules/mime-db": { @@ -9490,40 +9324,6 @@ "webpack": "^5.0.0" } }, - "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -9550,15 +9350,15 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/minimist": { @@ -9612,9 +9412,9 @@ } }, "node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -9692,15 +9492,15 @@ "dev": true }, "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/moment": { @@ -9810,6 +9610,18 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ngx-autosize": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/ngx-autosize/-/ngx-autosize-2.0.4.tgz", + "integrity": "sha512-+MgkvrJs5k/CdTXpkGnwFq/zhNurT1npuQYgCN/e3oDn3LV7xRJaRJQtYY6j+BwqnN4Tkujr4+6kUQtAMp55mA==", + "dependencies": { + "tslib": ">2.0.0" + }, + "peerDependencies": { + "@angular/common": ">12.0.0", + "@angular/core": ">12.0.0" + } + }, "node_modules/ngx-jdenticon": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ngx-jdenticon/-/ngx-jdenticon-2.0.0.tgz", @@ -9957,6 +9769,48 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/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/node-gyp/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10091,46 +9945,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/npm-packlist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm-packlist/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm-packlist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/npm-packlist/node_modules/npm-bundled": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", @@ -10287,9 +10101,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", + "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10325,7 +10139,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -10573,18 +10387,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/pacote/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -10631,12 +10433,12 @@ } }, "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-html-rewriting-stream": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "node_modules/parse5-html-rewriting-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", @@ -10646,6 +10448,12 @@ "parse5-sax-parser": "^6.0.1" } }, + "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", @@ -10655,6 +10463,12 @@ "parse5": "^6.0.1" } }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/parse5-sax-parser": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", @@ -10664,6 +10478,12 @@ "parse5": "^6.0.1" } }, + "node_modules/parse5-sax-parser/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -10685,7 +10505,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10732,9 +10552,9 @@ } }, "node_modules/path-scurry/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -10774,12 +10594,12 @@ } }, "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, "node_modules/piscina": { @@ -10820,9 +10640,9 @@ } }, "node_modules/postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -10832,10 +10652,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -11647,9 +11471,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -11661,15 +11485,6 @@ "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -11679,15 +11494,6 @@ "pify": "^2.3.0" } }, - "node_modules/read-cache/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read-package-json": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", @@ -11716,46 +11522,6 @@ "node": ">=10" } }, - "node_modules/read-package-json/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/read-package-json/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", @@ -11804,9 +11570,9 @@ "dev": true }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dev": true, "dependencies": { "regenerate": "^1.4.2" @@ -12016,6 +11782,48 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/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/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -12155,10 +11963,11 @@ } }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true, + "optional": true }, "node_modules/schema-utils": { "version": "2.7.1", @@ -12178,6 +11987,37 @@ "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/select": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", @@ -12202,9 +12042,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -12226,9 +12066,9 @@ } }, "node_modules/semver-dsl/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -12291,12 +12131,33 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/send/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/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/serialize-javascript": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", @@ -12375,15 +12236,6 @@ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -12513,27 +12365,6 @@ "ws": "~8.11.0" } }, - "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -12647,9 +12478,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "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", @@ -12699,9 +12530,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, "node_modules/spdy": { @@ -12735,9 +12566,9 @@ } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, "node_modules/ssf": { @@ -12764,12 +12595,12 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, "node_modules/streamroller": { @@ -12786,20 +12617,6 @@ "node": ">=8.0" } }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -12921,22 +12738,70 @@ "webpack": "^5.0.0" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/stylus/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "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==", + "node_modules/stylus/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylus/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/stylus/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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==", "dev": true, "engines": { "node": ">= 0.4" @@ -12989,18 +12854,6 @@ "node": ">=8" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -13059,6 +12912,37 @@ } } }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/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/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -13077,29 +12961,10 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/terser": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.4.tgz", - "integrity": "sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", + "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -13114,25 +12979,6 @@ "node": ">=10" } }, - "node_modules/terser/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/terser/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/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -13147,6 +12993,48 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/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/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -13308,19 +13196,73 @@ "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" } }, + "node_modules/tslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/tslint/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tslint/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/tslint/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" } }, "node_modules/tslint/node_modules/tslib": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz", - "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, "node_modules/tsutils": { @@ -13336,9 +13278,9 @@ } }, "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz", - "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, "node_modules/type-fest": { @@ -13386,9 +13328,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.35", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", - "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", + "version": "0.7.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.36.tgz", + "integrity": "sha512-CPPLoCts2p7D8VbybttE3P2ylv0OBZEAy7a12DsulIEcAiMtWJy+PBgMXgWDI80D5UwqE8oQPHYnk13tm38M2Q==", "dev": true, "funding": [ { @@ -13398,6 +13340,10 @@ { "type": "paypal", "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" } ], "engines": { @@ -13481,9 +13427,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -13535,9 +13481,13 @@ } }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -13699,40 +13649,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/webpack-dev-middleware/node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -13807,40 +13723,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/webpack-dev-server/node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -13903,6 +13785,37 @@ } } }, + "node_modules/webpack/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/webpack/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/webpack/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/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -14091,20 +14004,20 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { "bufferutil": { diff --git a/app/package.json b/app/package.json index d6c9e3d9f..851f82aa5 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "attack-workbench-frontend", - "version": "2.0.1", + "version": "2.1.0", "description": "An application allowing users to explore, create, annotate, and share extensions of the MITRE ATT&CK® knowledge base. This repository contains an Angular-based web application providing the user interface for the ATT&CK Workbench application.", "repository": { "type": "git", @@ -44,6 +44,7 @@ "@angular/router": "^14.3.0", "jdenticon": "^3.2.0", "moment": "^2.29.4", + "ngx-autosize": "^2.0.4", "ngx-jdenticon": "^2.0.0", "ngx-logger": "^5.0.12", "ngx-markdown": "^14.0.1", @@ -56,7 +57,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "^14.2.12", + "@angular-devkit/build-angular": "^14.2.13", "@angular/cli": "^14.2.12", "@angular/compiler-cli": "^14.3.0", "@types/jasmine": "^4.3.5", diff --git a/app/src/app/app-routing-stix.module.ts b/app/src/app/app-routing-stix.module.ts index c179b0e1d..51b681aa9 100644 --- a/app/src/app/app-routing-stix.module.ts +++ b/app/src/app/app-routing-stix.module.ts @@ -11,6 +11,7 @@ import { MarkingDefinitionListComponent } from './views/stix/marking-definition/ import { DataSourceListComponent } from './views/stix/data-source/data-source-list/data-source-list.component'; import { ReferenceManagerComponent } from './views/reference-manager/reference-manager.component'; import { CampaignListComponent } from './views/stix/campaign/campaign-list/campaign-list.component'; +import { AssetListComponent } from './views/stix/asset/asset-list/asset-list.component'; import { NotesPageComponent } from './views/notes-page/notes-page.component'; import { StixPageComponent } from './views/stix/stix-page/stix-page.component'; @@ -31,6 +32,7 @@ const attackTypeToPlural = { 'mitigation': 'mitigations', 'matrix': 'matrices', 'data-source': 'data-sources', + 'asset': 'assets', } const stixRouteData = [ { @@ -73,6 +75,11 @@ const stixRouteData = [ editable: true, component: CampaignListComponent }, + { + attackType: 'asset', + editable: true, + component: AssetListComponent + }, ] const stixRoutes: Routes = []; diff --git a/app/src/app/app.module.ts b/app/src/app/app.module.ts index 1f133e19b..6340a4da8 100644 --- a/app/src/app/app.module.ts +++ b/app/src/app/app.module.ts @@ -1,7 +1,7 @@ import { environment } from 'src/environments/environment'; import { LoggerModule } from 'ngx-logger'; -//angular imports +// angular imports import { BrowserModule } from '@angular/platform-browser'; import { APP_INITIALIZER, NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; @@ -52,6 +52,7 @@ import { MaterialFileInputModule } from 'ngx-material-file-input'; import { MarkdownModule } from "ngx-markdown"; import { PopoverModule } from "ngx-smart-popover"; import { NgxJdenticonModule, JDENTICON_CONFIG } from 'ngx-jdenticon'; +import { AutosizeModule } from 'ngx-autosize'; // custom components import { HeaderComponent } from './components/header/header.component'; @@ -82,16 +83,13 @@ import { UsersListComponent } from './components/users-list/users-list.component import { ExternalReferencesPropertyComponent } from "./components/stix/external-references-property/external-references-property.component"; import { ExternalReferencesViewComponent } from './components/stix/external-references-property/external-references-view/external-references-view.component'; -import { ExternalReferencesDiffComponent } from './components/stix/external-references-property/external-references-diff/external-references-diff.component'; import { DescriptivePropertyComponent } from './components/stix/descriptive-property/descriptive-property.component'; import { DescriptiveViewComponent } from './components/stix/descriptive-property/descriptive-view/descriptive-view.component'; import { DescriptiveEditComponent } from './components/stix/descriptive-property/descriptive-edit/descriptive-edit.component'; -import { DescriptiveDiffComponent } from './components/stix/descriptive-property/descriptive-diff/descriptive-diff.component'; import { TimestampPropertyComponent } from "./components/stix/timestamp-property/timestamp-property.component"; import { TimestampViewComponent } from "./components/stix/timestamp-property/timestamp-view/timestamp-view.component"; -import { TimestampDiffComponent } from "./components/stix/timestamp-property/timestamp-diff/timestamp-diff.component"; import { StatementPropertyComponent } from "./components/stix/statement-property/statement-property.component"; import { StatementViewComponent } from './components/stix/statement-property/statement-view/statement-view.component'; @@ -124,6 +122,11 @@ import { AliasViewComponent } from './components/stix/alias-property/alias-view/ import { AliasEditComponent } from './components/stix/alias-property/alias-edit/alias-edit.component'; import { AliasEditDialogComponent } from './components/stix/alias-property/alias-edit/alias-edit-dialog/alias-edit-dialog.component'; +import { SubtypePropertyComponent } from './components/stix/subtype-property/subtype-property.component'; +import { SubtypeViewComponent } from './components/stix/subtype-property/subtype-view/subtype-view.component'; +import { SubtypeEditComponent } from './components/stix/subtype-property/subtype-edit/subtype-edit.component'; +import { SubtypeDialogComponent } from './components/stix/subtype-property/subtype-dialog/subtype-dialog.component'; + import { OrderedListPropertyComponent } from './components/stix/ordered-list-property/ordered-list-property.component'; import { OrderedListViewComponent } from './components/stix/ordered-list-property/ordered-list-view/ordered-list-view.component'; import { OrderedListEditComponent } from './components/stix/ordered-list-property/ordered-list-edit/ordered-list-edit.component'; @@ -199,6 +202,9 @@ import { TacticCellComponent } from './components/matrix/tactic-cell/tactic-cell import { TechniqueCellComponent } from './components/matrix/technique-cell/technique-cell.component'; import { MatrixFlatComponent } from './views/stix/matrix/matrix-flat/matrix-flat.component'; +import { AssetListComponent } from './views/stix/asset/asset-list/asset-list.component'; +import { AssetViewComponent } from './views/stix/asset/asset-view/asset-view.component'; + import { TeamsListPageComponent } from './views/admin-page/teams/teams-list-page/teams-list-page.component'; import { TeamsViewPageComponent } from './views/admin-page/teams/teams-view-page/teams-view-page.component'; import { CreateNewDialogComponent } from './components/create-new-dialog/create-new-dialog.component'; @@ -239,13 +245,10 @@ export function initConfig(appConfigService: AppConfigService) { DescriptivePropertyComponent, DescriptiveViewComponent, DescriptiveEditComponent, - DescriptiveDiffComponent, ExternalReferencesPropertyComponent, ExternalReferencesViewComponent, - ExternalReferencesDiffComponent, TimestampPropertyComponent, TimestampViewComponent, - TimestampDiffComponent, StatementPropertyComponent, StatementViewComponent, StatementEditComponent, @@ -339,6 +342,12 @@ export function initConfig(appConfigService: AppConfigService) { TeamsViewPageComponent, CreateNewDialogComponent, UsersListComponent, + AssetListComponent, + AssetViewComponent, + SubtypePropertyComponent, + SubtypeViewComponent, + SubtypeEditComponent, + SubtypeDialogComponent, BreadcrumbComponent ], imports: [ @@ -359,6 +368,7 @@ export function initConfig(appConfigService: AppConfigService) { }), PopoverModule, NgxJdenticonModule, + AutosizeModule, BrowserModule, diff --git a/app/src/app/classes/external-references.ts b/app/src/app/classes/external-references.ts index e44207402..29bb5254c 100644 --- a/app/src/app/classes/external-references.ts +++ b/app/src/app/classes/external-references.ts @@ -4,6 +4,7 @@ import { RestApiConnectorService } from "../services/connectors/rest-api/rest-ap import { Serializable, ValidationData } from "./serializable"; import { StixObject } from "./stix/stix-object"; import { logger } from "../util/logger"; +import { RelatedAsset } from "./stix/asset"; export class ExternalReferences extends Serializable { private _externalReferences : Map = new Map(); @@ -146,12 +147,15 @@ export class ExternalReferences extends Serializable { // get list of descriptive fields that support citations let refs_fields = ['description']; if (['software', 'group', 'campaign'].includes(object.attackType)) refs_fields.push('aliases'); + if (object.attackType == 'asset') refs_fields.push('relatedAssets'); if (object.attackType == 'technique') refs_fields.push('detection'); if (object.attackType == 'campaign') refs_fields.push('first_seen_citation', 'last_seen_citation'); + // parse citations for each descriptive field on the object let parse_apis = []; for (let field of refs_fields) { if (field == 'aliases') parse_apis.push(this.parseCitationsFromAliases(object[field], restAPIConnector)); + else if (field == 'relatedAssets') parse_apis.push(this.parseCitationsFromRelatedAssets(object[field], restAPIConnector)); else parse_apis.push(this.parseCitations(object[field], restAPIConnector)); } @@ -252,6 +256,33 @@ export class ExternalReferences extends Serializable { ) } + /** + * Parse citations from related assets which stores descriptions in the related asset object + * Add missing references to object if found in global external reference list + * @param relatedAssets list of related asset objects + * @param restApiConnector to connect to the REST API + */ + public parseCitationsFromRelatedAssets(relatedAssets : RelatedAsset[], restApiConnector : RestApiConnectorService): Observable { + // Parse citations from the related asset descriptions + let api_calls = []; + let result = new CitationParseResult(); + for (let relatedAsset of relatedAssets) { + if ('description' in relatedAsset && relatedAsset.description) { + api_calls.push(this.parseCitations(relatedAsset.description, restApiConnector)); + } + } + if (api_calls.length == 0) return of(result); + else return forkJoin(api_calls).pipe( // get citation errors + map((api_results) => { + let citation_results = api_results as any; + for (let citation_result of citation_results) { // merge into master list + result.merge(citation_result); + } + return result; // return master list + }) + ) + } + /** * Update external references map with given reference list * @param references list of references @@ -354,7 +385,8 @@ export class ExternalReferences extends Serializable { let parse_apis = []; for (let field of options.fields) { if (!Object.keys(options.object)) continue; //object does not implement the field - if (field == "aliases") parse_apis.push(this.parseCitationsFromAliases(options.object[field], restAPIService)) + if (field == "aliases") parse_apis.push(this.parseCitationsFromAliases(options.object[field], restAPIService)); + else if (field == 'relatedAssets') parse_apis.push(this.parseCitationsFromRelatedAssets(options.object[field], restAPIService)); else parse_apis.push(this.parseCitations(options.object[field], restAPIService)); } return forkJoin(parse_apis).pipe( diff --git a/app/src/app/classes/stix/asset.ts b/app/src/app/classes/stix/asset.ts new file mode 100644 index 000000000..9a1243d7c --- /dev/null +++ b/app/src/app/classes/stix/asset.ts @@ -0,0 +1,140 @@ +import { StixObject } from "./stix-object"; +import { logger } from "../../util/logger"; +import { Observable } from "rxjs"; +import { RestApiConnectorService } from "src/app/services/connectors/rest-api/rest-api-connector.service"; +import { ValidationData } from "../serializable"; + +export class Asset extends StixObject { + public name: string = ""; + public contributors: string[] = []; + public sectors: string[] = []; + public relatedAssets: RelatedAsset[] = []; + public platforms: string[] = []; + + // assets are ICS-only + public domains: string[] = ['ics-attack']; + + public readonly supportsAttackID = true; + public readonly supportsNamespace = true; + protected get attackIDValidator() { + return { + regex: "A\\d{4}", + format: "A####" + } + } + + constructor(sdo?: any) { + super(sdo, "x-mitre-asset"); + if (sdo) { + this.deserialize(sdo); + } + } + + /** + * Transform the current object into a raw object for sending to the back-end, stripping any unnecessary fields + * @abstract + * @returns {*} the raw object to send + */ + public serialize(): any { + let rep = super.base_serialize(); + + rep.stix.name = this.name.trim(); + rep.stix.x_mitre_domains = this.domains; + rep.stix.x_mitre_sectors = this.sectors; + rep.stix.x_mitre_related_assets = this.relatedAssets.map((asset: RelatedAsset) => { + return { + name: asset.name.trim(), + related_asset_sectors: asset.related_asset_sectors ? asset.related_asset_sectors : [], + description: asset.description ? asset.description : "" + } + }); + rep.stix.x_mitre_platforms = this.platforms; + rep.stix.x_mitre_contributors = this.contributors.map(x => x.trim()); + + return rep; + } + + public isRelatedAssetArray(arr: any[]): boolean { + return arr.every(a => this.instanceOfRelatedAsset(a)); + } + + public instanceOfRelatedAsset(object: any): boolean { + return 'name' in object && 'related_asset_sectors' in object; + } + + /** + * Parse the object from the record returned from the back-end + * @abstract + * @param {*} raw the raw object to parse + */ + public deserialize(raw: any) { + if (!("stix" in raw)) return; + + let sdo = raw.stix; + + if (!("name" in sdo)) this.name = ""; + else if (typeof(sdo.name) === "string") this.name = sdo.name; + else logger.error(`TypeError: name field is not a string: ${sdo.name} (${typeof(sdo.name)})`); + + if (!("x_mitre_sectors" in sdo)) this.sectors = []; + else if (this.isStringArray(sdo.x_mitre_sectors)) this.sectors = sdo.x_mitre_sectors; + else logger.error(`TypeError: x_mitre_sectors field is not a string array.`); + + if (!("x_mitre_related_assets" in sdo)) this.relatedAssets = []; + else if (this.isRelatedAssetArray(sdo.x_mitre_related_assets)) this.relatedAssets = sdo.x_mitre_related_assets; + else logger.error(`TypeError: x_mitre_related_assets field is not an array of related assets.`); + + if (!("x_mitre_platforms" in sdo)) this.platforms = []; + else if (this.isStringArray(sdo.x_mitre_platforms)) this.platforms = sdo.x_mitre_platforms; + else logger.error(`TypeError: platforms field is not a string array.`); + + if (!("x_mitre_domains" in sdo)) this.domains = ["ics-attack"]; + else if(this.isStringArray(sdo.x_mitre_domains)) this.domains = sdo.x_mitre_domains; + else logger.error(`TypeError: domains field is not a string array.`); + + if (!("x_mitre_contributors" in sdo)) this.contributors = []; + else if (this.isStringArray(sdo.x_mitre_contributors)) this.contributors = sdo.x_mitre_contributors; + else logger.error(`TypeError: x_mitre_contributors is not a string array.`); + } + + /** + * Validate the current object state and return information on the result of the validation + * @param {RestApiConnectorService} restAPIService: the REST API connector through which asynchronous validation can be completed + * @returns {Observable} the validation warnings and errors once validation is complete. + */ + public validate(restAPIService: RestApiConnectorService): Observable { + return this.base_validate(restAPIService); + } + + /** + * Save the current state of the STIX object in the database. Update the current object from the response + * @param restAPIService [RestApiConnectorService] the service to perform the POST/PUT through + * @returns {Observable} of the post + */ + public save(restAPIService: RestApiConnectorService): Observable { + let postObservable = restAPIService.postAsset(this); + let subscription = postObservable.subscribe({ + next: (result) => { this.deserialize(result.serialize()); }, + complete: () => { subscription.unsubscribe(); } + }); + return postObservable; + } + + /** + * Delete this STIX object from the database. + * @param restAPIService [RestApiConnectorService] the service to perform the DELETE through + */ + public delete(restAPIService: RestApiConnectorService) : Observable<{}> { + let deleteObservable = restAPIService.deleteAsset(this.stixID); + let subscription = deleteObservable.subscribe({ + complete: () => { subscription.unsubscribe(); } + }); + return deleteObservable; + } +} + +export interface RelatedAsset { + name: string; + related_asset_sectors: string; + description: string; +} \ No newline at end of file diff --git a/app/src/app/classes/stix/collection.ts b/app/src/app/classes/stix/collection.ts index 60a504767..d1a16e962 100644 --- a/app/src/app/classes/stix/collection.ts +++ b/app/src/app/classes/stix/collection.ts @@ -1,19 +1,8 @@ import { Observable, of } from 'rxjs'; import { RestApiConnectorService } from 'src/app/services/connectors/rest-api/rest-api-connector.service'; import { ValidationData } from '../serializable'; -import { Group } from './group'; -import { Matrix } from './matrix'; -import { Mitigation } from './mitigation'; -import { Relationship } from './relationship'; -import { Software } from './software'; -import { StixObject } from './stix-object'; -import { Tactic } from './tactic'; -import { Technique } from './technique'; -import { DataSource } from './data-source'; -import { DataComponent } from './data-component'; +import { Asset, Campaign, DataComponent, DataSource, Group, MarkingDefinition, Matrix, Mitigation, Relationship, Software, StixObject, Tactic, Technique } from '../stix'; import { logger } from "../../util/logger"; -import { MarkingDefinition } from './marking-definition'; -import { Campaign } from './campaign'; /** * auto-generated changelog/report about an import @@ -296,6 +285,9 @@ export class Collection extends StixObject { case "marking-definition": // marking definition this.stix_contents.push(new MarkingDefinition(obj)) break; + case "x-mitre-asset": // asset + this.stix_contents.push(new Asset(obj)) + break; } } } @@ -315,8 +307,9 @@ export class Collection extends StixObject { matrix: CollectionDiffCategories, group: CollectionDiffCategories, data_source: CollectionDiffCategories, - data_component: CollectionDiffCategories - marking_definition: CollectionDiffCategories + data_component: CollectionDiffCategories, + marking_definition: CollectionDiffCategories, + asset: CollectionDiffCategories } { let results = { technique: new CollectionDiffCategories(), @@ -329,7 +322,8 @@ export class Collection extends StixObject { group: new CollectionDiffCategories(), data_source: new CollectionDiffCategories(), data_component: new CollectionDiffCategories(), - marking_definition: new CollectionDiffCategories() + marking_definition: new CollectionDiffCategories(), + asset: new CollectionDiffCategories(), } // build helper lookups to reduce complexity from n^2 to n. let thisStixLookup = new Map(this.stix_contents.map(sdo => [sdo.stixID, sdo])) diff --git a/app/src/app/classes/stix/index.ts b/app/src/app/classes/stix/index.ts new file mode 100644 index 000000000..7ca4c5be3 --- /dev/null +++ b/app/src/app/classes/stix/index.ts @@ -0,0 +1,15 @@ +export { Asset } from "./asset"; +export { Campaign } from "./campaign"; +export { DataComponent } from "./data-component"; +export { DataSource } from "./data-source"; +export { Group } from "./group"; +export { Identity } from "./identity"; +export { MarkingDefinition } from "./marking-definition"; +export { Matrix } from "./matrix"; +export { Mitigation } from "./mitigation"; +export { Note } from "./note"; +export { Relationship } from "./relationship"; +export { Software } from "./software"; +export { StixObject } from "./stix-object"; +export { Tactic } from "./tactic"; +export { Technique } from "./technique"; \ No newline at end of file diff --git a/app/src/app/classes/stix/relationship.ts b/app/src/app/classes/stix/relationship.ts index 388ef2447..4c02bc746 100644 --- a/app/src/app/classes/stix/relationship.ts +++ b/app/src/app/classes/stix/relationship.ts @@ -43,6 +43,7 @@ export class Relationship extends StixObject { if (this.relationship_type == "subtechnique-of") return ["technique"]; if (this.relationship_type == "detects") return ["data-component"]; if (this.relationship_type == "attributed-to") return ["campaign"]; + if (this.relationship_type == "targets") return ["technique"]; else return null; } /** @@ -58,6 +59,7 @@ export class Relationship extends StixObject { if (this.relationship_type == "subtechnique-of") return ["technique"]; if (this.relationship_type == "detects") return ["technique"]; if (this.relationship_type == "attributed-to") return ["group"]; + if (this.relationship_type == "targets") return ["asset"]; else return null; } diff --git a/app/src/app/classes/stix/stix-object.ts b/app/src/app/classes/stix/stix-object.ts index 1b57ca5e4..9247feb26 100644 --- a/app/src/app/classes/stix/stix-object.ts +++ b/app/src/app/classes/stix/stix-object.ts @@ -22,6 +22,7 @@ let stixTypeToAttackType = { "marking-definition": "marking-definition", "x-mitre-data-source": "data-source", "x-mitre-data-component": "data-component", + "x-mitre-asset": "asset", "note": "note" } export { stixTypeToAttackType }; @@ -59,7 +60,8 @@ export abstract class StixObject extends Serializable { "note": "notes", "marking-definition": "marking-definitions", "data-source": "datasources", - "data-component": "datacomponents" + "data-component": "datacomponents", + "asset": "assets" } private defaultMarkingDefinitionsLoaded = false; // avoid overloading of default marking definitions @@ -305,6 +307,7 @@ export abstract class StixObject extends Serializable { else if (this.attackType == "technique") accessor = restAPIService.getAllTechniques(options); else if (this.attackType == "data-source") accessor = restAPIService.getAllDataSources(options); else if (this.attackType == "data-component") accessor = restAPIService.getAllDataComponents(options); + else if (this.attackType == "asset") accessor = restAPIService.getAllAssets(); else accessor = restAPIService.getAllTactics(options); return accessor.pipe( @@ -404,6 +407,7 @@ export abstract class StixObject extends Serializable { // build list of fields to validate external references on according to ATT&CK type let refs_fields = ['description']; if (['software', 'group', 'campaign'].includes(this.attackType)) refs_fields.push('aliases'); + if (this.attackType == 'asset') refs_fields.push('relatedAssets'); if (this.attackType == 'technique') refs_fields.push('detection'); if (this.attackType == 'campaign') refs_fields.push('first_seen_citation', 'last_seen_citation'); @@ -587,17 +591,19 @@ export abstract class StixObject extends Serializable { public getNamespaceID(restAPIConnector, orgNamespace): Observable { let prefix = ''; // i.e. 'TA', if StixObject type is tactic let count = '' as any; // i.e. 1234 - let copyID = this.attackID.slice(); // Deep copy of attack id this.attackID = '(generating ID)'; - let accessor = this.attackType == "group" ? restAPIConnector.getAllGroups() : - this.attackType == "campaign" ? restAPIConnector.getAllCampaigns() : - this.attackType == "mitigation" ? restAPIConnector.getAllMitigations() : - this.attackType == "software" ? restAPIConnector.getAllSoftware() : - this.attackType == "tactic" ? restAPIConnector.getAllTactics() : - this.attackType == "technique" ? restAPIConnector.getAllTechniques() : - this.attackType == "data-source" ? restAPIConnector.getAllDataSources() : - this.attackType == "matrix" ? restAPIConnector.getAllMatrices() : null; + let accessor: Observable>; + if (this.attackType == "group") accessor = restAPIConnector.getAllGroups(); + else if (this.attackType == "campaign") accessor = restAPIConnector.getAllCampaigns(); + else if (this.attackType == "mitigation") accessor = restAPIConnector.getAllMitigations(); + else if (this.attackType == "software") accessor = restAPIConnector.getAllSoftware(); + else if (this.attackType == "tactic") accessor = restAPIConnector.getAllTactics(); + else if (this.attackType == "technique") accessor = restAPIConnector.getAllTechniques(); + else if (this.attackType == "data-source") accessor = restAPIConnector.getAllDataSources(); + else if (this.attackType == "asset") accessor = restAPIConnector.getAllAssets(); + else if (this.attackType == "matrix") accessor = restAPIConnector.getAllMatrices(); + else accessor = null; // Find all other objects that have this prefix and range, and set ID to the most recent & unique ID available if (accessor) { diff --git a/app/src/app/components/add-relationship-button/add-relationship-button.component.html b/app/src/app/components/add-relationship-button/add-relationship-button.component.html index 24b722e36..8bcbdabdf 100644 --- a/app/src/app/components/add-relationship-button/add-relationship-button.component.html +++ b/app/src/app/components/add-relationship-button/add-relationship-button.component.html @@ -1,6 +1,6 @@
diff --git a/app/src/app/components/add-relationship-button/add-relationship-button.component.ts b/app/src/app/components/add-relationship-button/add-relationship-button.component.ts index ca371fdb5..113474612 100644 --- a/app/src/app/components/add-relationship-button/add-relationship-button.component.ts +++ b/app/src/app/components/add-relationship-button/add-relationship-button.component.ts @@ -25,6 +25,8 @@ export class AddRelationshipButtonComponent implements OnInit { public createRelationship() { let relationship = new Relationship(); relationship.relationship_type = this.config.relationship_type; + let sourceType = this.config.sourceType ? this.config.sourceType : null; + let targetType = this.config.targetType ? this.config.targetType : null; let initializer = null; if (this.config.source_object) initializer = relationship.set_source_object(this.config.source_object, this.restApiService); else if (this.config.source_ref) initializer = relationship.set_source_ref(this.config.source_ref, this.restApiService); @@ -37,6 +39,8 @@ export class AddRelationshipButtonComponent implements OnInit { this.loading = false; let config: StixViewConfig = { object: relationship, + sourceType: sourceType, + targetType: targetType, editable: true, is_new: true, mode: "edit", @@ -74,8 +78,10 @@ export interface AddRelationshipButtonConfig { relationship_type: string; //relationship type to create source_ref?: string; //initial relationship source ref. source_object?: StixObject; //initial relationship source object. Takes precedence over source_ref if both are specified, and is much faster to execute + sourceType?: string; // the source type of the relationship target_ref?: string; //initial relationship target ref target_object?: StixObject; //initial relationship target object. Takes precedence over target_ref if both are specified, and is much faster to execute + targetType?: string; // the target type of the relationship /** * reference to the current working dialog. This is relevant when adding a new relationship from within the dialog. * If provided, the 'create relationship' interface will replace the dialog content. diff --git a/app/src/app/components/collection-import-summary/collection-import-summary.component.html b/app/src/app/components/collection-import-summary/collection-import-summary.component.html index d41de28ac..4f71f22df 100644 --- a/app/src/app/components/collection-import-summary/collection-import-summary.component.html +++ b/app/src/app/components/collection-import-summary/collection-import-summary.component.html @@ -1,6 +1,6 @@
- + {{format(attackType)}} ({{config.object_import_categories[attackType].object_count}}) diff --git a/app/src/app/components/collection-import-summary/collection-import-summary.component.ts b/app/src/app/components/collection-import-summary/collection-import-summary.component.ts index 0e908556e..3dd900c3d 100644 --- a/app/src/app/components/collection-import-summary/collection-import-summary.component.ts +++ b/app/src/app/components/collection-import-summary/collection-import-summary.component.ts @@ -1,16 +1,7 @@ import { SelectionModel } from '@angular/cdk/collections'; import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; -import { Campaign } from 'src/app/classes/stix/campaign'; +import { Asset, Campaign, DataComponent, DataSource, Group, Matrix, Mitigation, Relationship, Software, Tactic, Technique } from 'src/app/classes/stix'; import { CollectionDiffCategories } from 'src/app/classes/stix/collection'; -import { DataComponent } from 'src/app/classes/stix/data-component'; -import { DataSource } from 'src/app/classes/stix/data-source'; -import { Group } from 'src/app/classes/stix/group'; -import { Matrix } from 'src/app/classes/stix/matrix'; -import { Mitigation } from 'src/app/classes/stix/mitigation'; -import { Relationship } from 'src/app/classes/stix/relationship'; -import { Software } from 'src/app/classes/stix/software'; -import { Tactic } from 'src/app/classes/stix/tactic'; -import { Technique } from 'src/app/classes/stix/technique'; @Component({ selector: 'app-collection-import-summary', @@ -45,7 +36,8 @@ export interface CollectionImportSummaryConfig { matrix: CollectionDiffCategories, group: CollectionDiffCategories, data_source: CollectionDiffCategories, - data_component: CollectionDiffCategories + data_component: CollectionDiffCategories, + asset: CollectionDiffCategories }; select?: SelectionModel; } diff --git a/app/src/app/components/header/header.component.html b/app/src/app/components/header/header.component.html index 9d7c0c675..803a80665 100644 --- a/app/src/app/components/header/header.component.html +++ b/app/src/app/components/header/header.component.html @@ -23,22 +23,9 @@

ATT&CK Workbench v

- - - - - - - - - + + + + + + + + + + + diff --git a/app/src/app/components/header/header.component.scss b/app/src/app/components/header/header.component.scss index 2f5c22f1f..d5fcd94d1 100644 --- a/app/src/app/components/header/header.component.scss +++ b/app/src/app/components/header/header.component.scss @@ -33,6 +33,7 @@ overflow: hidden; &.pad-right { padding-right: 12px; } } + .account.pad-left { margin-left: 12px; } .hamburger { position: relative; width: 0; diff --git a/app/src/app/components/header/header.component.ts b/app/src/app/components/header/header.component.ts index 6e3988feb..75ec17d0d 100644 --- a/app/src/app/components/header/header.component.ts +++ b/app/src/app/components/header/header.component.ts @@ -35,7 +35,7 @@ export class HeaderComponent implements AfterViewInit { this.allRoutes = stixRoutes; this.filteredRoutes = stixRoutes.filter( x => x.data.more != true ); this.moreRoutes = stixRoutes.filter( x => x.data.more == true ); - + this.authnTypeSubscription = this.authenticationService.getAuthType().subscribe({ next: (v) => { this.authnType = v }, complete: () => { this.authnTypeSubscription.unsubscribe(); } diff --git a/app/src/app/components/object-status/object-status.component.ts b/app/src/app/components/object-status/object-status.component.ts index a4c47302c..de99c64e8 100644 --- a/app/src/app/components/object-status/object-status.component.ts +++ b/app/src/app/components/object-status/object-status.component.ts @@ -57,12 +57,13 @@ export class ObjectStatusComponent implements OnInit { else if (this.editorService.type == "collection") data$ = this.restAPIService.getAllCollections(options); else if (this.editorService.type == "data-source") data$ = this.restAPIService.getAllDataSources(options); else if (this.editorService.type == "data-component") data$ = this.restAPIService.getAllDataComponents(options); + else if (this.editorService.type == "asset") data$ = this.restAPIService.getAllAssets(options); let objSubscription = data$.subscribe({ next: (data) => { this.objects = data.data; this.object = this.objects.find(object => object.stixID === this.editorService.stixId); if (this.object) { - if (this.object.workflow && this.object.workflow.state) { + if (this.object.workflow?.state) { this.statusControl.setValue(this.object.workflow.state); } this.revoked = this.object.revoked; @@ -154,32 +155,18 @@ export class ObjectStatusComponent implements OnInit { complete: () => { revokedSubscription.unsubscribe(); } }); } else { - // deprecate the 'revoked-by' relationship - let revokedRelationships = this.relationships.filter(relationship => relationship.relationship_type == 'revoked-by'); - for (let relationship of revokedRelationships) { - let other_obj: any; - if (relationship.source_object.stix.id == this.object.stixID) other_obj = relationship.target_object.stix; - else other_obj = relationship.source_object.stix; - - if (!this.isDeprecatedOrRevoked(other_obj)) { - relationship.deprecated = true; - relationship.save(this.restAPIService); - } + // unrevoke object, deprecate the 'revoked-by' relationship + // this is the only case in which a 'revoked-by' relationship is deprecated + let revokedRelationship = this.relationships.find(r => r.relationship_type == 'revoked-by' && r.source_ref == this.object.stixID); + if (revokedRelationship) { + revokedRelationship.deprecated = true; + revokedRelationship.save(this.restAPIService); } - // un-revoke object this.object.revoked = false; this.save(); } } - /** - * Check if the given object is deprecated or revoked - * @param object source or target object of a relationship - */ - private isDeprecatedOrRevoked(object: any) { - return ('x_mitre_deprecated' in object && object.x_mitre_deprecated) || ('revoked' in object && object.revoked); - } - /** * Handle the selection for deprecating or un-deprecating an object * @param event deprecate selection @@ -224,7 +211,8 @@ export class ObjectStatusComponent implements OnInit { // update relationships with the object for (let relationship of this.relationships) { - if (!relationship.deprecated && relationship.relationship_type != 'subtechnique-of') { + // do not deprecate 'subtechnique-of' or 'revoked-by' relationships + if (!relationship.deprecated && !['subtechnique-of', 'revoked-by'].includes(relationship.relationship_type)) { relationship.deprecated = true; saves.push(relationship.save(this.restAPIService)); } diff --git a/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.html b/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.html index bd01d5e5d..4cd17fd4c 100644 --- a/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.html +++ b/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.html @@ -11,7 +11,7 @@ - + @@ -193,6 +193,32 @@

{{reference.source_name}}

+ + +

Objects citing this reference

+
+ No objects in the knowledge base cite this reference. +
+
+ + +

Objects citing this reference

+ +
+ +

Relationships citing this reference

+ +
+
\ No newline at end of file diff --git a/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.scss b/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.scss index c9aafd61b..142bb59c1 100644 --- a/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.scss +++ b/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.scss @@ -8,6 +8,11 @@ } h1 { margin-top: 0; + } + h3 { + margin-top: 20px; + } + h1, h3, .center-align { margin-bottom: 20px; text-align: center; } @@ -48,8 +53,7 @@ } .reference-view { padding: 25px; - max-width: 50vw; - min-width: 35vw; + width: 60vw; .clickable { cursor: pointer; } @@ -67,4 +71,7 @@ margin-top: 24px; margin-bottom: 24px; } + .section-header { + padding-top: 10px; + } } \ No newline at end of file diff --git a/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.ts b/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.ts index f6b4286e0..e0ffd17f5 100644 --- a/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.ts +++ b/app/src/app/components/reference-edit-dialog/reference-edit-dialog.component.ts @@ -14,7 +14,7 @@ import { DeleteDialogComponent } from '../delete-dialog/delete-dialog.component' export class CustomErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { - return !!(control && control.invalid && (control.dirty || control.touched)); + return !!(control?.invalid && (control.dirty || control.touched)); } } @@ -26,6 +26,9 @@ export class CustomErrorStateMatcher implements ErrorStateMatcher { }) export class ReferenceEditDialogComponent implements OnInit, OnDestroy { public reference: ExternalReference; + public stixObjects: StixObject[] = []; + public relationships: StixObject[] = []; + public isNew: boolean; public stage: number = 0; public patchObjects: StixObject[]; @@ -45,6 +48,7 @@ export class ReferenceEditDialogComponent implements OnInit, OnDestroy { public get editing(): boolean { return this.config.mode == 'edit'; } public get editable(): boolean { return this.authenticationService.canEdit(); } public get deletable(): boolean { return this.authenticationService.canDelete(); } + public get numCitingObjects(): number { return this.stixObjects.length + this.relationships.length; } constructor(@Inject(MAT_DIALOG_DATA) public config: ReferenceEditConfig, public dialogRef: MatDialogRef, @@ -55,6 +59,8 @@ export class ReferenceEditDialogComponent implements OnInit, OnDestroy { if (this.config.reference) { this.isNew = false; this.reference = this.referenceCopy; + this.stixObjects = this.config.objects?.filter(sdo => sdo.attackType != 'relationship'); + this.relationships = this.config.objects?.filter(sdo => sdo.attackType == 'relationship'); } else { this.isNew = true; @@ -171,7 +177,7 @@ export class ReferenceEditDialogComponent implements OnInit, OnDestroy { this.stage = 1; //enter patching stage let subscription = this.restApiConnectorService.getAllObjects(null, null, null, null, true, true, true).subscribe({ next: (results) => { - // build ID to [name, attackID] lookup + // build ID to SDO lookup let idToObject = {} results.data.forEach(x => { idToObject[x.stixID] = x }); // find objects with given reference @@ -325,4 +331,5 @@ export interface ReferenceEditConfig { */ mode?: "view" | "edit"; reference?: ExternalReference + objects?: StixObject[] } \ No newline at end of file diff --git a/app/src/app/components/resources-drawer/history-timeline/history-timeline.component.ts b/app/src/app/components/resources-drawer/history-timeline/history-timeline.component.ts index 4abcafe7f..3bd016782 100644 --- a/app/src/app/components/resources-drawer/history-timeline/history-timeline.component.ts +++ b/app/src/app/components/resources-drawer/history-timeline/history-timeline.component.ts @@ -40,8 +40,6 @@ export class HistoryTimelineComponent implements OnInit, OnDestroy { public showObjectHistory: boolean = true; public showRelationshipHistory: boolean = true; public onEditStopSubscription: Subscription; - - constructor(private route: ActivatedRoute, private router: Router, @@ -155,6 +153,7 @@ export class HistoryTimelineComponent implements OnInit, OnDestroy { else if (objectType == "collection") objects$ = this.restAPIConnectorService.getCollection(objectStixID, null, "all"); else if (objectType == "data-source") objects$ = this.restAPIConnectorService.getDataSource(objectStixID, null, "all"); else if (objectType == "data-component") objects$ = this.restAPIConnectorService.getDataComponent(objectStixID, null, "all"); + else if (objectType == "asset") objects$ = this.restAPIConnectorService.getAsset(objectStixID, null, "all"); // set up subscribers to get relationships let relationships$ = this.restAPIConnectorService.getRelatedTo({sourceOrTargetRef: objectStixID, versions: "all"}); // join subscribers diff --git a/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.html b/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.html index bf0f8b69e..82a70211d 100644 --- a/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.html +++ b/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.html @@ -26,8 +26,8 @@
- - + + @@ -38,9 +38,9 @@ [(ngModel)]="note.title"> - - - + + + diff --git a/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.scss b/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.scss index ae04256bb..db975fb67 100644 --- a/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.scss +++ b/app/src/app/components/resources-drawer/notes-editor/notes-editor.component.scss @@ -38,7 +38,6 @@ .sticky-note { padding: 0px; margin-top: 12px; - cursor: pointer; button.mat-button-disabled { opacity: 0.5; } &.edit-outline { @@ -67,12 +66,15 @@ .mat-form-field-underline { display: none; } mat-card-header { + cursor: pointer; textarea { margin-top: 12px; overflow: hidden; + &:read-only { cursor: pointer; } } .mat-card-header-text { width: 100%; } - .history { + .note-subtitle { + margin-bottom: 12px; font-size: 13px; @extend .text-label; } diff --git a/app/src/app/components/stix/alias-property/alias-edit/alias-edit-dialog/alias-edit-dialog.component.html b/app/src/app/components/stix/alias-property/alias-edit/alias-edit-dialog/alias-edit-dialog.component.html index b55a5db16..5a598bd18 100644 --- a/app/src/app/components/stix/alias-property/alias-edit/alias-edit-dialog/alias-edit-dialog.component.html +++ b/app/src/app/components/stix/alias-property/alias-edit/alias-edit-dialog/alias-edit-dialog.component.html @@ -1,6 +1,5 @@
-

Add an associated {{config.object.attackType}}

-

Edit an associated {{config.object.attackType}}

+

{{is_new ? 'Add' : 'Edit'}} an associated {{config.object.attackType}}

associated {{config.object.attackType}} name diff --git a/app/src/app/components/stix/alias-property/alias-edit/aliias-edit.component.spec.ts b/app/src/app/components/stix/alias-property/alias-edit/alias-edit.component.spec.ts similarity index 100% rename from app/src/app/components/stix/alias-property/alias-edit/aliias-edit.component.spec.ts rename to app/src/app/components/stix/alias-property/alias-edit/alias-edit.component.spec.ts diff --git a/app/src/app/components/stix/alias-property/alias-edit/alias-edit.component.ts b/app/src/app/components/stix/alias-property/alias-edit/alias-edit.component.ts index 83b34b332..da2229a86 100644 --- a/app/src/app/components/stix/alias-property/alias-edit/alias-edit.component.ts +++ b/app/src/app/components/stix/alias-property/alias-edit/alias-edit.component.ts @@ -14,7 +14,9 @@ export class AliasEditComponent implements OnInit { @Input() public config: AliasPropertyConfig; public attackType: string; - constructor(public dialog: MatDialog) { } + constructor(public dialog: MatDialog) { + // intentionally left blank + } ngOnInit(): void { let object = Array.isArray(this.config.object)? this.config.object[0] : this.config.object; diff --git a/app/src/app/components/stix/alias-property/alias-property.component.ts b/app/src/app/components/stix/alias-property/alias-property.component.ts index 71ec1677f..02f4914f2 100644 --- a/app/src/app/components/stix/alias-property/alias-property.component.ts +++ b/app/src/app/components/stix/alias-property/alias-property.component.ts @@ -19,7 +19,7 @@ export class AliasPropertyComponent implements OnInit { } export interface AliasPropertyConfig { - /* What is the current mode? Default: 'view + /* What is the current mode? Default: 'view' * view: viewing the alias property * edit: editing the alias property * diff: displaying the diff between two STIX objects. If this mode is selected, two StixObjects must be specified in the objects field diff --git a/app/src/app/components/stix/alias-property/alias-view/alias-view.component.html b/app/src/app/components/stix/alias-property/alias-view/alias-view.component.html index df3f7e23a..21716e2e8 100644 --- a/app/src/app/components/stix/alias-property/alias-view/alias-view.component.html +++ b/app/src/app/components/stix/alias-property/alias-view/alias-view.component.html @@ -29,5 +29,3 @@
- - diff --git a/app/src/app/components/stix/alias-property/alias-view/alias-view.component.ts b/app/src/app/components/stix/alias-property/alias-view/alias-view.component.ts index 0055a5711..ed2ea7ba4 100644 --- a/app/src/app/components/stix/alias-property/alias-view/alias-view.component.ts +++ b/app/src/app/components/stix/alias-property/alias-view/alias-view.component.ts @@ -76,7 +76,7 @@ export class AliasViewComponent implements OnInit { } /** - * return list of aliass with descriptive text + * return list of aliases with descriptive text */ public get description(): Array<[string, string]> { if (this.config.referencesField) { diff --git a/app/src/app/components/stix/datepicker-property/datepicker-property.component.ts b/app/src/app/components/stix/datepicker-property/datepicker-property.component.ts index fe6a92ef3..deadf0876 100644 --- a/app/src/app/components/stix/datepicker-property/datepicker-property.component.ts +++ b/app/src/app/components/stix/datepicker-property/datepicker-property.component.ts @@ -47,7 +47,7 @@ export class DatepickerPropertyComponent { public get formatHint() { return DATE_FORMATS.parse.dateInput; } public get date() { // get date in view display format (i.e. January 2022) if (this.config.object[this.config.field]) { - return moment(this.config.object[this.config.field]).format('MMMM YYYY'); + return moment.utc(this.config.object[this.config.field]).format('MMMM YYYY'); } return null; } diff --git a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.html b/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.html deleted file mode 100644 index 9426a6a04..000000000 --- a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.html +++ /dev/null @@ -1 +0,0 @@ -

descriptive-diff works!

diff --git a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.scss b/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.spec.ts b/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.spec.ts deleted file mode 100644 index 966f7bcdb..000000000 --- a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DescriptiveDiffComponent } from './descriptive-diff.component'; - -describe('DescriptiveDiffComponent', () => { - let component: DescriptiveDiffComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DescriptiveDiffComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DescriptiveDiffComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.ts b/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.ts deleted file mode 100644 index f16db1cfc..000000000 --- a/app/src/app/components/stix/descriptive-property/descriptive-diff/descriptive-diff.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-descriptive-diff', - templateUrl: './descriptive-diff.component.html', - styleUrls: ['./descriptive-diff.component.scss'] -}) -export class DescriptiveDiffComponent implements OnInit { - - constructor() { - // intentionally left blank - } - - ngOnInit(): void { - // intentionally left blank - } -} diff --git a/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.html b/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.html index e2916caa1..05f8df124 100644 --- a/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.html +++ b/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.html @@ -6,7 +6,7 @@

{{config.label}}

info_outline - + @@ -14,7 +14,7 @@

{{config.label}}

{{config.label}}

- +
diff --git a/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.scss b/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.scss index 11fe22f57..d43883a8c 100644 --- a/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.scss +++ b/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.scss @@ -1,6 +1,21 @@ @import "../../../../../style/globals"; .descriptive-edit { + @-moz-document url-prefix() { + min-height: 40vh; + .moz-height { + min-height: 40vh !important; + max-height: 60vh; + overflow-y: auto !important; + } + .markdown-view { + min-height: 40vh !important; + display: flex; + } + } + .mat-input-element { + line-height: 1.5; + } .mat-tab-header { border: 0px; } diff --git a/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.ts b/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.ts index 2abc4d6f3..44a3492a7 100644 --- a/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.ts +++ b/app/src/app/components/stix/descriptive-property/descriptive-edit/descriptive-edit.component.ts @@ -11,7 +11,6 @@ import { EditorService } from 'src/app/services/editor/editor.service'; styleUrls: ['./descriptive-edit.component.scss'], encapsulation: ViewEncapsulation.None }) - export class DescriptiveEditComponent implements OnDestroy, OnInit { @Input() public config: DescriptivePropertyConfig; @ViewChild('description') public description: DescriptiveViewComponent; @@ -22,9 +21,9 @@ export class DescriptiveEditComponent implements OnDestroy, OnInit { constructor(public restApiConnector: RestApiConnectorService, public editorService: EditorService) { } ngOnInit(): void { - if (this.config && 'parseReferences' in this.config) { - this.parseReferences = this.config.parseReferences; - } + if (this.config && 'parseReferences' in this.config) { + this.parseReferences = this.config.parseReferences; + } } ngOnDestroy(): void { @@ -46,13 +45,13 @@ export class DescriptiveEditComponent implements OnDestroy, OnInit { */ public parseCitations(): void { if (this.parseReferences) { - this.parsingCitations = true; - this.sub = this.config.object['external_references'].parseObjectCitations(this.config.object, this.restApiConnector).subscribe({ - next: (result) => { - this.parsingCitations = false; - this.editorService.onReloadReferences.emit(); - } - }) + this.parsingCitations = true; + this.sub = this.config.object['external_references'].parseObjectCitations(this.config.object, this.restApiConnector).subscribe({ + next: (result) => { + this.parsingCitations = false; + this.editorService.onReloadReferences.emit(); + } + }) } } } diff --git a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.html b/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.html deleted file mode 100644 index 4870eda42..000000000 --- a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.html +++ /dev/null @@ -1 +0,0 @@ -

external-references-diff works!

diff --git a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.scss b/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.spec.ts b/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.spec.ts deleted file mode 100644 index 8e29d9de3..000000000 --- a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ExternalReferencesDiffComponent } from './external-references-diff.component'; - -describe('ExternalReferencesDiffComponent', () => { - let component: ExternalReferencesDiffComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ExternalReferencesDiffComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ExternalReferencesDiffComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.ts b/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.ts deleted file mode 100644 index 1631360c2..000000000 --- a/app/src/app/components/stix/external-references-property/external-references-diff/external-references-diff.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-external-references-diff', - templateUrl: './external-references-diff.component.html', - styleUrls: ['./external-references-diff.component.scss'] -}) -export class ExternalReferencesDiffComponent implements OnInit { - - constructor() { - // intentionally left blank - } - - ngOnInit(): void { - // intentionally left blank - } -} diff --git a/app/src/app/components/stix/list-property/list-edit/list-edit.component.html b/app/src/app/components/stix/list-property/list-edit/list-edit.component.html index 66faeb28d..b588873bb 100644 --- a/app/src/app/components/stix/list-property/list-edit/list-edit.component.html +++ b/app/src/app/components/stix/list-property/list-edit/list-edit.component.html @@ -1,5 +1,5 @@
- + {{config.label? config.label : config.field}} @@ -12,7 +12,7 @@ (matChipInputTokenEnd)="add($event)" /> - + @@ -31,7 +31,7 @@ {{item}} - + {{config.label? config.label : config.field}} diff --git a/app/src/app/components/stix/list-property/list-edit/list-edit.component.scss b/app/src/app/components/stix/list-property/list-edit/list-edit.component.scss index b22c86a3c..a94e0c860 100644 --- a/app/src/app/components/stix/list-property/list-edit/list-edit.component.scss +++ b/app/src/app/components/stix/list-property/list-edit/list-edit.component.scss @@ -15,6 +15,7 @@ flex-direction: column; margin: 0.25em 0 0 0 !important; :active, :focus { outline: none; } + padding-bottom: 0px !important; } .mat-form-field-flex { flex: 1 0; diff --git a/app/src/app/components/stix/list-property/list-edit/list-edit.component.ts b/app/src/app/components/stix/list-property/list-edit/list-edit.component.ts index 0c6dce51c..eb952da99 100644 --- a/app/src/app/components/stix/list-property/list-edit/list-edit.component.ts +++ b/app/src/app/components/stix/list-property/list-edit/list-edit.component.ts @@ -50,7 +50,8 @@ export class ListEditComponent implements OnInit, AfterContentChecked { "effective_permissions": "x_mitre_effective_permissions", "permissions_required": "x_mitre_permissions_required", "collection_layers": "x_mitre_collection_layers", - "data_sources": "x_mitre_data_sources" + "data_sources": "x_mitre_data_sources", + "sectors": "x_mitre_sectors" } public domains = [ "enterprise-attack", @@ -77,7 +78,8 @@ export class ListEditComponent implements OnInit, AfterContentChecked { || this.config.field == 'impact_type' || this.config.field == 'domains' || this.config.field == 'collection_layers' - || this.config.field == 'data_sources') { + || this.config.field == 'data_sources' + || this.config.field == 'sectors') { if (!this.dataLoaded) { let data$ = this.restAPIConnectorService.getAllAllowedValues(); this.sub = data$.subscribe({ @@ -117,19 +119,18 @@ export class ListEditComponent implements OnInit, AfterContentChecked { complete: () => { subscription.unsubscribe(); } }) } else if (this.config.field == 'parentTechnique') { - this.type = 'technique'; - const subscription = this.restAPIConnectorService.getAllTechniques().subscribe({ - next: (r: Paginated) => { - this.allObjects = r.data.filter((t) => !t.is_subtechnique); - const selectableTechniqueIDs = r.data.map(t => t.stixID); - this.select = new SelectionModel(false, selectableTechniqueIDs); - this.dataLoaded = true; - }, - complete: () => { - subscription.unsubscribe(); - } - }); - + this.type = 'technique'; + const subscription = this.restAPIConnectorService.getAllTechniques().subscribe({ + next: (r: Paginated) => { + this.allObjects = r.data.filter((t) => !t.is_subtechnique); + const selectableTechniqueIDs = r.data.map(t => t.stixID); + this.select = new SelectionModel(false, selectableTechniqueIDs); + this.dataLoaded = true; + }, + complete: () => { + subscription.unsubscribe(); + } + }); } } diff --git a/app/src/app/components/stix/stix-list/stix-list.component.html b/app/src/app/components/stix/stix-list/stix-list.component.html index 584689238..88bac6eea 100644 --- a/app/src/app/components/stix/stix-list/stix-list.component.html +++ b/app/src/app/components/stix/stix-list/stix-list.component.html @@ -3,8 +3,8 @@ -
-
+
+
@@ -112,7 +112,7 @@ - + diff --git a/app/src/app/components/stix/stix-list/stix-list.component.ts b/app/src/app/components/stix/stix-list/stix-list.component.ts index 96eff0a3d..56f52fe44 100644 --- a/app/src/app/components/stix/stix-list/stix-list.component.ts +++ b/app/src/app/components/stix/stix-list/stix-list.component.ts @@ -66,6 +66,7 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { // options provided to the user for grouping and filtering public filterOptions: FilterGroup[] = []; + public showControls: boolean = true; // current grouping and filtering selections public filter: string[] = []; @@ -100,7 +101,8 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { "identity": "identity", "marking-definition": "marking-definition", "x-mitre-data-source": "data-source", - "x-mitre-data-component": "data-component" + "x-mitre-data-component": "data-component", + "x-mitre-asset": "asset" } // all possible each type of filter/groupBy @@ -150,7 +152,7 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { if (values.properties) { // extract domain->platforms properties from allowedValues structure let properties = values.properties.find(p => p.propertyName == 'x_mitre_platforms'); - if (properties && properties.domains) { + if (properties?.domains) { properties.domains.forEach(domain => { domainMap.set(domain.domainName, domain.allowedValues); }); @@ -162,6 +164,7 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { }, complete: () => { // build the stix list table + this.showControls = this.config.showControls ?? true; this.buildTable(); this.setUpControls(); // get objects from backend if data is not from config @@ -306,6 +309,19 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { "display": "descriptive" }] break; + case "asset": + this.addColumn("", "workflow", "icon"); + this.addColumn("", "state", "icon"); + this.addColumn("ID", "attackID", "plain", false); + this.addColumn("name", "name", "plain", sticky_allowed, ["name"]); + this.addColumn("platforms", "platforms", "list"); + this.addColumn("sectors", "sectors", "list"); + this.addVersionsAndDatesColumns(); + this.tableDetail = [{ + "field": "description", + "display": "descriptive" + }] + break; case "relationship": this.addColumn("", "state", "icon"); if (this.config.relationshipType && this.config.relationshipType !== "detects") { @@ -372,7 +388,7 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { } // open-link icon setup - if (this.config.clickBehavior && this.config.clickBehavior == "linkToObjectRef") { + if (this.config.clickBehavior && ["linkToObjectPage", "linkToObjectRef"].includes(this.config.clickBehavior)) { controls_after.push("open-link") } @@ -514,6 +530,10 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { complete: () => { subscription.unsubscribe(); } }); } + else if (this.config.clickBehavior && this.config.clickBehavior == "linkToObjectPage") { + this.onRowAction.emit(); // close any open dialogs + this.router.navigateByUrl('/' + element.attackType + '/' + element.stixID); + } else if (this.config.clickBehavior && this.config.clickBehavior == "linkToSourceRef") { let source_ref = element['source_ref']; // Get type to navigate from source_ref @@ -786,6 +806,7 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { else if (this.config.type == "relationship") this.data$ = this.restAPIConnectorService.getRelatedTo({ sourceRef: this.config.sourceRef, targetRef: this.config.targetRef, sourceType: this.config.sourceType, targetType: this.config.targetType, relationshipType: this.config.relationshipType, excludeSourceRefs: this.config.excludeSourceRefs, excludeTargetRefs: this.config.excludeTargetRefs, limit: limit, offset: offset, includeDeprecated: deprecated }); else if (this.config.type == "data-source") this.data$ = this.restAPIConnectorService.getAllDataSources(options); else if (this.config.type == "data-component") this.data$ = this.restAPIConnectorService.getAllDataComponents(options); + else if (this.config.type == "asset") this.data$ = this.restAPIConnectorService.getAllAssets(options); else if (this.config.type == "marking-definition") this.data$ = this.restAPIConnectorService.getAllMarkingDefinitions(options); else if (this.config.type == "note") this.data$ = this.restAPIConnectorService.getAllNotes(options); let subscription = this.data$.subscribe({ @@ -886,7 +907,7 @@ export class StixListComponent implements OnInit, AfterViewInit, OnDestroy { } //allowed types for StixListConfig -type type_attacktype = "collection" | "campaign" | "group" | "matrix" | "mitigation" | "software" | "tactic" | "technique" | "relationship" | "data-source" | "data-component" | "marking-definition" | "note"; +type type_attacktype = "collection" | "campaign" | "group" | "matrix" | "mitigation" | "software" | "tactic" | "technique" | "relationship" | "data-source" | "data-component" | "asset" | "marking-definition" | "note"; type selection_types = "one" | "many" | "disabled"; type filter_types = "state" | "workflow_status"; export interface StixListConfig { @@ -922,6 +943,8 @@ export interface StixListConfig { showLinks?: boolean; /** default true, if false hides the filter dropdown menu */ showFilters?: boolean; + /** default true, if false hides all search/filter/control options */ + showControls?: boolean; /** display the 'show deprecated' filter, default false * this may be relevant when displaying a list of embedded relationships, where * the list of STIX objects is provided in the 'stixObjects' configuration @@ -935,12 +958,13 @@ export interface StixListConfig { * How should the table act when the row is clicked? default "expand" * "expand": expand the row to show additional detail * "dialog": open a dialog with the full object definition + * "linkToObjectPage": clicking redirects to the object's page * "linkToSourceRef": clicking redirects to the source ref object * "linkToTargetRef": clicking redirects user to target ref object - * "linkToObjectRef": clicking redirects user to first object in the object ref array + * "linkToObjectRef": clicking redirects user to first object in a Note's object ref array * "none": row is not clickable */ - clickBehavior?: "expand" | "dialog" | "linkToSourceRef" | "linkToTargetRef" | "linkToObjectRef" | "none"; + clickBehavior?: "expand" | "dialog" | "linkToObjectPage" | "linkToSourceRef" | "linkToTargetRef" | "linkToObjectRef" | "none"; /** * Default false. If true, allows for edits of the objects in the table * when in dialog mode diff --git a/app/src/app/components/stix/string-property/string-property.component.html b/app/src/app/components/stix/string-property/string-property.component.html index fbcbb0db6..6c5c59b3b 100644 --- a/app/src/app/components/stix/string-property/string-property.component.html +++ b/app/src/app/components/stix/string-property/string-property.component.html @@ -5,11 +5,10 @@
-
+
{{config.label? config.label : config.field}}
- -
\ No newline at end of file +
diff --git a/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.html b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.html new file mode 100644 index 000000000..1e9bb13c3 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.html @@ -0,0 +1,37 @@ +
+

{{isNew ? 'Add' : 'Edit'}} {{config.tooltip}}

+ + + + + {{field.name}} + + + + + + +   + Loading {{field.label? field.label : field.name}}... + + {{field.label ? field.label : field.name}} + + + + + + {{value}} cancel + + + + {{item}} + + + + + +
+ + +
+
\ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.scss b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.scss new file mode 100644 index 000000000..b05b2f22a --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.scss @@ -0,0 +1,13 @@ +.subtype-edit-dialog { + min-width: 75vw; + .mat-form-field { + width: 100%; + } + .buttons { + button + button { + margin-left: 10px; + } + margin-top: 24px; + margin-bottom: 24px; + } +} \ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.spec.ts b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.spec.ts new file mode 100644 index 000000000..e74e312a9 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SubtypeDialogComponent } from './subtype-dialog.component'; + +describe('SubtypeDialogComponent', () => { + let component: SubtypeDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SubtypeDialogComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SubtypeDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.ts b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.ts new file mode 100644 index 000000000..0e977f9d1 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-dialog/subtype-dialog.component.ts @@ -0,0 +1,128 @@ +import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { MatOptionSelectionChange } from '@angular/material/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Subscription } from 'rxjs'; +import { StixObject } from 'src/app/classes/stix'; +import { RestApiConnectorService } from 'src/app/services/connectors/rest-api/rest-api-connector.service'; +import { EditorService } from 'src/app/services/editor/editor.service'; + +@Component({ + selector: 'app-subtype-dialog', + templateUrl: './subtype-dialog.component.html', + styleUrls: ['./subtype-dialog.component.scss'] +}) +export class SubtypeDialogComponent implements OnInit, OnDestroy { + public isNew: boolean = false; + public data: any = {}; + + public allowedValues: any = {}; + public selectControls: {[index: string] : FormControl} = {} ; + public dataLoaded: boolean = false; + private allowedValuesSub: Subscription = new Subscription(); + private saveSubscription: Subscription = new Subscription(); + + public get isValid(): boolean { + let required = this.config.subtypeFields.filter(field => field.required); + return required.every(field => field.name in this.data && this.data[field.name].length) + } + + constructor(public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public config: SubtypeDialogConfig, + public restApiService: RestApiConnectorService, + public editorService: EditorService) { + this.isNew = config.index == undefined; + if (!this.isNew) this.data = config.object[config.field][config.index]; + } + + ngOnInit(): void { + // retrieve 'select' fields + let selections = this.config.subtypeFields.filter(field => field.editType == 'select').map(field => field.name); + if (!selections.length) return; + + // create a form control for each 'select' field + selections.forEach(fieldName => { + if (!this.data[fieldName]) this.data[fieldName] = []; + this.selectControls[fieldName] = new FormControl(this.data[fieldName]); + }); + + // load allowed values for 'select' fields + this.allowedValuesSub = this.restApiService.getAllAllowedValues().subscribe({ + next: (data) => { + let allAllowedValues = data.find(obj => obj.objectType == this.config.object.attackType); + selections.forEach(field => { + let values: Set = new Set(); + let property = allAllowedValues.properties.find(p => p.propertyName == field); + if ("domains" in this.config.object) { + let obj = this.config.object as any; + property.domains.forEach(domain => { + if (obj.domains.includes(domain.domainName)) { + domain.allowedValues.forEach(values.add, values); + } + }) + } else { // domains not specified on object + property.domains.forEach(domain => { + domain.allowedValues.forEach(values.add, values); + }); + } + this.allowedValues[field] = Array.from(values); + }); + this.dataLoaded = true; + } + }); + } + + ngOnDestroy(): void { + if (this.allowedValuesSub) this.allowedValuesSub.unsubscribe(); + if (this.saveSubscription) this.saveSubscription.unsubscribe(); + } + + /** Add value to subtype field */ + public add(): void { + if (this.config.index || this.config.index === 0) { + // update the existing value + this.config.object[this.config.field][this.config.index] = this.data; + } else { + // add the value to the field + this.config.object[this.config.field].push(this.data); + } + + // parse citations + this.saveSubscription = this.config.object['external_references'].parseObjectCitations(this.config.object, this.restApiService).subscribe({ + next: (result) => { + this.editorService.onReloadReferences.emit(); + } + }) + this.dialogRef.close(); + } + + /** Handles onSelectionChange event to add or remove the + * user's selection from a multi-select field */ + public change(event: MatOptionSelectionChange, fieldName: string): void { + if (!event.isUserInput) return; + if (event.source.selected) this.data[fieldName].push(event.source.value); + else this.remove(fieldName, event.source.value); + } + + /** Remove value from multi-select field */ + public remove(fieldName: string, value: string): void { + let values = this.selectControls[fieldName].value as string[]; + let i = values.indexOf(value); + if (i >= 0) values.splice(i, 1); + this.selectControls[fieldName].setValue(values); + } +} + +export interface SubtypeDialogConfig { + object: StixObject; + field: string; + index?: number; + tooltip: string; + subtypeFields: { + name: string; + editType: string; + label: string; + required?: boolean; + key?: boolean; /** Specifies which subtypeField is used as an indexing key, there must be at least one */ + }[]; +} \ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.html b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.html new file mode 100644 index 000000000..3ccf41985 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.html @@ -0,0 +1,13 @@ +
+
+ + + {{value}} cancel + + + +
+ +
\ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.scss b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.scss new file mode 100644 index 000000000..fb5897d42 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.scss @@ -0,0 +1,5 @@ +.subtype-edit { + .mat-chip { + cursor: pointer; + } +} \ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.spec.ts b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.spec.ts new file mode 100644 index 000000000..f26afb64e --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SubtypeEditComponent } from './subtype-edit.component'; + +describe('SubtypeEditComponent', () => { + let component: SubtypeEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SubtypeEditComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SubtypeEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.ts b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.ts new file mode 100644 index 000000000..b2a85067c --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-edit/subtype-edit.component.ts @@ -0,0 +1,52 @@ +import { Component, Input, ViewEncapsulation } from '@angular/core'; +import { SubtypePropertyConfig } from '../subtype-property.component'; +import { MatDialog } from '@angular/material/dialog'; +import { SubtypeDialogComponent } from '../subtype-dialog/subtype-dialog.component'; + +@Component({ + selector: 'app-subtype-edit', + templateUrl: './subtype-edit.component.html', + styleUrls: ['./subtype-edit.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class SubtypeEditComponent { + @Input() public config: SubtypePropertyConfig; + + /** + * Get list of key values from subtype list + */ + public get keyValues(): any[] { + let key = this.config.subtypeFields.find(subtype => subtype.key).name; + return this.config.object[this.config.field].map(value => value[key]); + } + + constructor(public dialog: MatDialog) { + // intentionally left blank + } + + public removeValue(i: number): void { + // remove subtype from field + this.config.object[this.config.field].splice(i, 1); + } + + /** + * Open the edit dialog to create/edit the item + * @param i the index of the selected item to edit; or, if none is + * provided, create a new item + */ + public editValue(i?: number): void { + let ref = this.dialog.open(SubtypeDialogComponent, { + maxHeight: "75vh", + data: { + object: this.config.object, + field: this.config.field, + index: i, + subtypeFields: this.config.subtypeFields, + tooltip: this.config.tooltip + } + }); + let subscription = ref.afterClosed().subscribe({ + complete: () => { subscription.unsubscribe(); } + }); + } +} diff --git a/app/src/app/components/stix/subtype-property/subtype-property.component.html b/app/src/app/components/stix/subtype-property/subtype-property.component.html new file mode 100644 index 000000000..4197ad945 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-property.component.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/app/src/app/components/stix/subtype-property/subtype-property.component.spec.ts b/app/src/app/components/stix/subtype-property/subtype-property.component.spec.ts new file mode 100644 index 000000000..acb406555 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-property.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SubtypePropertyComponent } from './subtype-property.component'; + +describe('SubtypePropertyComponent', () => { + let component: SubtypePropertyComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SubtypePropertyComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SubtypePropertyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/app/src/app/components/stix/subtype-property/subtype-property.component.ts b/app/src/app/components/stix/subtype-property/subtype-property.component.ts new file mode 100644 index 000000000..28055e870 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-property.component.ts @@ -0,0 +1,34 @@ +import { Component, Input } from '@angular/core'; +import { StixObject } from 'src/app/classes/stix'; + +@Component({ + selector: 'app-subtype-property', + templateUrl: './subtype-property.component.html' +}) +export class SubtypePropertyComponent { + @Input() public config: SubtypePropertyConfig +} + +export interface SubtypePropertyConfig { + /* What is the current mode? Default: 'view' */ + mode?: "view" | "edit"; + /* The object to show the field of */ + object: StixObject; + /* The field of the object to visualize */ + field: string; + /* The label for labelled box */ + label: string; + /* The object's references field. References will be removed if not included */ + referencesField?: string; + /* The fields & types of the subtype property */ + subtypeFields: { + name: string; + type: "string" | "select"; + required?: boolean; // default false + label?: string; + supportsReferences?: boolean; // whether this field supports references, default false + key?: boolean; /** The key field, must have at least one */ + }[]; + /* The tooltip for the add button/edit dialog */ + tooltip: string; +} \ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.html b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.html new file mode 100644 index 000000000..37fba22a1 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.html @@ -0,0 +1,17 @@ +
+
+ + + + + + + + +
{{ (column.label ? column.label : column.name) | titlecase }} + {{format(element[column.name])}} + +
+
+ +
diff --git a/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.scss b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.scss new file mode 100644 index 000000000..9574a4b01 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.scss @@ -0,0 +1,29 @@ +@import "../../../../../style/globals"; + +.subtype-view { + @extend .labelled-box; + + .subtype-table{ + width: 100%; + padding: 8px; + tr.mat-header-row { height: 25px; } + .mat-cell, .mat-header-cell { + padding: 0 10px; + .light & { border-color: border-color(light); } + .dark & { border-color: border-color(dark); } + } + .ref-column { + // width: 65%; + } + } + .subtype-markdown { + p { + padding: 0; + margin: 0; + } + sup { + vertical-align: top; + position: relative; + } + } +} \ No newline at end of file diff --git a/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.spec.ts b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.spec.ts new file mode 100644 index 000000000..24d96de46 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SubtypeViewComponent } from './subtype-view.component'; + +describe('SubtypeViewComponent', () => { + let component: SubtypeViewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SubtypeViewComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SubtypeViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.ts b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.ts new file mode 100644 index 000000000..a28146321 --- /dev/null +++ b/app/src/app/components/stix/subtype-property/subtype-view/subtype-view.component.ts @@ -0,0 +1,79 @@ +import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { SubtypePropertyConfig } from '../subtype-property.component'; + +@Component({ + selector: 'app-subtype-view', + templateUrl: './subtype-view.component.html', + styleUrls: ['./subtype-view.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class SubtypeViewComponent implements OnInit { + @Input() public config: SubtypePropertyConfig; + + private citationRegex = /\(Citation: (.*?)\)/gmu; + public showMore: boolean = false; + public detailTable: any[] = []; + + public get subtypeFields() { return this.config.subtypeFields; } + public get fieldLabels(): string[] { return this.config.subtypeFields.map(f => f.label ? f.label : f.name); } + + public get valueCopy() { + return JSON.parse(JSON.stringify(this.config.object[this.config.field])); //deep copy + } + + ngOnInit(): void { + this.detailTable = this.valueCopy; + this.buildTable(); + } + + /** + * Get list of references in string + * @param value string that may contains references + */ + private getReferences(value: string): Array { + return value.match(this.citationRegex); + } + + /** + * Get HTML string for reference + * @param sourceName source name of the reference + */ + private referenceToHTML(sourceName: string): string { + let reference = this.config.object[this.config.referencesField].getReference(sourceName); + let referenceNumber = this.config.object[this.config.referencesField].getIndexOfReference(sourceName); + + if (reference && referenceNumber) { + if (reference.url) { + return "
[" + referenceNumber + "]"; + } + return "[" + referenceNumber + "]" + } + return ""; + } + + // Build table of values including any inline citations + public buildTable(): void { + // get subtype field that supports references + let referenceField = this.config.subtypeFields.find(f => f.supportsReferences); + if (!referenceField || !this.config.referencesField) return; + for (let row of this.detailTable) { + if (referenceField.name in row) { + // field supporting references found in row, parse citations + let references = this.getReferences(row[referenceField.name]); + if (references) { + for (let reference of references) { + let sourceName = reference.split("(Citation: ")[1].slice(0, -1); + let referenceHTML = this.referenceToHTML(sourceName); + row[referenceField.name] = row[referenceField.name].replace(reference, referenceHTML); + } + } + } + } + } + + /** Format table column */ + public format(value): string { + if (Array.isArray(value)) return value.join("; "); + return value; + } +} diff --git a/app/src/app/components/stix/timestamp-property/README.md b/app/src/app/components/stix/timestamp-property/README.md deleted file mode 100644 index 7f7d2820c..000000000 --- a/app/src/app/components/stix/timestamp-property/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# timestamp-property -`timestamp-property.component` is used to display timestamp properties of STIX objects such as `created` and `modified` dates. \ No newline at end of file diff --git a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.html b/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.html deleted file mode 100644 index 2fe189a5d..000000000 --- a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.html +++ /dev/null @@ -1 +0,0 @@ -

timestamp-diff works!

diff --git a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.scss b/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.spec.ts b/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.spec.ts deleted file mode 100644 index ae7e91cf7..000000000 --- a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TimestampDiffComponent } from './timestamp-diff.component'; - -describe('TimestampDiffComponent', () => { - let component: TimestampDiffComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ TimestampDiffComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TimestampDiffComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.ts b/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.ts deleted file mode 100644 index 379efed30..000000000 --- a/app/src/app/components/stix/timestamp-property/timestamp-diff/timestamp-diff.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { TimestampPropertyConfig } from '../timestamp-property.component'; - -@Component({ - selector: 'app-timestamp-diff', - templateUrl: './timestamp-diff.component.html', - styleUrls: ['./timestamp-diff.component.scss'] -}) -export class TimestampDiffComponent implements OnInit { - @Input() public config: TimestampPropertyConfig; - - constructor() { - // intentionally left blank - } - - ngOnInit(): void { - // intentionally left blank - } -} diff --git a/app/src/app/components/stix/timestamp-property/timestamp-property.component.ts b/app/src/app/components/stix/timestamp-property/timestamp-property.component.ts index d16b737a4..3342df746 100644 --- a/app/src/app/components/stix/timestamp-property/timestamp-property.component.ts +++ b/app/src/app/components/stix/timestamp-property/timestamp-property.component.ts @@ -57,5 +57,5 @@ export interface TimestampPropertyConfig { /* if true, the username of the user who created the object will be displayed before the timestamp. Default: false */ - displayCreatorUsernameWithTimestamp?: boolean; + showDisplayName?: boolean; } \ No newline at end of file diff --git a/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.html b/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.html index 931972d06..f967064b9 100644 --- a/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.html +++ b/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.html @@ -1,6 +1,6 @@
- - {{displayName}}, - +
+ {{displayName}} +
{{config.humanize? humanized : timestamp}}
\ No newline at end of file diff --git a/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.ts b/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.ts index c4dc7d5de..dd00697be 100644 --- a/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.ts +++ b/app/src/app/components/stix/timestamp-property/timestamp-view/timestamp-view.component.ts @@ -22,7 +22,7 @@ export class TimestampViewComponent implements OnInit { } ngOnInit(): void { - if (this.config.displayCreatorUsernameWithTimestamp) { + if (this.config.showDisplayName) { const object = Array.isArray(this.config.object) ? this.config.object[0] : this.config.object; const createdByAccountId = object.workflow.created_by_user_account; if (!createdByAccountId) { diff --git a/app/src/app/components/stix/version-property/version-edit/version-edit.component.scss b/app/src/app/components/stix/version-property/version-edit/version-edit.component.scss index bb9951dee..7e6532e8f 100644 --- a/app/src/app/components/stix/version-property/version-edit/version-edit.component.scss +++ b/app/src/app/components/stix/version-property/version-edit/version-edit.component.scss @@ -2,4 +2,7 @@ mat-form-field { width: 100%; } + .mat-form-field-wrapper { + padding-bottom: 0 !important; + } } \ No newline at end of file diff --git a/app/src/app/components/stix/version-property/version-edit/version-edit.component.ts b/app/src/app/components/stix/version-property/version-edit/version-edit.component.ts index 790e16398..fd20c434a 100644 --- a/app/src/app/components/stix/version-property/version-edit/version-edit.component.ts +++ b/app/src/app/components/stix/version-property/version-edit/version-edit.component.ts @@ -1,10 +1,11 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { VersionPropertyConfig } from '../version-property.component'; @Component({ selector: 'app-version-edit', templateUrl: './version-edit.component.html', - styleUrls: ['./version-edit.component.scss'] + styleUrls: ['./version-edit.component.scss'], + encapsulation: ViewEncapsulation.None }) export class VersionEditComponent implements OnInit { @Input() public config: VersionPropertyConfig; diff --git a/app/src/app/services/connectors/rest-api/rest-api-connector.service.ts b/app/src/app/services/connectors/rest-api/rest-api-connector.service.ts index 2320e6d20..28c3702e1 100644 --- a/app/src/app/services/connectors/rest-api/rest-api-connector.service.ts +++ b/app/src/app/services/connectors/rest-api/rest-api-connector.service.ts @@ -25,15 +25,17 @@ import { DataComponent } from 'src/app/classes/stix/data-component'; import { UserAccount } from 'src/app/classes/authn/user-account'; import { Campaign } from 'src/app/classes/stix/campaign'; import { Team } from 'src/app/classes/authn/team'; +import { Asset } from 'src/app/classes/stix/asset'; //attack types -type AttackType = "campaign" | "collection" | "group" | "matrix" | "mitigation" | "software" | "tactic" | "technique" | "relationship" | "note" | "identity" | "marking-definition" | "data-source" | "data-component"; +type AttackType = "asset" | "campaign" | "collection" | "group" | "matrix" | "mitigation" | "software" | "tactic" | "technique" | "relationship" | "note" | "identity" | "marking-definition" | "data-source" | "data-component"; // pluralize AttackType const attackTypeToPlural = { "technique": "techniques", "tactic": "tactics", "group": "groups", "campaign": "campaigns", + "asset": "assets", "software": "software", "mitigation": "mitigations", "matrix": "matrices", @@ -51,6 +53,7 @@ const attackTypeToClass = { "tactic": Tactic, "group": Group, "campaign": Campaign, + "asset": Asset, "software": Software, "mitigation": Mitigation, "matrix": Matrix, @@ -69,6 +72,7 @@ const stixTypeToClass = { "x-mitre-tactic": Tactic, "intrusion-set": Group, "campaign": Campaign, + "x-mitre-asset": Asset, "tool": Software, "malware": Software, "course-of-action": Mitigation, @@ -275,6 +279,18 @@ export class RestApiConnectorService extends ApiConnector { * @returns {Observable} observable of retrieved objects */ public get getAllCampaigns() { return this.getStixObjectsFactory("campaign"); } + /** + * Get all assets + * @param {number} [limit] the number of assets to retrieve + * @param {number} [offset] the number of assets to skip + * @param {string} [state] if specified, only get objects with this state + * @param {string} [lastUpdatedBy] if specified, only get objects which were last updated by these users + * @param {boolean} [revoked] if true, get revoked objects + * @param {boolean} [deprecated] if true, get deprecated objects + * @param {string[]} [excludeIDs] if specified, excludes these STIX IDs from the result + * @returns {Observable} observable of retrieved objects + */ + public get getAllAssets() { return this.getStixObjectsFactory("asset"); } /** * Get all software * @param {number} [limit] the number of software to retrieve @@ -632,6 +648,14 @@ export class RestApiConnectorService extends ApiConnector { * @returns {Observable} the object with the given ID and modified date */ public get getCampaign() { return this.getStixObjectFactory("campaign"); } + /** + * Get a single asset by STIX ID + * @param {string} id the object STIX ID + * @param {Date} [modified] if specified, get the version modified at the given date + * * @param {versions} [string] default "latest", if "all" returns all versions of the object instead of just the latest version. + * @returns {Observable} the object with the given ID and modified date + */ + public get getAsset() { return this.getStixObjectFactory("asset"); } /** * Get a single software by STIX ID * @param {string} id the object STIX ID @@ -752,6 +776,12 @@ export class RestApiConnectorService extends ApiConnector { * @returns {Observable} the created object */ public get postCampaign() { return this.postStixObjectFactory("campaign"); } + /** + * POST (create) a new asset + * @param {Asset} object the object to create + * @returns {Observable} the created object + */ + public get postAsset() { return this.postStixObjectFactory("asset"); } /** * POST (create) a new software * @param {Software} object the object to create @@ -866,6 +896,13 @@ export class RestApiConnectorService extends ApiConnector { * @returns {Observable} the updated object */ public get putCampaign() { return this.putStixObjectFactory("campaign"); } + /** + * PUT (update) an asset + * @param {Asset} object the object to update + * @param {Date} [modified] optional, the modified date to overwrite. If omitted, uses the modified field of the object + * @returns {Observable} the updated object + */ + public get putAsset() { return this.putStixObjectFactory("asset"); } /** * PUT (update) a software * @param {Software} object the object to update @@ -960,6 +997,12 @@ export class RestApiConnectorService extends ApiConnector { * @returns {Observable<{}>} observable of the response body */ public get deleteCampaign() { return this.deleteStixObjectFactory("campaign"); } + /** + * DELETE an asset + * @param {string} id the STIX ID of the object to delete + * @returns {Observable<{}>} observable of the response body + */ + public get deleteAsset() { return this.deleteStixObjectFactory("asset"); } /** * DELETE a software * @param {string} id the STIX ID of the object to delete diff --git a/app/src/app/services/editor/editor.service.ts b/app/src/app/services/editor/editor.service.ts index 120ea04de..8d1c0e266 100644 --- a/app/src/app/services/editor/editor.service.ts +++ b/app/src/app/services/editor/editor.service.ts @@ -43,13 +43,14 @@ export class EditorService { let editable = this.getEditableFromRoute(this.router.routerState, this.router.routerState.root); let attackType = this.route.root.firstChild.snapshot.data.breadcrumb; this.editable = editable.length > 0 && editable.every(x => x) && this.authenticationService.canEdit(attackType); - // if we have a group type and it is NOT new we can create a collection from all of the objects in the group - this.isGroup = this.type === 'group' && !this.router.url.includes("/new"); this.hasWorkflow = attackType !== 'home'; if (!(this.editable && this.hasWorkflow)) this.sidebarService.currentTab = "references"; this.sidebarService.setEnabled("history", this.editable && this.hasWorkflow); this.sidebarService.setEnabled("notes", this.editable && this.hasWorkflow); + this.isGroup = false; if (this.editable) { + // if we have a group type and it is NOT new we can create a collection from all of the objects in the group + this.isGroup = this.type === 'group' && !this.router.url.includes("/new"); if (!this.hasWorkflow) { this.hasRelationships = false; if (this.type.includes('profile')) this.deletable = false; diff --git a/app/src/app/views/reference-manager/reference-manager.component.ts b/app/src/app/views/reference-manager/reference-manager.component.ts index 385d21d8d..141aa6ce3 100644 --- a/app/src/app/views/reference-manager/reference-manager.component.ts +++ b/app/src/app/views/reference-manager/reference-manager.component.ts @@ -5,6 +5,7 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { fromEvent, Observable, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, filter, tap } from 'rxjs/operators'; import { ExternalReference } from 'src/app/classes/external-references'; +import { Relationship } from 'src/app/classes/stix/relationship'; import { StixObject } from 'src/app/classes/stix/stix-object'; import { ReferenceEditDialogComponent } from 'src/app/components/reference-edit-dialog/reference-edit-dialog.component'; import { AuthenticationService } from 'src/app/services/connectors/authentication/authentication.service'; @@ -19,11 +20,11 @@ import { Paginated, RestApiConnectorService } from 'src/app/services/connectors/ export class ReferenceManagerComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild('search') search: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; - public attackObjects: StixObject[]; // all objects in the knowledge base + public attackObjects: StixObject[] = []; // all objects in the knowledge base public references$: Observable>; public totalReferences: number = 0; public columnDefs: string[] = ['citation', 'reference', 'count', 'open']; - public referenceMap: Map = new Map(); // reference.source_name => number of objects that use the reference + public referenceMap: Map = new Map(); // reference.source_name => list of STIX objects citing the reference public loading: boolean = false; private searchSubscription: Subscription; public searchQuery: string = ""; @@ -36,9 +37,25 @@ export class ReferenceManagerComponent implements OnInit, AfterViewInit, OnDestr public snackbar: MatSnackBar) { } ngOnInit(): void { - let subscription = this.restApiConnector.getAllObjects().subscribe({ + let subscription = this.restApiConnector.getAllObjects(null, null, null, null, true, true, true).subscribe({ next: (results) => { - this.attackObjects = results as StixObject[]; + // build ID to SDO lookup + let idToObject = {}; + results.data.forEach(x => idToObject[x.stixID] = x); + + results.data.forEach(sdo => { + if (sdo.attackType == 'relationship') { + // serialize relationship source/target objects + let rel = sdo as Relationship; + if (idToObject[rel.source_ref] && idToObject[rel.target_ref]) { + let serialized = rel.serialize(); + serialized.source_object = idToObject[rel.source_ref].serialize(); + serialized.target_object = idToObject[rel.target_ref].serialize(); + rel.deserialize(serialized); + this.attackObjects.push(rel); + } + } else this.attackObjects.push(sdo); + }); }, complete: () => { this.applyControls(); @@ -85,7 +102,7 @@ export class ReferenceManagerComponent implements OnInit, AfterViewInit, OnDestr data: { mode: reference ? 'view' : 'edit', reference: reference, - count: reference ? this.referenceCount(reference.source_name): 0 + objects: reference ? this.referenceMap[reference.source_name] : [] } }); let subscription = prompt.afterClosed().subscribe({ @@ -116,13 +133,10 @@ export class ReferenceManagerComponent implements OnInit, AfterViewInit, OnDestr let uses = function(reference: ExternalReference) { // count number of objects that have this reference in its external_references list let usesReference: StixObject[] = self.attackObjects.filter(o => { - let ext_refs: any[] = o['stix'] && o['stix']['external_references'] && o['stix']['external_references'].length > 0 ? o['stix']['external_references'] : undefined; - if (!ext_refs) return false; // object does not have external references - let sources = ext_refs.map(ref => ref.source_name); - if (sources.includes(reference.source_name)) return true; - return false; + let ext_refs = o.external_references && o.external_references.list().length > 0 ? o.external_references : undefined; + return ext_refs?.hasValue(reference.source_name); }); - return usesReference.length; + return usesReference; } for (let ref of data.data) { if (!this.referenceMap.has(ref.source_name)) { @@ -140,6 +154,6 @@ export class ReferenceManagerComponent implements OnInit, AfterViewInit, OnDestr */ public referenceCount(source: string): number { if (!source) return 0; - return this.referenceMap[source]; + return this.referenceMap[source]?.length; } } diff --git a/app/src/app/views/stix/asset/asset-list/asset-list.component.html b/app/src/app/views/stix/asset/asset-list/asset-list.component.html new file mode 100644 index 000000000..30c9ab187 --- /dev/null +++ b/app/src/app/views/stix/asset/asset-list/asset-list.component.html @@ -0,0 +1,11 @@ +
+
+

assets

+
+ +
+
+ +
\ No newline at end of file diff --git a/app/src/app/views/stix/asset/asset-list/asset-list.component.scss b/app/src/app/views/stix/asset/asset-list/asset-list.component.scss new file mode 100644 index 000000000..414f10010 --- /dev/null +++ b/app/src/app/views/stix/asset/asset-list/asset-list.component.scss @@ -0,0 +1,4 @@ +.add-button { + text-align: center; + margin-bottom: 20px; +} \ No newline at end of file diff --git a/app/src/app/views/stix/asset/asset-list/asset-list.component.spec.ts b/app/src/app/views/stix/asset/asset-list/asset-list.component.spec.ts new file mode 100644 index 000000000..83bb183e5 --- /dev/null +++ b/app/src/app/views/stix/asset/asset-list/asset-list.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AssetListComponent } from './asset-list.component'; + +describe('AssetListComponent', () => { + let component: AssetListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AssetListComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AssetListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/app/src/app/views/stix/asset/asset-list/asset-list.component.ts b/app/src/app/views/stix/asset/asset-list/asset-list.component.ts new file mode 100644 index 000000000..071a11b74 --- /dev/null +++ b/app/src/app/views/stix/asset/asset-list/asset-list.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { AuthenticationService } from 'src/app/services/connectors/authentication/authentication.service'; + +@Component({ + selector: 'app-asset-list', + templateUrl: './asset-list.component.html', + styleUrls: ['./asset-list.component.scss'] +}) +export class AssetListComponent { + public get canEdit(): boolean { return this.authenticationService.canEdit(); } + + constructor(private authenticationService: AuthenticationService) { + // intentionally left blank + } +} diff --git a/app/src/app/views/stix/asset/asset-view/asset-view.component.html b/app/src/app/views/stix/asset/asset-view/asset-view.component.html new file mode 100644 index 000000000..7afb01ac8 --- /dev/null +++ b/app/src/app/views/stix/asset/asset-view/asset-view.component.html @@ -0,0 +1,148 @@ +
+
+
+ + + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+ +
+
+

Techniques Used

+
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+

References

+
+
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/app/views/stix/asset/asset-view/asset-view.component.spec.ts b/app/src/app/views/stix/asset/asset-view/asset-view.component.spec.ts new file mode 100644 index 000000000..bcb6e948a --- /dev/null +++ b/app/src/app/views/stix/asset/asset-view/asset-view.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AssetViewComponent } from './asset-view.component'; + +describe('AssetViewComponent', () => { + let component: AssetViewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AssetViewComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AssetViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/app/src/app/views/stix/asset/asset-view/asset-view.component.ts b/app/src/app/views/stix/asset/asset-view/asset-view.component.ts new file mode 100644 index 000000000..9313e8431 --- /dev/null +++ b/app/src/app/views/stix/asset/asset-view/asset-view.component.ts @@ -0,0 +1,24 @@ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Asset } from 'src/app/classes/stix'; +import { AuthenticationService } from 'src/app/services/connectors/authentication/authentication.service'; +import { RestApiConnectorService } from 'src/app/services/connectors/rest-api/rest-api-connector.service'; +import { StixViewPage } from '../../stix-view-page'; + +@Component({ + selector: 'app-asset-view', + templateUrl: './asset-view.component.html' +}) +export class AssetViewComponent extends StixViewPage implements OnInit { + @Output() public onReload = new EventEmitter(); + public get asset(): Asset { return this.config.object as Asset; } + + constructor(authenticationService: AuthenticationService, private restApiConnector: RestApiConnectorService) { + super(authenticationService) + } + + ngOnInit(): void { + if (this.asset.firstInitialized) { + this.asset.initializeWithDefaultMarkingDefinitions(this.restApiConnector); + } + } +} diff --git a/app/src/app/views/stix/campaign/campaign-list/campaign-list.component.ts b/app/src/app/views/stix/campaign/campaign-list/campaign-list.component.ts index c9df16cf8..4bcf113e3 100644 --- a/app/src/app/views/stix/campaign/campaign-list/campaign-list.component.ts +++ b/app/src/app/views/stix/campaign/campaign-list/campaign-list.component.ts @@ -9,7 +9,9 @@ import { AuthenticationService } from 'src/app/services/connectors/authenticatio export class CampaignListComponent implements OnInit { public get canEdit(): boolean { return this.authenticationService.canEdit(); } - constructor(private authenticationService: AuthenticationService) { } + constructor(private authenticationService: AuthenticationService) { + // intentionally left blank + } ngOnInit(): void { // intentionally left blank diff --git a/app/src/app/views/stix/campaign/campaign-view/campaign-view.component.html b/app/src/app/views/stix/campaign/campaign-view/campaign-view.component.html index db222734d..c7ce5f09a 100644 --- a/app/src/app/views/stix/campaign/campaign-view/campaign-view.component.html +++ b/app/src/app/views/stix/campaign/campaign-view/campaign-view.component.html @@ -116,8 +116,9 @@

Groups

@@ -144,8 +145,9 @@

Techniques Used

@@ -172,8 +174,9 @@

Software Used

diff --git a/app/src/app/views/stix/collection/collection-import/collection-import-review/collection-import-review.component.ts b/app/src/app/views/stix/collection/collection-import/collection-import-review/collection-import-review.component.ts index b30a0a66e..9dbbbf0cf 100644 --- a/app/src/app/views/stix/collection/collection-import/collection-import-review/collection-import-review.component.ts +++ b/app/src/app/views/stix/collection/collection-import/collection-import-review/collection-import-review.component.ts @@ -1,19 +1,10 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Collection, CollectionDiffCategories } from 'src/app/classes/stix/collection'; -import { Group } from 'src/app/classes/stix/group'; -import { Matrix } from 'src/app/classes/stix/matrix'; -import { Mitigation } from 'src/app/classes/stix/mitigation'; -import { Relationship } from 'src/app/classes/stix/relationship'; -import { Software } from 'src/app/classes/stix/software'; -import { Tactic } from 'src/app/classes/stix/tactic'; -import { Technique } from 'src/app/classes/stix/technique'; -import { DataSource } from 'src/app/classes/stix/data-source'; -import { DataComponent } from 'src/app/classes/stix/data-component'; +import { Asset, Campaign, DataComponent, DataSource, Group, Matrix, Mitigation, Relationship, Software, Tactic, Technique } from 'src/app/classes/stix'; import { EditorService } from 'src/app/services/editor/editor.service'; import { StixViewPage } from '../../../stix-view-page'; import { AuthenticationService } from 'src/app/services/connectors/authentication/authentication.service'; -import { Campaign } from 'src/app/classes/stix/campaign'; @Component({ selector: 'app-collection-import-review', @@ -37,7 +28,8 @@ export class CollectionImportReviewComponent extends StixViewPage implements OnI matrix: new CollectionDiffCategories(), group: new CollectionDiffCategories(), data_source: new CollectionDiffCategories(), - data_component: new CollectionDiffCategories() + data_component: new CollectionDiffCategories(), + asset: new CollectionDiffCategories() } constructor(private route: ActivatedRoute, public editor: EditorService, authenticationService: AuthenticationService) { @@ -119,6 +111,9 @@ export class CollectionImportReviewComponent extends StixViewPage implements OnI case "campaign": // campaign this.collection_import_categories.campaign[category].push(object); break; + case "x-mitre-asset": // asset + this.collection_import_categories.asset[category].push(object); + break; } } } diff --git a/app/src/app/views/stix/collection/collection-import/collection-import-workflow/collection-import.component.ts b/app/src/app/views/stix/collection/collection-import/collection-import-workflow/collection-import.component.ts index 14459e096..ba582e7e2 100644 --- a/app/src/app/views/stix/collection/collection-import/collection-import-workflow/collection-import.component.ts +++ b/app/src/app/views/stix/collection/collection-import/collection-import-workflow/collection-import.component.ts @@ -6,17 +6,8 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { MatStepper } from '@angular/material/stepper'; import { ActivatedRoute } from '@angular/router'; import { FileInputComponent } from 'ngx-material-file-input'; -import { Campaign } from 'src/app/classes/stix/campaign'; +import { Asset, Campaign, DataComponent, DataSource, Group, Matrix, Mitigation, Relationship, Software, Tactic, Technique } from 'src/app/classes/stix'; import { Collection, CollectionDiffCategories } from 'src/app/classes/stix/collection'; -import { DataComponent } from 'src/app/classes/stix/data-component'; -import { DataSource } from 'src/app/classes/stix/data-source'; -import { Group } from 'src/app/classes/stix/group'; -import { Matrix } from 'src/app/classes/stix/matrix'; -import { Mitigation } from 'src/app/classes/stix/mitigation'; -import { Relationship } from 'src/app/classes/stix/relationship'; -import { Software } from 'src/app/classes/stix/software'; -import { Tactic } from 'src/app/classes/stix/tactic'; -import { Technique } from 'src/app/classes/stix/technique'; import { ConfirmationDialogComponent } from 'src/app/components/confirmation-dialog/confirmation-dialog.component'; import { RestApiConnectorService } from 'src/app/services/connectors/rest-api/rest-api-connector.service'; import { AuthenticationService } from 'src/app/services/connectors/authentication/authentication.service'; @@ -66,6 +57,7 @@ export class CollectionImportComponent implements OnInit { group: new CollectionDiffCategories(), data_source: new CollectionDiffCategories(), data_component: new CollectionDiffCategories(), + asset: new CollectionDiffCategories() }; // list of headers that comes from mitre-generated excel files and the mapping to support collection objects @@ -105,7 +97,10 @@ export class CollectionImportComponent implements OnInit { "course-of-action": "mitigations", "x-mitre-tactic": "tactics", "x-mitre-data-source": "datasources", - "x-mitre-data-component": "datacomponents" + "x-mitre-data-component": "datacomponents", + "x-mitre-asset": "assets", + "x-mitre-matrix": "matrices", + } constructor(public route: ActivatedRoute, @@ -596,6 +591,11 @@ export class CollectionImportComponent implements OnInit { new Campaign(raw) ); break; + case 'x-mitre-asset': // asset + this.object_import_categories.asset[category].push( + new Asset(raw) + ); + break; } } // set up selection @@ -653,6 +653,9 @@ export class CollectionImportComponent implements OnInit { case 'c': // campaign object.id = 'campaign--' + uuid(); return; + case 'a': // asset + object.id = 'x-mitre-asset--' + uuid(); + return; } } // relationships don't have attack ids, so check for target and source fields here diff --git a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.html b/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.html deleted file mode 100644 index 0b5c20ee9..000000000 --- a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.html +++ /dev/null @@ -1 +0,0 @@ -

collection-imported-list works!

diff --git a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.scss b/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.spec.ts b/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.spec.ts deleted file mode 100644 index dfa897dcc..000000000 --- a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CollectionImportedListComponent } from './collection-imported-list.component'; - -describe('CollectionImportedListComponent', () => { - let component: CollectionImportedListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ CollectionImportedListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(CollectionImportedListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.ts b/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.ts deleted file mode 100644 index 3b59f5fe2..000000000 --- a/app/src/app/views/stix/collection/collection-import/collection-imported-list/collection-imported-list.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-collection-imported-list', - templateUrl: './collection-imported-list.component.html', - styleUrls: ['./collection-imported-list.component.scss'] -}) -export class CollectionImportedListComponent implements OnInit { - - constructor() { - // intentionally left blank - } - - ngOnInit(): void { - // intentionally left blank - } -} diff --git a/app/src/app/views/stix/collection/collection-index/collection-index-view/collection-index-view.component.html b/app/src/app/views/stix/collection/collection-index/collection-index-view/collection-index-view.component.html index 20453f6e3..aa75867df 100644 --- a/app/src/app/views/stix/collection/collection-index/collection-index-view/collection-index-view.component.html +++ b/app/src/app/views/stix/collection/collection-index/collection-index-view/collection-index-view.component.html @@ -24,12 +24,13 @@

{{config.index.collection_index.name}}

-
-
- {{config.index.collection_index.description}} -
- -
+
diff --git a/app/src/app/views/stix/collection/collection-view/collection-view.component.html b/app/src/app/views/stix/collection/collection-view/collection-view.component.html index 4c15cb7d4..09e604668 100644 --- a/app/src/app/views/stix/collection/collection-view/collection-view.component.html +++ b/app/src/app/views/stix/collection/collection-view/collection-view.component.html @@ -103,7 +103,7 @@

Changes in this release

diff --git a/app/src/app/views/stix/collection/collection-view/collection-view.component.ts b/app/src/app/views/stix/collection/collection-view/collection-view.component.ts index 55e2325f7..d0d6f14f2 100644 --- a/app/src/app/views/stix/collection/collection-view/collection-view.component.ts +++ b/app/src/app/views/stix/collection/collection-view/collection-view.component.ts @@ -4,16 +4,7 @@ import { forkJoin, of } from 'rxjs'; import { delay, map, switchMap, tap } from 'rxjs/operators'; import { ValidationData } from 'src/app/classes/serializable'; import { Collection, CollectionDiffCategories, VersionReference } from 'src/app/classes/stix/collection'; -import { Group } from 'src/app/classes/stix/group'; -import { Matrix } from 'src/app/classes/stix/matrix'; -import { Mitigation } from 'src/app/classes/stix/mitigation'; -import { Relationship } from 'src/app/classes/stix/relationship'; -import { Software } from 'src/app/classes/stix/software'; -import { StixObject } from 'src/app/classes/stix/stix-object'; -import { Tactic } from 'src/app/classes/stix/tactic'; -import { Technique } from 'src/app/classes/stix/technique'; -import { DataSource } from 'src/app/classes/stix/data-source'; -import { DataComponent } from 'src/app/classes/stix/data-component'; +import { Asset, Campaign, DataComponent, DataSource, Group, Matrix, Mitigation, Relationship, Software, StixObject, Tactic, Technique } from 'src/app/classes/stix'; import { StixListComponent } from 'src/app/components/stix/stix-list/stix-list.component'; import { RestApiConnectorService } from 'src/app/services/connectors/rest-api/rest-api-connector.service'; import { EditorService } from 'src/app/services/editor/editor.service'; @@ -24,7 +15,6 @@ import { logger } from "../../../../util/logger"; import { AuthenticationService } from 'src/app/services/connectors/authentication/authentication.service'; import { MatDialog } from '@angular/material/dialog'; import { CollectionUpdateDialogComponent } from 'src/app/components/collection-update-dialog/collection-update-dialog.component'; -import { Campaign } from 'src/app/classes/stix/campaign'; import { AddDialogComponent } from 'src/app/components/add-dialog/add-dialog.component'; import { SelectionModel } from '@angular/cdk/collections'; @@ -62,6 +52,7 @@ export class CollectionViewComponent extends StixViewPage implements OnInit { 'Intrusion-Set': 'group', 'Data-Source': 'data_source', 'Data-Component': 'data_component', + 'Asset': 'asset' }; // pluralize attackType for text display @@ -73,7 +64,8 @@ export class CollectionViewComponent extends StixViewPage implements OnInit { "mitigation": "mitigations", "matrix": "matrices", "data-source": "data sources", - "data-component": "data components" + "data-component": "data components", + "asset": "assets" } public get collectionDownloadURL() { @@ -96,7 +88,8 @@ export class CollectionViewComponent extends StixViewPage implements OnInit { matrix: new CollectionDiffCategories(), group: new CollectionDiffCategories(), data_source: new CollectionDiffCategories(), - data_component: new CollectionDiffCategories() + data_component: new CollectionDiffCategories(), + asset: new CollectionDiffCategories() } public collectionChanges = { @@ -109,12 +102,12 @@ export class CollectionViewComponent extends StixViewPage implements OnInit { matrix: new CollectionDiffCategories(), group: new CollectionDiffCategories(), data_source: new CollectionDiffCategories(), - data_component: new CollectionDiffCategories() + data_component: new CollectionDiffCategories(), + asset: new CollectionDiffCategories() } public collection_import_categories = []; - constructor(private route: ActivatedRoute, private router: Router, private restApiConnector: RestApiConnectorService, diff --git a/app/src/app/views/stix/data-component/data-component-view/data-component-view.component.html b/app/src/app/views/stix/data-component/data-component-view/data-component-view.component.html index 294c315e1..d831db62c 100644 --- a/app/src/app/views/stix/data-component/data-component-view/data-component-view.component.html +++ b/app/src/app/views/stix/data-component/data-component-view/data-component-view.component.html @@ -55,8 +55,9 @@

Techniques Detected

diff --git a/app/src/app/views/stix/group/group-view/group-view.component.html b/app/src/app/views/stix/group/group-view/group-view.component.html index b99bf1801..065a99b70 100644 --- a/app/src/app/views/stix/group/group-view/group-view.component.html +++ b/app/src/app/views/stix/group/group-view/group-view.component.html @@ -69,7 +69,7 @@

Campaigns

@@ -96,8 +96,9 @@

Techniques Used

@@ -124,8 +125,9 @@

Software Used

diff --git a/app/src/app/views/stix/mitigation/mitigation-view/mitigation-view.component.html b/app/src/app/views/stix/mitigation/mitigation-view/mitigation-view.component.html index 1b98aa6e1..526bf812c 100644 --- a/app/src/app/views/stix/mitigation/mitigation-view/mitigation-view.component.html +++ b/app/src/app/views/stix/mitigation/mitigation-view/mitigation-view.component.html @@ -70,8 +70,9 @@

Techniques Addressed by Mitigation

diff --git a/app/src/app/views/stix/relationship/relationship-view/relationship-view.component.ts b/app/src/app/views/stix/relationship/relationship-view/relationship-view.component.ts index 97184dda2..e5d453be3 100644 --- a/app/src/app/views/stix/relationship/relationship-view/relationship-view.component.ts +++ b/app/src/app/views/stix/relationship/relationship-view/relationship-view.component.ts @@ -46,9 +46,12 @@ export class RelationshipViewComponent extends StixViewPage implements OnInit { ngOnInit(): void { // initialize source/target types if there is a source/target object, or if there is only one possible value - if (this.relationship.source_object) this.source_type = stixTypeToAttackType[this.relationship.source_object.stix.type] + if (this.relationship.source_object) this.source_type = stixTypeToAttackType[this.relationship.source_object.stix.type]; + else if (this.config.sourceType) this.source_type = this.config.sourceType; else if (this.relationship.valid_source_types.length == 1) this.source_type = this.relationship.valid_source_types[0]; - if (this.relationship.target_object) this.target_type = stixTypeToAttackType[this.relationship.target_object.stix.type] + + if (this.relationship.target_object) this.target_type = stixTypeToAttackType[this.relationship.target_object.stix.type]; + else if (this.config.targetType) this.target_type = this.config.targetType; else if (this.relationship.valid_target_types.length == 1) this.target_type = this.relationship.valid_target_types[0]; // fetch parent of source and/or target objects diff --git a/app/src/app/views/stix/software/software-view/software-view.component.html b/app/src/app/views/stix/software/software-view/software-view.component.html index 1b2af2ac0..0b8c36066 100644 --- a/app/src/app/views/stix/software/software-view/software-view.component.html +++ b/app/src/app/views/stix/software/software-view/software-view.component.html @@ -100,8 +100,9 @@

Techniques Used

@@ -128,8 +129,9 @@

Associated Groups

@@ -156,8 +158,9 @@

Campaigns

diff --git a/app/src/app/views/stix/stix-dialog/stix-dialog.component.html b/app/src/app/views/stix/stix-dialog/stix-dialog.component.html index 0c7f5d023..04a4af277 100644 --- a/app/src/app/views/stix/stix-dialog/stix-dialog.component.html +++ b/app/src/app/views/stix/stix-dialog/stix-dialog.component.html @@ -74,6 +74,11 @@ (onOpenNotes)="openNotes()" (onClickRelationship)="changeDialogObject($event)"> + + ¯\_(ツ)_/¯ Nothing her + diff --git a/app/src/app/views/stix/stix-page/stix-page.component.ts b/app/src/app/views/stix/stix-page/stix-page.component.ts index eee18566f..c12f4ba2b 100644 --- a/app/src/app/views/stix/stix-page/stix-page.component.ts +++ b/app/src/app/views/stix/stix-page/stix-page.component.ts @@ -3,19 +3,9 @@ import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router, NavigationEnd } from '@angular/router'; import { Observable, forkJoin } from 'rxjs'; -import { Campaign } from 'src/app/classes/stix/campaign'; +import { Asset, Campaign, DataSource, Group, MarkingDefinition, Matrix, Mitigation, Note, Software, StixObject, Tactic, Technique } from 'src/app/classes/stix'; import { concatMap } from "rxjs/operators"; import { Collection } from 'src/app/classes/stix/collection'; -import { DataSource } from 'src/app/classes/stix/data-source'; -import { Group } from 'src/app/classes/stix/group'; -import { MarkingDefinition } from 'src/app/classes/stix/marking-definition'; -import { Matrix } from 'src/app/classes/stix/matrix'; -import { Mitigation } from 'src/app/classes/stix/mitigation'; -import { Note } from 'src/app/classes/stix/note'; -import { Software } from 'src/app/classes/stix/software'; -import { StixObject } from 'src/app/classes/stix/stix-object'; -import { Tactic } from 'src/app/classes/stix/tactic'; -import { Technique } from 'src/app/classes/stix/technique'; import { VersionNumber } from 'src/app/classes/version-number'; import { DeleteDialogComponent } from 'src/app/components/delete-dialog/delete-dialog.component'; import { MultipleChoiceDialogComponent } from 'src/app/components/multiple-choice-dialog/multiple-choice-dialog.component'; @@ -196,6 +186,7 @@ export class StixPageComponent implements OnInit, OnDestroy { else if (this.objectType == "collection") objects$ = this.restApiService.getCollection(objectStixID, objectModified, "latest", false, true); else if (this.objectType == "data-source") objects$ = this.restApiService.getDataSource(objectStixID, null, "latest", false, false, true); else if (this.objectType == "data-component") objects$ = this.restApiService.getDataComponent(objectStixID); + else if (this.objectType == "asset") objects$ = this.restApiService.getAsset(objectStixID); else if (this.objectType == "marking-definition") objects$ = this.restApiService.getMarkingDefinition(objectStixID); let subscription = objects$.subscribe({ next: result => { @@ -244,6 +235,7 @@ export class StixPageComponent implements OnInit, OnDestroy { case 'group': return new Group(); case 'collection': return new Collection(); case 'data-source': return new DataSource(); + case 'asset': return new Asset(); case 'marking-definition': return new MarkingDefinition(); default: return null; } diff --git a/app/src/app/views/stix/stix-view-page.ts b/app/src/app/views/stix/stix-view-page.ts index 671d927fe..e857abefc 100644 --- a/app/src/app/views/stix/stix-view-page.ts +++ b/app/src/app/views/stix/stix-view-page.ts @@ -30,7 +30,9 @@ export interface StixViewConfig { /* The object to show on the page * Note: if mode is diff, pass an array of two objects to diff */ - object: StixObject | StixObject[] + object: StixObject | StixObject[]; + sourceType?: string; // the relationship source type (only relevant when creating a new relationship) + targetType?: string; // the relationship target type (only relevant when creating a new relationship) /* if true or omitted, show relationships with the object on the page. If false, omit the relationships */ showRelationships?: boolean; /* is the current page editable? diff --git a/app/src/app/views/stix/technique/technique-view/technique-view.component.html b/app/src/app/views/stix/technique/technique-view/technique-view.component.html index d691f6425..10da17d05 100644 --- a/app/src/app/views/stix/technique/technique-view/technique-view.component.html +++ b/app/src/app/views/stix/technique/technique-view/technique-view.component.html @@ -252,7 +252,7 @@

Sub-techniques

@@ -300,8 +300,9 @@

Campaigns

@@ -327,7 +328,7 @@

Mitigations

@@ -353,7 +354,7 @@

Procedure Examples

@@ -379,7 +380,7 @@

Data Sources

@@ -396,6 +397,33 @@

Data Sources

}">
+ +
+
+

Assets

+
+
+
+
+ +
+
+
+
+ +
+
diff --git a/docs/changelog.md b/docs/changelog.md index 675ee3aac..97eaafca3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -32,17 +32,39 @@ # Changelog +## 31 October 2023 + +### ATT&CK Workbench version 2.1.0 + +#### New Features + +- Added the ability to create, view, and edit Asset objects. +- Added the ability to view and route to objects that cite a given reference from the reference dialog. See [frontend#263](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/263). + +#### Improvements + +- Navigation menu collapses under a separate hamburger menu rather than the identity icon. See [frontend#494](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/494). +- Markdown support for collection index descriptions. See [frontend#222](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/222). + +#### Fixes + +- Fixed an issue where revoking or deprecating an object would deprecate all `revoked-by` relationships with the object. See [frontend#467](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/467). +- Fixed an issue where first/last seen Campaign dates were parsed in local time, causing the dates to be displayed incorrectly in certain timezones. See [frontend#508](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/508). +- Fixed a bug where the "create a collection from group" button was being displayed on the group list page. +- Notes will only start editing when the header is clicked, enabling the contents of the note to easily be clicked or copied. See [frontend#213](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/213). + ## 21 September 2023 ### ATT&CK Workbench version 2.0.1 -#### Fixes in 2.0.1 -- Fixed a crash that would occur when retrieving recent activity for large teams. -- Fixed the incorrect path to the REST API Docker image documented in [`docker-compose.md`](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/blob/master/docs/docker-compose.md). -- Fixed an issue where the version number of an object could be saved in an invalid format. -- Fixed object name and ATT&CK ID validation to check against revoked and deprecated objects. -- Fixed an issue where the `retrieveAll()` query for Relationships and ATT&CK objects would cause a "Sort exceeded memory limit" error. See [rest-api#285](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/285). -- Updated Angular to v14. +#### Fixes + +- Fixed a crash that would occur when retrieving recent activity for large teams. +- Fixed the incorrect path to the REST API Docker image documented in [`docker-compose.md`](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/blob/master/docs/docker-compose.md). +- Fixed an issue where the version number of an object could be saved in an invalid format. +- Fixed object name and ATT&CK ID validation to check against revoked and deprecated objects. +- Fixed an issue where the `retrieveAll()` query for Relationships and ATT&CK objects would cause a "Sort exceeded memory limit" error. See [rest-api#285](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/285). +- Updated Angular to v14. ## 16 August 2023 @@ -52,45 +74,51 @@ As of v2.0.0, the [ATT&CK Workbench Collection Manager](https://github.com/cente The ATT&CK Workbench now features a persistent database for Docker installs with the use of a named volume. **This change may result in data on the current anonymous volume being lost.** The [Docker Install Update Guide](/docs/update.md) describes how to backup your existing ATT&CK Workbench data, update to v2.0.0, and restore your data after the update. -#### New Features in 2.0.0 -- Added an Admin interface for creating and managing teams. -- Added the ability to search objects by one or more users. -- Added a new user profile page where logged in users can view their recent activity across the Workbench and view/edit their display name. -- Added an option to configure an external ATT&CK Website in which to view Workbench objects, if a relevant object page exists. -- Added functionality to create a collection from a group and its related objects. -- Added button to import groups and their related objects into new or existing collections. -- Added an option to deprecate Data Component objects. See [frontend#429](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/429). -- Added Matrix view to Matrix pages similar to the full matrix on the [ATT&CK website](https://attack.mitre.org/). See [frontend#20](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/20). -- Added ability to upload csv and excel files in collection imports. -- Added support for configuring a default landing page. The desired landing page can be specified in `assets/config.json`, which Workbench will route to upon login. - -#### Improvements in 2.0.0 -- Improved error handling during collection import. -- Lists of objects can now be filtered when viewing or editing collections. See [frontend#393](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/393). -- Added a persistent database to Docker installs. -- Published pre-built Docker images to the Github Container Registry. See [frontend#250](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/250). -- Improved the collection view to display versions in the drop down rather than in the main list. - -#### Fixes in 2.0.0 -- Fixed an issue where duplicate entries would be displayed in some dropdown lists for objects in multiple domains. See [frontend#454](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/454). +#### New Features + +- Added an Admin interface for creating and managing teams. +- Added the ability to search objects by one or more users. +- Added a new user profile page where logged in users can view their recent activity across the Workbench and view/edit their display name. +- Added an option to configure an external ATT&CK Website in which to view Workbench objects, if a relevant object page exists. +- Added functionality to create a collection from a group and its related objects. +- Added button to import groups and their related objects into new or existing collections. +- Added an option to deprecate Data Component objects. See [frontend#429](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/429). +- Added Matrix view to Matrix pages similar to the full matrix on the [ATT&CK website](https://attack.mitre.org/). See [frontend#20](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/20). +- Added ability to upload csv and excel files in collection imports. +- Added support for configuring a default landing page. The desired landing page can be specified in `assets/config.json`, which Workbench will route to upon login. + +#### Improvements + +- Improved error handling during collection import. +- Lists of objects can now be filtered when viewing or editing collections. See [frontend#393](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/393). +- Added a persistent database to Docker installs. +- Published pre-built Docker images to the Github Container Registry. See [frontend#250](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/250). +- Improved the collection view to display versions in the drop down rather than in the main list. + +#### Fixes + +- Fixed an issue where duplicate entries would be displayed in some dropdown lists for objects in multiple domains. See [frontend#454](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/454). ## 21 April 2023 ### ATT&CK Workbench version 1.3.1 -#### New Features in 1.3.1 -- Added universal Notes page where users can search for notes based on title or content. Selecting a note in the table will redirect the user to the object the note was created on. See [frontend#176](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/175). +#### New Features + +- Added universal Notes page where users can search for notes based on title or content. Selecting a note in the table will redirect the user to the object the note was created on. See [frontend#176](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/175). -#### Improvements in 1.3.1 -- Added individual attribution to edits made on Note objects. -- Added the ICS Security Control mapping field to Mitigation objects. See [frontend#419](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/419). -- Updated the documentation for installing Workbench with additional certs. See [frontend#225](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/225). +#### Improvements -#### Fixes in 1.3.1 -- Fixed an issue where assigning an existing technique as a sub-technique would not create a `subtechnique-of` relationship. See [frontend#446](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/446). -- Fixed an issue causing a user's `displayName` to be removed when updating a user account on the admin page. See [frontend#449](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/449). -- Fixed an issue where updates to a user account role or status would not be reflected until the page was refreshed. See [frontend#450](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/450). -- Fixed a bug with the validation of the `source_name` field on Reference objects. +- Added individual attribution to edits made on Note objects. +- Added the ICS Security Control mapping field to Mitigation objects. See [frontend#419](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/419). +- Updated the documentation for installing Workbench with additional certs. See [frontend#225](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/225). + +#### Fixes + +- Fixed an issue where assigning an existing technique as a sub-technique would not create a `subtechnique-of` relationship. See [frontend#446](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/446). +- Fixed an issue causing a user's `displayName` to be removed when updating a user account on the admin page. See [frontend#449](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/449). +- Fixed an issue where updates to a user account role or status would not be reflected until the page was refreshed. See [frontend#450](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/450). +- Fixed a bug with the validation of the `source_name` field on Reference objects. ## 8 March 2023 @@ -98,22 +126,24 @@ The ATT&CK Workbench now features a persistent database for Docker installs with ATT&CK Workbench version 1.3.0 supports the deletion of objects. -#### New Features in 1.3.0 +#### New Features + +- Added a Reference Manager page to the Workbench to increase usability. The ability to view and edit a reference has been moved from the sidebar to the Reference Manager page. See [frontend#349](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/349). +- Added functionality to delete Relationship objects, with the exception of `subtechnique_of` relationships. See [frontend#341](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/341). +- Added functionality to delete References which are not cited by any objects. See [frontend#350](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/350). +- Added functionality to delete Mitigation, Group, Software, Data Source, Data Component, and Technique objects. Objects can only be deleted by users with `admin` roles if the object does not have any existing relationships. See [frontend#342](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/342), [frontend#346](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/346), [frontend#347](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/347), and [frontend#343](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/343). + +#### Improvements -- Added a Reference Manager page to the Workbench to increase usability. The ability to view and edit a reference has been moved from the sidebar to the Reference Manager page. See [frontend#349](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/349). -- Added functionality to delete Relationship objects, with the exception of `subtechnique_of` relationships. See [frontend#341](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/341). -- Added functionality to delete References which are not cited by any objects. See [frontend#350](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/350). -- Added functionality to delete Mitigation, Group, Software, Data Source, Data Component, and Technique objects. Objects can only be deleted by users with `admin` roles if the object does not have any existing relationships. See [frontend#342](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/342), [frontend#346](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/346), [frontend#347](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/347), and [frontend#343](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/343). +- Improved validation for the `source_name` field on Reference objects to prevent duplicated source names and issues caused by invalid characters during citation parsing. See [frontend#352](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/352). +- Enabled editing of the `domains` field for Data Sources and Data Components. See [frontend#428](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/428). -#### Improvements in 1.3.0 -- Improved validation for the `source_name` field on Reference objects to prevent duplicated source names and issues caused by invalid characters during citation parsing. See [frontend#352](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/352). -- Enabled editing of the `domains` field for Data Sources and Data Components. See [frontend#428](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/428). +#### Fixes -#### Fixes in 1.3.0 -- Fixed an issue where the "apply patches and save" button would be unavailable when updating a reference used only by Relationship objects. See [frontend#356](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/356). -- Fixed an issue where the external reference for a Data Source's ATT&CK ID pointed to an incorrect URL. See [frontend#422](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/422). -- Fixed an issue where updating a reference used by a revoked or deprecated object would throw an error and prevent the user from saving the changes to the reference. See [frontend#355](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/355). -- Fixed a bug where citations would break if the reference source name contained special characters because the query was not correctly encoded in the request. See [frontend#371](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/371). +- Fixed an issue where the "apply patches and save" button would be unavailable when updating a reference used only by Relationship objects. See [frontend#356](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/356). +- Fixed an issue where the external reference for a Data Source's ATT&CK ID pointed to an incorrect URL. See [frontend#422](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/422). +- Fixed an issue where updating a reference used by a revoked or deprecated object would throw an error and prevent the user from saving the changes to the reference. See [frontend#355](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/355). +- Fixed a bug where citations would break if the reference source name contained special characters because the query was not correctly encoded in the request. See [frontend#371](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/371). ## 25 October 2022 @@ -123,55 +153,56 @@ ATT&CK Workbench v1.2.0 supports authentication and authorization for users. The Additionally, Workbench v1.2.0 introduces the ability to create, edit, and view Campaign objects and coincides with the ATT&CK v12.0 release. Users who do not upgrade to Workbench v1.2.0 may encounter issues with the new ATT&CK data. -#### New Features in 1.2.0 - -- Added functionality to generate object ATT&CK IDs. See [frontend#114](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/114) and [frontend#300](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/300). -- Added optional namespace settings for ATT&CK IDs, so object IDs don't conflict with ATT&CK or other organizations' object IDs. These settings are automatically applied when creating a new object. See [frontend#113](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/113). -- Added parent technique field when creating a sub-technique, this will automatically create a relationship between the parent and sub-technique. See [frontend#308](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/308). -- Added support for LinkById tags, which allow users to add links from one object to another in Workbench. LinkById tags are formatted as `(LinkById: ATT&CK ID)` and are supported in `description` and `x_mitre_detection` fields. When previewing or viewing these fields, LinkById tags are detected and replaced with a link to the corresponding object's page on the Workbench. See [frontend#279](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/279). - - LinkById tags are automatically checked and updated when a referenced object's ATT&CK ID is changed. See [frontend#281](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/281). -- Added a button to object ATT&CK ID fields to copy the object's LinkById tag. See [frontend#327](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/327). -- Added `contributors` field to Technique and Tactic objects. See [frontend#325](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/325). -- Added ability to search for objects by ATT&CK ID. See [rest-api#162](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/162). -- Added a view page for References in the Reference Manager. See [frontend#304](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/304). -- Added a link to the parent technique page from the sub-technique page. See [frontend#309](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/309). -- Added a link to tactic pages from the matrix page. See [frontend#391](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/391). -- Added support for viewing techniques associated with a tactic on the tactic view page. See [frontend#390](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/390). -- Added ability to create and edit Campaign objects. See [frontend#376](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/376), [frontend#377](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/377), and [frontend#384](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/384). -- Added the ability to automatically find and add tactics related to techniques when creating or editing a collection. See [frontend#388](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/388). -- Added the option to include associated Note objects in the Collection bundle export. See [frontend#389](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/389). - -#### Improvements in 1.2.0 - -- Added authentication and authorization to the Workbench. Only authorized users can access the data of the Workbench instance. Documentation pages may be viewed by unauthenticated users. See [frontend#192](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/192). -- Added user registration and approval. Administrators can approve registrants and set their permission levels on the administrator user accounts page. See [frontend#193](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/193). -- Added user login and logout functionality. Pending users cannot log in until the Adminstrator has approved their account. See [frontend#266](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/266). -- Added support for individual attribution. If a user is logged in, the application will display the individual user who has edited an object in place of the organization-level identity. Individual attribution is not supported when the Workbench instance is set up with anonymous authentication. See [frontend#191](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/191). -- Added support for marking definitions. See [frontend#188](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/188). -- Relationships which have been deprecated are hidden in the list of relationships without requiring a page refresh. See [frontend#321](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/321). -- Changing a user's role to `admin`, `editor` or `visitor` automatically sets the user's status to `active`. A user's status is automatically set to `inactive` if their role is changed to `none`. See [frontend#318](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/318). -- Added options to the relationship edit dialog to increment the source and/or target object versions when creating a new relationship. See [frontend#307](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/307). -- The source and target objects' version numbers and last modified dates are shown alongside their names when creating a new relationship to provide more context. See [frontend#313](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/313). -- When creating a new Reference object, the `retrieved` field will default to the current date. See [frontend#305](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/305). -- The external references field at the bottom of object pages are automatically updated to reflect citation changes to the `description` and `x_mitre_detection` fields before the object is saved. See [frontend#329](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/329). -- Added validation to ensure a technique has been assigned at least one tactic. See [frontend#273](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/273). -- Removed the comma key as a keycode separator for list input fields (i.e. `contributors`, `system requirements`, `CAPEC IDs`, etc.). See [frontend#335](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/335). -- Whitespace is trimmed during the serialization of string fields for all STIX objects and external references. See [frontend#187](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/187). -- Lists of objects can now be filtered by domains and platforms. See [frontend#392](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/392). -- Added validation for Reference URLs. See [frontend#407](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/407). - - -#### Fixes in 1.2.0 -- Added missing fields from User Account objects: `created`, `modified`, and `displayName`. See [frontend#319](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/319). -- Fixed a bug where spaces would break the search in object tables and show no results. See [frontend#303](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/303). -- Fixed an issue where other external references (such as MTC IDs or CAPEC IDs) were being identified as the object's ATT&CK ID, when the object had not yet been assigned an ATT&CK ID. See [frontend#322](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/322). -- Fixed an issue where Matrix ATT&CK IDs (a.k.a. domain identifiers) were being validated and preventing users from saving. This caused issues for domains which have multiple matrices with the same domain identifier. See [frontend#315](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/315). -- Fixed the unexpected calls being made to the REST API before the user is authenticated. See [frontend#314](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/314). -- Fixed a bug where the external reference links at the bottom of object pages did not redirect to the reference's associated URL. See [frontend#306](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/306). -- Fixed a bug where the search functionality would break with special characters because the query was not correctly encoded in the request. See [frontend#332](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/332). -- Fixed an issue where Note objects were not registered as a valid class, resulting in errors when trying to retrieve all objects from the REST API. See [frontend#338](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/338). -- Fixed an issue where the Software/Group `aliases` field expected the object name as the first array entry, causing display issues in downstream applications. See [frontend#370](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/370). -- Increased request timeout in nginx. See [frontend#387](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/387). +#### New Features + +- Added functionality to generate object ATT&CK IDs. See [frontend#114](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/114) and [frontend#300](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/300). +- Added optional namespace settings for ATT&CK IDs, so object IDs don't conflict with ATT&CK or other organizations' object IDs. These settings are automatically applied when creating a new object. See [frontend#113](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/113). +- Added parent technique field when creating a sub-technique, this will automatically create a relationship between the parent and sub-technique. See [frontend#308](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/308). +- Added support for LinkById tags, which allow users to add links from one object to another in Workbench. LinkById tags are formatted as `(LinkById: ATT&CK ID)` and are supported in `description` and `x_mitre_detection` fields. When previewing or viewing these fields, LinkById tags are detected and replaced with a link to the corresponding object's page on the Workbench. See [frontend#279](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/279). + - LinkById tags are automatically checked and updated when a referenced object's ATT&CK ID is changed. See [frontend#281](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/281). +- Added a button to object ATT&CK ID fields to copy the object's LinkById tag. See [frontend#327](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/327). +- Added `contributors` field to Technique and Tactic objects. See [frontend#325](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/325). +- Added ability to search for objects by ATT&CK ID. See [rest-api#162](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/162). +- Added a view page for References in the Reference Manager. See [frontend#304](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/304). +- Added a link to the parent technique page from the sub-technique page. See [frontend#309](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/309). +- Added a link to tactic pages from the matrix page. See [frontend#391](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/391). +- Added support for viewing techniques associated with a tactic on the tactic view page. See [frontend#390](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/390). +- Added ability to create and edit Campaign objects. See [frontend#376](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/376), [frontend#377](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/377), and [frontend#384](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/384). +- Added the ability to automatically find and add tactics related to techniques when creating or editing a collection. See [frontend#388](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/388). +- Added the option to include associated Note objects in the Collection bundle export. See [frontend#389](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/389). + +#### Improvements + +- Added authentication and authorization to the Workbench. Only authorized users can access the data of the Workbench instance. Documentation pages may be viewed by unauthenticated users. See [frontend#192](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/192). +- Added user registration and approval. Administrators can approve registrants and set their permission levels on the administrator user accounts page. See [frontend#193](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/193). +- Added user login and logout functionality. Pending users cannot log in until the Adminstrator has approved their account. See [frontend#266](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/266). +- Added support for individual attribution. If a user is logged in, the application will display the individual user who has edited an object in place of the organization-level identity. Individual attribution is not supported when the Workbench instance is set up with anonymous authentication. See [frontend#191](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/191). +- Added support for marking definitions. See [frontend#188](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/188). +- Relationships which have been deprecated are hidden in the list of relationships without requiring a page refresh. See [frontend#321](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/321). +- Changing a user's role to `admin`, `editor` or `visitor` automatically sets the user's status to `active`. A user's status is automatically set to `inactive` if their role is changed to `none`. See [frontend#318](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/318). +- Added options to the relationship edit dialog to increment the source and/or target object versions when creating a new relationship. See [frontend#307](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/307). +- The source and target objects' version numbers and last modified dates are shown alongside their names when creating a new relationship to provide more context. See [frontend#313](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/313). +- When creating a new Reference object, the `retrieved` field will default to the current date. See [frontend#305](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/305). +- The external references field at the bottom of object pages are automatically updated to reflect citation changes to the `description` and `x_mitre_detection` fields before the object is saved. See [frontend#329](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/329). +- Added validation to ensure a technique has been assigned at least one tactic. See [frontend#273](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/273). +- Removed the comma key as a keycode separator for list input fields (i.e. `contributors`, `system requirements`, `CAPEC IDs`, etc.). See [frontend#335](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/335). +- Whitespace is trimmed during the serialization of string fields for all STIX objects and external references. See [frontend#187](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/187). +- Lists of objects can now be filtered by domains and platforms. See [frontend#392](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/392). +- Added validation for Reference URLs. See [frontend#407](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/407). + + +#### Fixes + +- Added missing fields from User Account objects: `created`, `modified`, and `displayName`. See [frontend#319](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/319). +- Fixed a bug where spaces would break the search in object tables and show no results. See [frontend#303](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/303). +- Fixed an issue where other external references (such as MTC IDs or CAPEC IDs) were being identified as the object's ATT&CK ID, when the object had not yet been assigned an ATT&CK ID. See [frontend#322](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/322). +- Fixed an issue where Matrix ATT&CK IDs (a.k.a. domain identifiers) were being validated and preventing users from saving. This caused issues for domains which have multiple matrices with the same domain identifier. See [frontend#315](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/315). +- Fixed the unexpected calls being made to the REST API before the user is authenticated. See [frontend#314](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/314). +- Fixed a bug where the external reference links at the bottom of object pages did not redirect to the reference's associated URL. See [frontend#306](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/306). +- Fixed a bug where the search functionality would break with special characters because the query was not correctly encoded in the request. See [frontend#332](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/332). +- Fixed an issue where Note objects were not registered as a valid class, resulting in errors when trying to retrieve all objects from the REST API. See [frontend#338](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/pull/338). +- Fixed an issue where the Software/Group `aliases` field expected the object name as the first array entry, causing display issues in downstream applications. See [frontend#370](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/370). +- Increased request timeout in nginx. See [frontend#387](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/387). ## 21 October 2021 @@ -179,164 +210,164 @@ Additionally, Workbench v1.2.0 introduces the ability to create, edit, and view ATT&CK Workbench v1.1.0 includes support for ATT&CK Spec v2.1.0 and coincides with the ATT&CK v10.0 release. Users who do not upgrade to Workbench v1.1.0 may encounter issues with the new ATT&CK data: -- If the user added the ATT&CK collection index prior to the ATT&CK v10.0 release, it may lose track of imported Enterprise collections. These collections can still be found in the "imported collections" tab of the collection manager, but won't be reflected in the collection manager. Collection subscriptions for Enterprise may also be lost. Upgrading to ATT&CK Workbench v1.1.0 will fix this issue and restore prior collection subscriptions. -- If the user imports ATT&CK v10.0 using ATT&CK Workbench 1.0.X, data sources and data components will not be imported into their local knowledge base. You can re-import the collection after upgrading Workbench to v1.1.0 to acquire the data sources and data components even if you had already imported it when running a prior version of Workbench. +- If the user added the ATT&CK collection index prior to the ATT&CK v10.0 release, it may lose track of imported Enterprise collections. These collections can still be found in the "imported collections" tab of the collection manager, but won't be reflected in the collection manager. Collection subscriptions for Enterprise may also be lost. Upgrading to ATT&CK Workbench v1.1.0 will fix this issue and restore prior collection subscriptions. +- If the user imports ATT&CK v10.0 using ATT&CK Workbench 1.0.X, data sources and data components will not be imported into their local knowledge base. You can re-import the collection after upgrading Workbench to v1.1.0 to acquire the data sources and data components even if you had already imported it when running a prior version of Workbench. ATT&CK Workbench version 1.1.0 includes improvements to how data is imported which should circumvent the above issues for future releases of ATT&CK. -#### Improvements in 1.1.0 - -- Added object type documentation on list pages. See [frontend#221](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/221). -- Added support for ATT&CK Spec v2.1.0: - - Added support for data sources and data components, and viewing/editing interfaces for these object types and their relationships with techniques. See [frontend#67](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/67), [frontend#66](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/66). - - Added support for `x_mitre_attack_spec_version` on all object types. -- Improved the flexibility and robustness of collection imports: - - Workbench will now check the ATT&CK Spec version of imported data and warn the user if the ATT&CK Spec version is unsupported (ex. if the Workbench instance is too outdated to support the data it is trying to import). The user can choose to bypass this warning. - - Workbench can now import the same collection multiple times in case objects in the initial import could not be imported due to an error. - - The user will now be provided with a downloadable list of objects that could not be saved (and the reason why) in the event of import errors. - - REST API will now log import errors for individual objects to the console when the log level is set to `verbose`. - - Frontend will now log import errors to the console when the application environment is not set to production. -- Added validation for missing ATT&CK IDs on objects that support them. The user will now be warned if they neglect to assign an ATT&CK ID to an object which supports it. When exporting a collection, the user will similarly be warned if any contained objects are missing ATT&CK IDs. See [frontend#231](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/231). -- REST API now supports setting the log level through an environment variable. See [rest-api#108](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/108). -- REST API no longer sets the `upgrade-insecure-requests` directive of the `Content-Security-Policy` header in responses. This will facilitate the deployment of ATT&CK Workbench in an internal environment without requiring the system to be configured to support HTTPS. See [rest-api#96](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/96). - -#### Fixes in 1.1.0 - -- Fixed an issue where the navigation header could be inaccessible when navigating within the application or when the page resized due to user input. -- Frontend will no longer claim objects were imported when they were actually discarded due to import errors such as spec violations. -- Imported STIX bundles will no longer require (but still allow) the `spec_version` field on the bundle itself. This was causing issues importing collections created by the Workbench. Objects within the bundle still require the `spec_version` field per the STIX 2.1 spec. See [rest-api#103](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/103). -- Fixed an issue where the REST API would save references when importing a collection bundle even though the `previewOnly` flag had been set. See [rest-api#120](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/120). +#### Improvements + +- Added object type documentation on list pages. See [frontend#221](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/221). +- Added support for ATT&CK Spec v2.1.0: + - Added support for data sources and data components, and viewing/editing interfaces for these object types and their relationships with techniques. See [frontend#67](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/67), [frontend#66](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/66). + - Added support for `x_mitre_attack_spec_version` on all object types. +- Improved the flexibility and robustness of collection imports: + - Workbench will now check the ATT&CK Spec version of imported data and warn the user if the ATT&CK Spec version is unsupported (ex. if the Workbench instance is too outdated to support the data it is trying to import). The user can choose to bypass this warning. + - Workbench can now import the same collection multiple times in case objects in the initial import could not be imported due to an error. + - The user will now be provided with a downloadable list of objects that could not be saved (and the reason why) in the event of import errors. + - REST API will now log import errors for individual objects to the console when the log level is set to `verbose`. + - Frontend will now log import errors to the console when the application environment is not set to production. +- Added validation for missing ATT&CK IDs on objects that support them. The user will now be warned if they neglect to assign an ATT&CK ID to an object which supports it. When exporting a collection, the user will similarly be warned if any contained objects are missing ATT&CK IDs. See [frontend#231](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/231). +- REST API now supports setting the log level through an environment variable. See [rest-api#108](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/108). +- REST API no longer sets the `upgrade-insecure-requests` directive of the `Content-Security-Policy` header in responses. This will facilitate the deployment of ATT&CK Workbench in an internal environment without requiring the system to be configured to support HTTPS. See [rest-api#96](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/96). + +#### Fixes + +- Fixed an issue where the navigation header could be inaccessible when navigating within the application or when the page resized due to user input. +- Frontend will no longer claim objects were imported when they were actually discarded due to import errors such as spec violations. +- Imported STIX bundles will no longer require (but still allow) the `spec_version` field on the bundle itself. This was causing issues importing collections created by the Workbench. Objects within the bundle still require the `spec_version` field per the STIX 2.1 spec. See [rest-api#103](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/103). +- Fixed an issue where the REST API would save references when importing a collection bundle even though the `previewOnly` flag had been set. See [rest-api#120](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/120). ## 20 August 2021 ### ATT&CK Workbench version 1.0.2 -#### Fixes in 1.0.2 +#### Fixes -- Error snackbars will now show appropriate messages instead of `[object ProgressEvent]` when communication with the REST API is interrupted or cannot be established. See [frontend#227](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/227). -- Fixed a bug where tactic shortnames were computed incorrectly for tactics with more than one space in the name (E.g `"Command and Control"`). See [frontend#239](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/239). - - If you have edited a technique under a tactic with more than one space in the name, remove and re-add the tactic under the technique edit interface to ensure that the tactic reference is formatted properly. - - If you have created a tactic with more than one space in the name, save a new version of the tactic and the proper shortname should be saved. You do not need to make any edits when saving the tactic page for the shortname to be fixed. +- Error snackbars will now show appropriate messages instead of `[object ProgressEvent]` when communication with the REST API is interrupted or cannot be established. See [frontend#227](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/227). +- Fixed a bug where tactic shortnames were computed incorrectly for tactics with more than one space in the name (E.g `"Command and Control"`). See [frontend#239](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/239). + - If you have edited a technique under a tactic with more than one space in the name, remove and re-add the tactic under the technique edit interface to ensure that the tactic reference is formatted properly. + - If you have created a tactic with more than one space in the name, save a new version of the tactic and the proper shortname should be saved. You do not need to make any edits when saving the tactic page for the shortname to be fixed. ## 8 July 2021 ### ATT&CK Workbench version 1.0.1 -#### Improvements in 1.0.1 +#### Improvements -- Added a system for configuring the Collection Manager with self-signed certs when using the docker setup. Documentation for this configuration will be improved in a subsequent release. +- Added a system for configuring the Collection Manager with self-signed certs when using the docker setup. Documentation for this configuration will be improved in a subsequent release. -#### Fixes in 1.0.1 +#### Fixes -- Fixed an error encountered when using the `attack-objects` API with large datasets. This error was preventing users from loading the "create a collection" page when Enterprise ATT&CK collections were imported. See [rest-api#87](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/87). +- Fixed an error encountered when using the `attack-objects` API with large datasets. This error was preventing users from loading the "create a collection" page when Enterprise ATT&CK collections were imported. See [rest-api#87](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/87). ## 21 June 2021 ### ATT&CK Workbench version 1.0.0 -#### Improvements in 1.0.0 +#### Improvements -- Performance improvements when adding, editing, and validating relationships. -- Improved error messages when importing collections that are too large or malformed. See [frontend#198](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/198). -- Improved page titles and breadcrumb on "object not found" pages. -- User can now import collections from file. See [frontend#207](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/207). -- Collection index update interval is now set in the REST API configuration instead of hardcoded in the frontend. See [frontend#200](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/200). +- Performance improvements when adding, editing, and validating relationships. +- Improved error messages when importing collections that are too large or malformed. See [frontend#198](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/198). +- Improved page titles and breadcrumb on "object not found" pages. +- User can now import collections from file. See [frontend#207](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/207). +- Collection index update interval is now set in the REST API configuration instead of hardcoded in the frontend. See [frontend#200](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/200). -#### Fixes in 1.0.0 +#### Fixes -- Fixed vertically misaligned timestamps across several UIs. -- Fixed missing timestamp on collection version lists within collection indexes. -- Fixed object status popover showing the wrong status if opened too soon after the page loads. Also improved performance of the status popover code. -- Collection import UI no longer gets stuck if it runs into a problem fetching/importing/previewing the collection. See [frontend#198](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/198) -- Object status popover now closes properly when the user starts editing the object. See [frontend#199](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/199). +- Fixed vertically misaligned timestamps across several UIs. +- Fixed missing timestamp on collection version lists within collection indexes. +- Fixed object status popover showing the wrong status if opened too soon after the page loads. Also improved performance of the status popover code. +- Collection import UI no longer gets stuck if it runs into a problem fetching/importing/previewing the collection. See [frontend#198](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/198) +- Object status popover now closes properly when the user starts editing the object. See [frontend#199](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/199). ## 7 May 2021 ### ATT&CK Workbench version 0.4.0 -#### Improvements in 0.4.0 +#### Improvements -- Added a favicon. See [frontend#137](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/137). -- Added dynamic page title to make it easier to distinguish multiple Workbench tabs in the browser. See [frontend#130](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/130). -- Added a list of recommended indexes available when adding a collection index. See [frontend#194](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/194). -- Added ability to set workflow state when objects are saved. See [frontend#184](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/184). -- Updated occurrences of "aliases" to "associated groups" or "associated software" for consistency across the application. See [frontend#176](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/176). -- Improved logging and added log level to environment configuration to suppress unnecessary logs from production deployments. See [frontend#209](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/209). -- Updated the reference editor to enforce correct formatting when creating a new reference. See [frontend#177](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/177). +- Added a favicon. See [frontend#137](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/137). +- Added dynamic page title to make it easier to distinguish multiple Workbench tabs in the browser. See [frontend#130](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/130). +- Added a list of recommended indexes available when adding a collection index. See [frontend#194](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/194). +- Added ability to set workflow state when objects are saved. See [frontend#184](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/184). +- Updated occurrences of "aliases" to "associated groups" or "associated software" for consistency across the application. See [frontend#176](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/176). +- Improved logging and added log level to environment configuration to suppress unnecessary logs from production deployments. See [frontend#209](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/209). +- Updated the reference editor to enforce correct formatting when creating a new reference. See [frontend#177](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/177). ## 21 April 2021 ### ATT&CK Workbench version 0.3.0 -#### New Features in 0.3.0 +#### New Features -- Added attribution of edits and tracking of organization identity. See [frontend#61](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/124) and [frontend#182](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/61). -- Added ability to revoke and deprecate objects. See [frontend#164](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/164). -- Added tracking of workflow state. See [frontend#3](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/3). -- Added ability to create and edit collections. See [frontend#4](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/4), [frontend#5](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/5), and [frontend#112](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/112). -- Added support and documentation for [ATT&CK Navigator](https://github.com/mitre-attack/attack-navigator) integration. See [frontend#153](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/153). -- Added support and documentation for [ATT&CK Website](https://github.com/mitre-attack/attack-website/) integration. See [frontend#152](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/152). +- Added attribution of edits and tracking of organization identity. See [frontend#61](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/124) and [frontend#182](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/61). +- Added ability to revoke and deprecate objects. See [frontend#164](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/164). +- Added tracking of workflow state. See [frontend#3](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/3). +- Added ability to create and edit collections. See [frontend#4](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/4), [frontend#5](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/5), and [frontend#112](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/112). +- Added support and documentation for [ATT&CK Navigator](https://github.com/mitre-attack/attack-navigator) integration. See [frontend#153](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/153). +- Added support and documentation for [ATT&CK Website](https://github.com/mitre-attack/attack-website/) integration. See [frontend#152](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/152). -#### Improvements in 0.3.0 +#### Improvements -- Improved display of object domains. See [frontend#166](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/166). +- Improved display of object domains. See [frontend#166](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/166). ## 19 March 2021 ### ATT&CK Workbench version 0.2.0 -#### New Features in 0.2.0 +#### New Features -- Added support for MTC and CAPEC IDs. See [frontend#124](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/124). -- Added ability to create and edit objects. See [frontend#44](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/44) and [frontend#145](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/145). - - Added ability to edit group/software aliases. See [frontend#118](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/118). - - Added ability to edit various list properties such as platforms, tactics, and domains. See [frontend#31](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/31). - - Added rich-text description editor. See [frontend#32](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/32). - - Added ability to convert techniques to sub-techniques, and vice versa. - - Added ability to edit ATT&CK IDs. See [frontend#55](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/55). - - Added validation system to warn user of malformed data. - - Added ability to reorder tactics on matrices. See [frontend#116](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/116). - - Added ability to edit object version numbers, and a UI for incrementing versions when objects are saved. See [frontend#56](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/56). -- Added ability to create and edit notes (annotations) on objects. See [frontend#59](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/59). -- Added citations/references support. - - Added automatic detection of citations on descriptions and aliases. See [frontend#115](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/115). - - Added references manager tool. See [frontend#115](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/115) and [frontend#133](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/133). +- Added support for MTC and CAPEC IDs. See [frontend#124](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/124). +- Added ability to create and edit objects. See [frontend#44](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/44) and [frontend#145](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/145). + - Added ability to edit group/software aliases. See [frontend#118](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/118). + - Added ability to edit various list properties such as platforms, tactics, and domains. See [frontend#31](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/31). + - Added rich-text description editor. See [frontend#32](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/32). + - Added ability to convert techniques to sub-techniques, and vice versa. + - Added ability to edit ATT&CK IDs. See [frontend#55](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/55). + - Added validation system to warn user of malformed data. + - Added ability to reorder tactics on matrices. See [frontend#116](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/116). + - Added ability to edit object version numbers, and a UI for incrementing versions when objects are saved. See [frontend#56](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/56). +- Added ability to create and edit notes (annotations) on objects. See [frontend#59](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/59). +- Added citations/references support. + - Added automatic detection of citations on descriptions and aliases. See [frontend#115](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/115). + - Added references manager tool. See [frontend#115](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/115) and [frontend#133](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/133). -#### Improvements in 0.2.0 +#### Improvements -- Lists of objects can now be searched and filtered. See [frontend#128](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/128) and [frontend#127](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/127). -- Lists of objects now display ATT&CK IDs when relevant. See [frontend#119](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/119). -- When viewing an object, fields which have no value(s) will now be hidden. See [frontend#120](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/120). -- Improved display of sub-techniques. See [frontend#125](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/125). -- Layout and formatting improvements to [USAGE](/docs/usage.md) document. +- Lists of objects can now be searched and filtered. See [frontend#128](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/128) and [frontend#127](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/127). +- Lists of objects now display ATT&CK IDs when relevant. See [frontend#119](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/119). +- When viewing an object, fields which have no value(s) will now be hidden. See [frontend#120](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/120). +- Improved display of sub-techniques. See [frontend#125](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/125). +- Layout and formatting improvements to [USAGE](/docs/usage.md) document. -#### Fixes in 0.2.0 +#### Fixes -- Fixed broken pagination on relationship tables. See [frontend#126](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/126). +- Fixed broken pagination on relationship tables. See [frontend#126](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/126). ## 16 February 2021 ### ATT&CK Workbench version 0.1.1 -#### New Features in 0.1.1 +#### New Features -- Added Dockerfiles, docker-compose, [and documentation on how to use them](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/tree/master/docs/docker-compose.md). See [frontend#108](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/108), [frontend#109](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/109) [rest-api#14](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/14), and [collection-manager#13](https://github.com/center-for-threat-informed-defense/attack-workbench-collection-manager/issues/13). +- Added Dockerfiles, docker-compose, [and documentation on how to use them](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/tree/master/docs/docker-compose.md). See [frontend#108](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/108), [frontend#109](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/issues/109) [rest-api#14](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/14), and [collection-manager#13](https://github.com/center-for-threat-informed-defense/attack-workbench-collection-manager/issues/13). -#### Fixes in 0.1.1 +#### Fixes -- Fixed a crash that could occur with specific queries on the REST API. See [rest-api#28](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/28). +- Fixed a crash that could occur with specific queries on the REST API. See [rest-api#28](https://github.com/center-for-threat-informed-defense/attack-workbench-rest-api/issues/28). ## 19 January 2021 ### ATT&CK Workbench version 0.1.0 -#### New Features in 0.1.0 +#### New Features -- Created object view pages for matrix, technique, tactic, mitigation, group, and software objects. -- Added the ability to browse and import collection indexes. - - Collection indexes can be imported via URL. - - A preview of the collection index is shown before confirming the import. -- Added the ability to import, view, and subscribe to collections. - - Collections listed within an index can be subscribed to, which will pull new versions when they are published. - - Collections can also be manually imported via URL. When importing, a preview of the collection and its contents is shown before confirming the import. At this step, users can preview the objects in the collection and select which ones they want to import. Changes in the import are displayed relative to the state of the knowledge base similar to the update pages on the [ATT&CK Website](https://attack.mitre.org/resources/updates/). - - An interface provides the ability to review prior imports, which provides a list of changes at the time of the import identical to that shown during the import of the collection. +- Created object view pages for matrix, technique, tactic, mitigation, group, and software objects. +- Added the ability to browse and import collection indexes. + - Collection indexes can be imported via URL. + - A preview of the collection index is shown before confirming the import. +- Added the ability to import, view, and subscribe to collections. + - Collections listed within an index can be subscribed to, which will pull new versions when they are published. + - Collections can also be manually imported via URL. When importing, a preview of the collection and its contents is shown before confirming the import. At this step, users can preview the objects in the collection and select which ones they want to import. Changes in the import are displayed relative to the state of the knowledge base similar to the update pages on the [ATT&CK Website](https://attack.mitre.org/resources/updates/). + - An interface provides the ability to review prior imports, which provides a list of changes at the time of the import identical to that shown during the import of the collection.