diff --git a/package-lock.json b/package-lock.json index 04970d0..bd5d130 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,27 +1,27 @@ { "name": "we-bstly-angular", - "version": "3.2.0", + "version": "4.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "we-bstly-angular", - "version": "3.2.0", + "version": "4.0.0", "dependencies": { - "@angular/animations": "^20.3.10", - "@angular/cdk": "^20.2.12", - "@angular/common": "^20.3.10", - "@angular/compiler": "^20.3.10", - "@angular/core": "^20.3.10", - "@angular/forms": "^20.3.10", - "@angular/material": "^20.2.12", - "@angular/material-moment-adapter": "^20.2.12", - "@angular/platform-browser": "^20.3.10", - "@angular/platform-browser-dynamic": "^20.3.10", - "@angular/router": "^20.3.10", + "@angular/animations": "^20.3.15", + "@angular/cdk": "^20.2.14", + "@angular/common": "^20.3.15", + "@angular/compiler": "^20.3.15", + "@angular/core": "^20.3.15", + "@angular/forms": "^20.3.15", + "@angular/material": "^20.2.14", + "@angular/material-moment-adapter": "^20.2.14", + "@angular/platform-browser": "^20.3.15", + "@angular/platform-browser-dynamic": "^20.3.15", + "@angular/router": "^20.3.15", "moment": "^2.30.1", "ng-qrcode": "^20.0.1", - "openpgp": "^6.2.2", + "openpgp": "^6.3.0", "qr-scanner": "^1.4.2", "rxjs": "~7.8.2", "tslib": "^2.8.1", @@ -29,15 +29,15 @@ "zone.js": "~0.15.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^20.3.9", - "@angular/cli": "^20.3.9", - "@angular/compiler-cli": "^20.3.10", - "@angular/localize": "^20.3.10", - "@types/jasmine": "^5.1.12", + "@angular-devkit/build-angular": "^20.3.13", + "@angular/cli": "^20.3.13", + "@angular/compiler-cli": "^20.3.15", + "@angular/localize": "^20.3.15", + "@types/jasmine": "^5.1.13", "@types/jasminewd2": "^2.0.13", - "@types/node": "^24.10.0", + "@types/node": "^24.10.4", "@types/openpgp": "^5.0.0", - "jasmine-core": "~5.12.1", + "jasmine-core": "~5.13.0", "jasmine-spec-reporter": "~7.0.0", "karma": "^6.4.4", "karma-chrome-launcher": "~3.2.0", @@ -273,13 +273,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2003.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.9.tgz", - "integrity": "sha512-p0GO2H8hiZjRHI9sm4tXTF3OpWaEnkqvB0GBGJfGp8RvpPfDA2t3j2NAUNtd75H+B0xdfyWLmNq9YJGpy6gznA==", + "version": "0.2003.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.13.tgz", + "integrity": "sha512-JyH6Af6PNC1IHJToColFk1RaXDU87mpPjz7M5sWDfn8bC+KBipw6dSdRkCEuw0D9HY1lZkC9EBV9k9GhpvHjCQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.9", + "@angular-devkit/core": "20.3.13", "rxjs": "7.8.2" }, "engines": { @@ -289,17 +289,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.9.tgz", - "integrity": "sha512-DCzHY+EQ98u0h1n8s9add1KVSNWco1RW/Rl8TRkEuGmRQ43MpOfTIZQvlnnqaeMcNH0fZ4zkybVBDj7korJbZg==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.13.tgz", + "integrity": "sha512-wEM5UHc37XGtH9FFVXZPwlZooccveL1VnFUbd2ArECGi4ylW+YgjeVSe0m6uJDvWOXULNVAoHlabXTXvmqV09A==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.9", - "@angular-devkit/build-webpack": "0.2003.9", - "@angular-devkit/core": "20.3.9", - "@angular/build": "20.3.9", + "@angular-devkit/architect": "0.2003.13", + "@angular-devkit/build-webpack": "0.2003.13", + "@angular-devkit/core": "20.3.13", + "@angular/build": "20.3.13", "@babel/core": "7.28.3", "@babel/generator": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", @@ -310,7 +310,7 @@ "@babel/preset-env": "7.28.3", "@babel/runtime": "7.28.3", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "20.3.9", + "@ngtools/webpack": "20.3.13", "ansi-colors": "4.1.3", "autoprefixer": "10.4.21", "babel-loader": "10.0.0", @@ -365,7 +365,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.9", + "@angular/ssr": "^20.3.13", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0 || ^30.2.0", @@ -422,13 +422,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.2003.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.9.tgz", - "integrity": "sha512-2VSKR4BR/M3g5VvAJpKdytAErPt8Oj+HzTKp+ujVeJEBs3U48bpb6mZJOMTxU1YFf2hvawDQo5aiwkondS1qLg==", + "version": "0.2003.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.13.tgz", + "integrity": "sha512-k57PdWOB64/u2MQYPylQNCKDSAHGsV0T2bvvZid2wfPJ7anvSUCU15OQMCMU1JMR0JENZEyIsLw9teShAO9w0Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.9", + "@angular-devkit/architect": "0.2003.13", "rxjs": "7.8.2" }, "engines": { @@ -442,9 +442,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.9.tgz", - "integrity": "sha512-bXsAGIUb4p60x548YmvnMvjwd3FwWz6re1uTM7dV0XH8nQn3XMhOQ3Q3sAckzJHxkDuaRhB3K/a4kupoOmVfTQ==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.13.tgz", + "integrity": "sha512-/D84T1Caxll3I2sRihPDR9UaWBhF50M+tAX15PdP6uSh/TxwAlLl9p7Rm1bD0mPjPercqaEKA+h9a9qLP16hug==", "dev": true, "license": "MIT", "dependencies": { @@ -470,13 +470,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.9.tgz", - "integrity": "sha512-oaIjAKPmHMZBTC0met5M7dbXBeZnCNwmHacT/kBHNVBAz/NI95fuAfb2P0Jxt7gWdQXejDSxWp0tL+sZIyO0xw==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.13.tgz", + "integrity": "sha512-hdMKY4rUTko8xqeWYGnwwDYDomkeOoLsYsP6SdaHWK7hpGvzWsT6Q/aIv8J8NrCYkLu+M+5nLiKOooweUZu3GQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.9", + "@angular-devkit/core": "20.3.13", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "8.2.0", @@ -489,9 +489,9 @@ } }, "node_modules/@angular/animations": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.10.tgz", - "integrity": "sha512-WSKHyF82URlAQkYGWZjozZgSYj2ClH40GDunayz6kuRewup639iH91HE8sbFfVqKgqELKIAy2E0LhmtDKnMwZA==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.15.tgz", + "integrity": "sha512-ikyKfhkxoqQA6JcBN0B9RaN6369sM1XYX81Id0lI58dmWCe7gYfrTp8ejqxxKftl514psQO3pkW8Gn1nJ131Gw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -500,18 +500,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.10" + "@angular/core": "20.3.15" } }, "node_modules/@angular/build": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.9.tgz", - "integrity": "sha512-Ulimvg6twPSCraaZECEmENfKBlD4M1yqeHlg6dCzFNM4xcwaGUnuG6O3cIQD59DaEvaG73ceM2y8ftYdxAwFow==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.13.tgz", + "integrity": "sha512-/5pM3ZS+lLkZgA+n6TMmNV8I6t9Ow1C6Vkj6bXqWeOgFDH5LwnIEZFAKzEDBkCGos0m2gPKPcREcDD5tfp9h4g==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.9", + "@angular-devkit/architect": "0.2003.13", "@babel/core": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -553,7 +553,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.9", + "@angular/ssr": "^20.3.13", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^20.0.0", @@ -603,9 +603,9 @@ } }, "node_modules/@angular/cdk": { - "version": "20.2.12", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.12.tgz", - "integrity": "sha512-hz8GtiMy3N9/e8407ZfrByHD5GEC4SkWtxyUknWuTM9P88AOie0jDZ6CfQg9gQ0OJX+6BAbJV3RpYZA1uzNUqA==", + "version": "20.2.14", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.14.tgz", + "integrity": "sha512-7bZxc01URbiPiIBWThQ69XwOxVduqEKN4PhpbF2AAyfMc/W8Hcr4VoIJOwL0O1Nkq5beS8pCAqoOeIgFyXd/kg==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", @@ -618,19 +618,19 @@ } }, "node_modules/@angular/cli": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.9.tgz", - "integrity": "sha512-4eKpRDg96B20yrKJqjA24zgxYy1RiRd70FvF/KG1hqSowsWwtzydtEJ3VM6iFWS9t1D8truuVpKjMEnn1Y274A==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.13.tgz", + "integrity": "sha512-G78I/HDJULloS2LSqfUfbmBlhDCbcWujIRWfuMnGsRf82TyGA2OEPe3IA/F8MrJfeOzPQim2fMyn24MqHL40Vg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.9", - "@angular-devkit/core": "20.3.9", - "@angular-devkit/schematics": "20.3.9", + "@angular-devkit/architect": "0.2003.13", + "@angular-devkit/core": "20.3.13", + "@angular-devkit/schematics": "20.3.13", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", - "@modelcontextprotocol/sdk": "1.17.3", - "@schematics/angular": "20.3.9", + "@modelcontextprotocol/sdk": "1.24.0", + "@schematics/angular": "20.3.13", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", "ini": "5.0.0", @@ -641,7 +641,7 @@ "resolve": "1.22.10", "semver": "7.7.2", "yargs": "18.0.0", - "zod": "3.25.76" + "zod": "4.1.13" }, "bin": { "ng": "bin/ng.js" @@ -653,9 +653,9 @@ } }, "node_modules/@angular/common": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.10.tgz", - "integrity": "sha512-12fEzvKbEqjqy1fSk9DMYlJz6dF1MJVXuC5BB+oWWJpd+2lfh4xJ62pkvvLGAICI89hfM5n9Cy5kWnXwnqPZsA==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.15.tgz", + "integrity": "sha512-k4mCXWRFiOHK3bUKfWkRQQ8KBPxW8TAJuKLYCsSHPCpMz6u0eA1F0VlrnOkZVKWPI792fOaEAWH2Y4PTaXlUHw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -664,14 +664,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.10", + "@angular/core": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.10.tgz", - "integrity": "sha512-cW939Lr8GZjPSYfbQKIDNrUaHWmn2M+zBbERThfq5skLuY+xM60bJFv4NqBekfX6YqKLCY62ilUZlnImYIXaqA==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.15.tgz", + "integrity": "sha512-lMicIAFAKZXa+BCZWs3soTjNQPZZXrF/WMVDinm8dQcggNarnDj4UmXgKSyXkkyqK5SLfnLsXVzrX6ndVT6z7A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -681,9 +681,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.10.tgz", - "integrity": "sha512-9BemvpFxA26yIVdu8ROffadMkEdlk/AQQ2Jb486w7RPkrvUQ0pbEJukhv9aryJvhbMopT66S5H/j4ipOUMzmzQ==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.15.tgz", + "integrity": "sha512-8sJoxodxsfyZ8eJ5r6Bx7BCbazXYgsZ1+dE8t5u5rTQ6jNggwNtYEzkyReoD5xvP+MMtRkos3xpwq4rtFnpI6A==", "dev": true, "license": "MIT", "dependencies": { @@ -704,7 +704,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.10", + "@angular/compiler": "20.3.15", "typescript": ">=5.8 <6.0" }, "peerDependenciesMeta": { @@ -714,9 +714,9 @@ } }, "node_modules/@angular/core": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.10.tgz", - "integrity": "sha512-g99Qe+NOVo72OLxowVF9NjCckswWYHmvO7MgeiZTDJbTjF9tXH96dMx7AWq76/GUinV10sNzDysVW16NoAbCRQ==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.15.tgz", + "integrity": "sha512-NMbX71SlTZIY9+rh/SPhRYFJU0pMJYW7z/TBD4lqiO+b0DTOIg1k7Pg9ydJGqSjFO1Z4dQaA6TteNuF99TJCNw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -725,7 +725,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.10", + "@angular/compiler": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" }, @@ -739,9 +739,9 @@ } }, "node_modules/@angular/forms": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.10.tgz", - "integrity": "sha512-9yWr51EUauTEINB745AaHwZNTHLpXIm4uxuykxzOg+g2QskEgVfH26uS8G2ogdNuwYpB8wnsXWr34qhM3qgOWw==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.15.tgz", + "integrity": "sha512-gS5hQkinq52pm/7mxz4yHPCzEcmRWjtUkOVddPH0V1BW/HMni/p4Y6k2KqKBeGb9p8S5EAp6PDxDVLOPukp3mg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -750,16 +750,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.10", - "@angular/core": "20.3.10", - "@angular/platform-browser": "20.3.10", + "@angular/common": "20.3.15", + "@angular/core": "20.3.15", + "@angular/platform-browser": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.3.10.tgz", - "integrity": "sha512-kw9yypjUdZP2uEknpNJq8Dryj4xAjwK0aIun0Wz2ZlnP8J6yH0U56qqKRQaqusKjt7fe1OFmJ2XbFEb0LrNlMw==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.3.15.tgz", + "integrity": "sha512-vJDLXzQgLE+zpzwT2n85yWmWHuk9BsnPByOHyF63K178GFs0TG49UqZOFKohGbq5Vlo1GI9NIvXkcegkoMJCMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -777,20 +777,20 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.10", - "@angular/compiler-cli": "20.3.10" + "@angular/compiler": "20.3.15", + "@angular/compiler-cli": "20.3.15" } }, "node_modules/@angular/material": { - "version": "20.2.12", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.2.12.tgz", - "integrity": "sha512-DVenIZmV87qhDBlI2Xv3Z+b+IFI1s4wcZsFrzDi1FBMxKLsltJwMHf4SAmuqY0Mm/2Vw7HEZlfE130TuqjG8Ig==", + "version": "20.2.14", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.2.14.tgz", + "integrity": "sha512-IbAgV6XLsvmHiJzxycVhcNC1PA4M30qi+ERCOir6cT333Bxm8vDV32gsOjfL52uzG5YRARroPC+8s1XqR2oxeA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "20.2.12", + "@angular/cdk": "20.2.14", "@angular/common": "^20.0.0 || ^21.0.0", "@angular/core": "^20.0.0 || ^21.0.0", "@angular/forms": "^20.0.0 || ^21.0.0", @@ -799,23 +799,23 @@ } }, "node_modules/@angular/material-moment-adapter": { - "version": "20.2.12", - "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-20.2.12.tgz", - "integrity": "sha512-IECd9uTBIzMdJu8I45q7dSo7VSSny5qZdqeq2qa8TTZh929D9zlMegI/j/4BQCBCOr+QU8PqE49jaIyr1QRsjw==", + "version": "20.2.14", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-20.2.14.tgz", + "integrity": "sha512-K9LHW3MhesJjKbVZ5O58ZBT4pLwLIf+Yyjbf1slkBll++4W1saZuPbMHnVH+DyQ52iZ0Q2TIq17MM0KG9f/WFg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "^20.0.0 || ^21.0.0", - "@angular/material": "20.2.12", + "@angular/material": "20.2.14", "moment": "^2.18.1" } }, "node_modules/@angular/platform-browser": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.10.tgz", - "integrity": "sha512-UV8CGoB5P3FmJciI3/I/n3L7C3NVgGh7bIlZ1BaB/qJDtv0Wq0rRAGwmT/Z3gwmrRtfHZWme7/CeQ2CYJmMyUQ==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.15.tgz", + "integrity": "sha512-TxRM/wTW/oGXv/3/Iohn58yWoiYXOaeEnxSasiGNS1qhbkcKtR70xzxW6NjChBUYAixz2ERkLURkpx3pI8Q6Dw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -824,9 +824,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.3.10", - "@angular/common": "20.3.10", - "@angular/core": "20.3.10" + "@angular/animations": "20.3.15", + "@angular/common": "20.3.15", + "@angular/core": "20.3.15" }, "peerDependenciesMeta": { "@angular/animations": { @@ -835,9 +835,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.10.tgz", - "integrity": "sha512-gtZPCuxfxxkMzHYBdTU9tJeTiHj+Aty3C408DJGtGU+7rZgKt9hDC14vQN9OVzB9Ly9Jwj2yr8u7AH80TxxCJw==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.15.tgz", + "integrity": "sha512-RizuRdBt0d6ongQ2y8cr8YsXFyjF8f91vFfpSNw+cFj+oiEmRC1txcWUlH5bPLD9qSDied8qazUi0Tb8VPQDGw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -846,16 +846,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.10", - "@angular/compiler": "20.3.10", - "@angular/core": "20.3.10", - "@angular/platform-browser": "20.3.10" + "@angular/common": "20.3.15", + "@angular/compiler": "20.3.15", + "@angular/core": "20.3.15", + "@angular/platform-browser": "20.3.15" } }, "node_modules/@angular/router": { - "version": "20.3.10", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.10.tgz", - "integrity": "sha512-Z03cfH1jgQ7XMDJj4R8qAGqivcvhdG3wYBwaiN1K1ODBgPhbFKNeD4stKqYp7xBNtswmM2O2jMxrL/Djwju4Gg==", + "version": "20.3.15", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.15.tgz", + "integrity": "sha512-6+qgk8swGSoAu7ISSY//GatAyCP36hEvvUgvjbZgkXLLH9yUQxdo77ij05aJ5s0OyB25q/JkqS8VTY0z1yE9NQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -864,9 +864,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.10", - "@angular/core": "20.3.10", - "@angular/platform-browser": "20.3.10", + "@angular/common": "20.3.15", + "@angular/core": "20.3.15", + "@angular/platform-browser": "20.3.15", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -2999,9 +2999,9 @@ } }, "node_modules/@inquirer/ansi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", - "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, "license": "MIT", "engines": { @@ -3009,17 +3009,17 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", - "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3056,20 +3056,20 @@ } }, "node_modules/@inquirer/core": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", - "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3084,15 +3084,15 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.21", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", - "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/external-editor": "^1.0.2", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3107,15 +3107,15 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", - "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3130,13 +3130,13 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", - "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", "dependencies": { - "chardet": "^2.1.0", + "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "engines": { @@ -3152,9 +3152,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", - "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", "engines": { @@ -3162,14 +3162,14 @@ } }, "node_modules/@inquirer/input": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", - "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3184,14 +3184,14 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", - "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3206,15 +3206,15 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", - "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3259,15 +3259,15 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", - "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3282,16 +3282,16 @@ } }, "node_modules/@inquirer/search": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", - "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3306,17 +3306,17 @@ } }, "node_modules/@inquirer/select": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", - "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3331,9 +3331,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", - "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, "license": "MIT", "engines": { @@ -3748,13 +3748,14 @@ ] }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz", - "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.24.0.tgz", + "integrity": "sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.6", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", @@ -3762,39 +3763,28 @@ "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" }, "engines": { "node": ">=18" - } - }, - "node_modules/@modelcontextprotocol/sdk/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, - "license": "MIT", - "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" + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } } }, - "node_modules/@modelcontextprotocol/sdk/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, - "license": "MIT" - }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", @@ -4203,9 +4193,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.9.tgz", - "integrity": "sha512-3h5laY9+kP7Tzociy3Lg5sMfpTTKMU+XbLQAHxnIvywHLD6r/fgVkwRli8GZf5JFMTwAkul0AQPKom9SCSWJLg==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.13.tgz", + "integrity": "sha512-7GyH55pOy8XUwo1lVWHzjZoAmSLtRT/vQbMn43x7WDl8pymAbi5zfwE/cnIX+5xgUOvkmT8sW9gJAD19rkASag==", "dev": true, "license": "MIT", "engines": { @@ -4404,9 +4394,9 @@ } }, "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -5205,14 +5195,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.9.tgz", - "integrity": "sha512-XkgTwGhhrx+MVi2+TFO32d6Es5Uezzx7Y7B/e2ulDlj08bizxQj+9wkeLt5+bR8JWODHpEntZn/Xd5WvXnODGA==", + "version": "20.3.13", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.13.tgz", + "integrity": "sha512-ETJ1budKmrkdxojo5QP6TPr6zQZYGxtWWf8NrX1cBIS851zPCmFkKyhSFLZsoksariYF/LP8ljvm8tlcIzt/XA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.9", - "@angular-devkit/schematics": "20.3.9", + "@angular-devkit/core": "20.3.13", + "@angular-devkit/schematics": "20.3.13", "jsonc-parser": "3.3.1" }, "engines": { @@ -5309,9 +5299,9 @@ "license": "MIT" }, "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, "license": "MIT" }, @@ -5556,9 +5546,9 @@ } }, "node_modules/@types/jasmine": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.12.tgz", - "integrity": "sha512-1BzPxNsFDLDfj9InVR3IeY0ZVf4o9XV+4mDqoCfyPkbsA7dYyKAPAb2co6wLFlHcvxPlt1wShm7zQdV7uTfLGA==", + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.13.tgz", + "integrity": "sha512-MYCcDkruFc92LeYZux5BC0dmqo2jk+M5UIZ4/oFnAPCXN9mCcQhLyj7F3/Za7rocVyt5YRr1MmqJqFlvQ9LVcg==", "dev": true, "license": "MIT" }, @@ -5587,9 +5577,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", - "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "version": "24.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", + "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "dev": true, "license": "MIT", "dependencies": { @@ -6316,9 +6306,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.25", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz", - "integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==", + "version": "2.9.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.10.tgz", + "integrity": "sha512-2VIKvDx8Z1a9rTB2eCkdPE5nSe28XnA+qivGnWHoB40hMMt/h1hSz0960Zqsn6ZyxWXUie0EBdElKv8may20AA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6376,37 +6366,28 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/bonjour-service": { @@ -6452,9 +6433,9 @@ } }, "node_modules/browserslist": { - "version": "4.27.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", - "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -6472,11 +6453,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.19", - "caniuse-lite": "^1.0.30001751", - "electron-to-chromium": "^1.5.238", - "node-releases": "^2.0.26", - "update-browserslist-db": "^1.1.4" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -6573,9 +6554,9 @@ } }, "node_modules/cacache/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -6694,9 +6675,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001754", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz", - "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==", + "version": "1.0.30001760", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", + "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", "dev": true, "funding": [ { @@ -7091,16 +7072,17 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -7178,13 +7160,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", - "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", + "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.26.3" + "browserslist": "^4.28.0" }, "funding": { "type": "opencollective", @@ -7385,9 +7367,9 @@ } }, "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "dev": true, "license": "MIT", "dependencies": { @@ -7402,9 +7384,9 @@ } }, "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "dev": true, "license": "MIT", "engines": { @@ -7604,9 +7586,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.249", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.249.tgz", - "integrity": "sha512-5vcfL3BBe++qZ5kuFhD/p8WOM1N9m3nwvJPULJx+4xf2usSlZFJ0qoNYO2fOX4hi3ocuDcmDobtA+5SFr4OmBg==", + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "dev": true, "license": "ISC" }, @@ -7759,9 +7741,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8106,19 +8088,20 @@ "license": "Apache-2.0" }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -8208,13 +8191,6 @@ "node": ">= 6" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -8287,9 +8263,9 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { @@ -8301,7 +8277,11 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/find-up": { @@ -8693,11 +8673,11 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } @@ -8803,30 +8783,24 @@ "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "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, - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-parser-js": { @@ -8908,9 +8882,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "dev": true, "license": "MIT", "dependencies": { @@ -9044,9 +9018,9 @@ } }, "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, "license": "MIT", "engines": { @@ -9476,9 +9450,9 @@ } }, "node_modules/jasmine-core": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.12.1.tgz", - "integrity": "sha512-P/UbRZ0LKwXe7wEpwDheuhunPwITn4oPALhrJEQJo6756EwNGnsK/TSQrWojBB4cQDQ+VaxWYws9tFNDuiMh2Q==", + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.13.0.tgz", + "integrity": "sha512-vsYjfh7lyqvZX5QgqKc4YH8phs7g96Z8bsdIFNEU3VqXhlHaq+vov/Fgn/sr6MiUczdZkyXRC3TX369Ll4Nzbw==", "dev": true, "license": "MIT" }, @@ -9533,6 +9507,16 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9541,9 +9525,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -9774,24 +9758,24 @@ } }, "node_modules/karma/node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "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.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -9941,33 +9925,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/karma/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/karma/node_modules/raw-body": { - "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==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -10566,9 +10534,9 @@ } }, "node_modules/memfs": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.50.0.tgz", - "integrity": "sha512-N0LUYQMUA1yS5tJKmMtU9yprPm6ZIg24yr/OVv/7t6q0kKDIho4cBbXRi1XKttUmNYDYgF/q45qrKE/UhGO0CA==", + "version": "4.51.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.51.1.tgz", + "integrity": "sha512-Eyt3XrufitN2ZL9c/uIRMyDwXanLI88h/L3MoWqNY747ha3dMR9dWqp8cRT5ntjZ0U1TNuq4U91ZXK0sMBjYOQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -10675,16 +10643,20 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-function": { @@ -10944,9 +10916,9 @@ "license": "MIT" }, "node_modules/msgpackr": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.5.tgz", - "integrity": "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==", + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.8.tgz", + "integrity": "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==", "dev": true, "license": "MIT", "optional": true, @@ -11092,9 +11064,9 @@ "optional": true }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { @@ -11315,9 +11287,9 @@ } }, "node_modules/npm-packlist/node_modules/proc-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", - "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "dev": true, "license": "ISC", "engines": { @@ -11544,9 +11516,9 @@ } }, "node_modules/openpgp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-6.2.2.tgz", - "integrity": "sha512-P/dyEqQ3gfwOCo+xsqffzXjmUhGn4AZTOJ1LCcN21S23vAk+EAvMJOQTsb/C8krL6GjOSBxqGYckhik7+hneNw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-6.3.0.tgz", + "integrity": "sha512-pLzCU8IgyKXPSO11eeharQkQ4GzOKNWhXq79pQarIRZEMt1/ssyr+MIuWBv1mNoenJLg04gvPx+fi4gcKZ4bag==", "license": "LGPL-3.0+", "engines": { "node": ">= 18.0.0" @@ -11617,9 +11589,9 @@ } }, "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { @@ -11980,9 +11952,9 @@ } }, "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "dev": true, "license": "MIT", "engines": { @@ -12130,9 +12102,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -12458,16 +12430,16 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" @@ -13035,26 +13007,30 @@ } }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/serialize-javascript": { @@ -13201,9 +13177,9 @@ } }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, "license": "MIT", "dependencies": { @@ -13214,6 +13190,10 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/set-blocking": { @@ -14086,9 +14066,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -14369,9 +14349,9 @@ } }, "node_modules/tslint/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -14617,9 +14597,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -14647,26 +14627,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -15041,24 +15001,24 @@ } }, "node_modules/webpack-dev-server/node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "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.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -15103,20 +15063,10 @@ "node": ">= 0.6" } }, - "node_modules/webpack-dev-server/node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/webpack-dev-server/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "dev": true, "license": "MIT" }, @@ -15138,40 +15088,40 @@ "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -15185,18 +15135,18 @@ } }, "node_modules/webpack-dev-server/node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -15265,9 +15215,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", "dev": true, "license": "MIT", "engines": { @@ -15360,33 +15310,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/webpack-dev-server/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/webpack-dev-server/node_modules/raw-body": { - "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==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -15406,66 +15340,46 @@ } }, "node_modules/webpack-dev-server/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/webpack-dev-server/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/webpack-dev-server/node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "dev": true, "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.19.0" + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/webpack-dev-server/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, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/webpack-dev-server/node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -15929,9 +15843,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "dev": true, "license": "MIT", "funding": { @@ -15939,13 +15853,13 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.24.6", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", - "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", + "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", "dev": true, "license": "ISC", "peerDependencies": { - "zod": "^3.24.1" + "zod": "^3.25 || ^4" } }, "node_modules/zone.js": { diff --git a/package.json b/package.json index aff7e7e..176d0f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "we-bstly-angular", - "version": "3.5.1", + "version": "4.0.0", "scripts": { "ng": "ng", "start": "ng serve", @@ -11,20 +11,20 @@ }, "private": true, "dependencies": { - "@angular/animations": "^20.3.10", - "@angular/cdk": "^20.2.12", - "@angular/common": "^20.3.10", - "@angular/compiler": "^20.3.10", - "@angular/core": "^20.3.10", - "@angular/forms": "^20.3.10", - "@angular/material": "^20.2.12", - "@angular/material-moment-adapter": "^20.2.12", - "@angular/platform-browser": "^20.3.10", - "@angular/platform-browser-dynamic": "^20.3.10", - "@angular/router": "^20.3.10", + "@angular/animations": "^20.3.15", + "@angular/cdk": "^20.2.14", + "@angular/common": "^20.3.15", + "@angular/compiler": "^20.3.15", + "@angular/core": "^20.3.15", + "@angular/forms": "^20.3.15", + "@angular/material": "^20.2.14", + "@angular/material-moment-adapter": "^20.2.14", + "@angular/platform-browser": "^20.3.15", + "@angular/platform-browser-dynamic": "^20.3.15", + "@angular/router": "^20.3.15", "moment": "^2.30.1", "ng-qrcode": "^20.0.1", - "openpgp": "^6.2.2", + "openpgp": "^6.3.0", "qr-scanner": "^1.4.2", "rxjs": "~7.8.2", "tslib": "^2.8.1", @@ -32,15 +32,15 @@ "zone.js": "~0.15.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^20.3.9", - "@angular/cli": "^20.3.9", - "@angular/compiler-cli": "^20.3.10", - "@angular/localize": "^20.3.10", - "@types/jasmine": "^5.1.12", + "@angular-devkit/build-angular": "^20.3.13", + "@angular/cli": "^20.3.13", + "@angular/compiler-cli": "^20.3.15", + "@angular/localize": "^20.3.15", + "@types/jasmine": "^5.1.13", "@types/jasminewd2": "^2.0.13", - "@types/node": "^24.10.0", + "@types/node": "^24.10.4", "@types/openpgp": "^5.0.0", - "jasmine-core": "~5.12.1", + "jasmine-core": "~5.13.0", "jasmine-spec-reporter": "~7.0.0", "karma": "^6.4.4", "karma-chrome-launcher": "~3.2.0", diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index e1a6ff3..57bc742 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -64,7 +64,7 @@ const routes: Routes = [ { path: 'partey/manage', component: ParteyComponent, canActivate: [AuthenticatedGuard] }, { path: '', component: MainComponent, children: [ - { path: '', redirectTo: "/services", pathMatch: 'full' }, + { path: '', redirectTo: "/account/info", pathMatch: 'full' }, { path: 'login', component: FormLoginComponent, canActivate: [AnonymousGuard] }, { path: 'login/2fa', component: FormLogin2FAComponent, canActivate: [AnonymousGuard] }, { path: 'login/oidc', component: FormLoginOidcComponent, canActivate: [AuthenticatedGuard] }, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e745723..3943a49 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,7 +28,7 @@ import { ServicesGridComponent } from './ui/servicesgrid/servicesgrid.component' import { ServicesTableComponent } from './ui/servicestable/servicestable.component'; import { ProfileFieldPgpBlob } from './ui/profilefields/binary/pgp/profilefield.pgp-blob'; import { QuotasComponent } from './ui/quotas/quotas.component'; -import { SecurityComponent, SecurityTotpDialog } from './pages/account/security/security.component'; +import { SecurityComponent, SecurityKeyDialog, SecurityTotpDialog } from './pages/account/security/security.component'; import { VoucherComponent } from './pages/account/voucher/voucher.component'; import { VoucherDialog } from './pages/account/voucher/voucher.component'; import { InfoComponent } from './pages/account/info/info.component'; @@ -140,6 +140,7 @@ export class XhrInterceptor implements HttpInterceptor { QuotasComponent, SecurityComponent, SecurityTotpDialog, + SecurityKeyDialog, VoucherComponent, VoucherDialog, InfoComponent, diff --git a/src/app/pages/account/security/security-key.dialog.html b/src/app/pages/account/security/security-key.dialog.html new file mode 100644 index 0000000..89ab949 --- /dev/null +++ b/src/app/pages/account/security/security-key.dialog.html @@ -0,0 +1,16 @@ +

+ {{'security.webauthn.create' | i18n}} +

+
+

+ {{'security.webauthn.dialog.info' | i18n}} +

+ + {{'security.webauthn.nickname' | i18n}} + + +
+
+ + +
\ No newline at end of file diff --git a/src/app/pages/account/security/security.component.html b/src/app/pages/account/security/security.component.html index c98b29c..48aa39f 100644 --- a/src/app/pages/account/security/security.component.html +++ b/src/app/pages/account/security/security.component.html @@ -4,30 +4,30 @@

{{'password.change' | i18n}}

{{'password.current' | i18n}} - + @for (error of passwordForm.get('oldPassword').errors | keyvalue; track error) { - - {{error.key}} - + + {{error.key}} + } @if (success) { - - {{'password.changed' | i18n}} - + + {{'password.changed' | i18n}} + } {{'password' | i18n}} - + @for (error of passwordForm.get('password').errors | keyvalue; track error) { - - {{error.key}} - + + {{error.key}} + } {{'password.confirm' | i18n}} - + {{'password.not-match' | i18n}} @@ -35,12 +35,12 @@ @if (working) { - + } @if (!working) { - + } @@ -53,34 +53,34 @@

{{'security.status.hint' | i18n}}

{{'security.status' | i18n}} - + @for (status of statuses; track status) { - - {{'security.status.' + status | i18n}} - + + {{'security.status.' + status | i18n}} + } @if (successStatus) { - - {{'security.status.success' | i18n}} - + + {{'security.status.success' | i18n}} + } - {{'security.status.' + model.status + '.hint' | i18n}} + {{'security.status.' + statusSelect.value + '.hint' | i18n}} @if (working) { - + } @if (!working) { - + } - + contact_support @@ -94,11 +94,11 @@ @if (!totp) { - {{'security.2fa.totp.create' | + {{'security.2fa.totp.create' | i18n}} } @if (totp) { - {{'security.2fa.totp.remove' | + {{'security.2fa.totp.remove' | i18n}} } @@ -108,4 +108,53 @@ contact_support - \ No newline at end of file + + +@if (webAuthnSupported) { + + +

{{'security.webauthn' | i18n}}

+

{{'security.webauthn.info' | i18n}}

+ + @if (webAuthnCredentials.length > 0) { +

{{'security.webauthn.registered' | i18n}}

+ + @for (credential of webAuthnCredentials; track credential.id) { + + + {{ credential.nickname | i18n }} + + + {{ credential.createdAt | datef }} + +
+ + {{'security.webauthn.usage' | i18n}} + + {{'security.webauthn.usage.none' | i18n}} + {{'security.webauthn.usage.two-fa' | i18n}} + {{'security.webauthn.usage.login' | i18n}} + + + +
+
+ } +
+ } +
+ + {{'security.webauthn.create' | i18n}} + + + + contact_support + + +
+} \ No newline at end of file diff --git a/src/app/pages/account/security/security.component.ts b/src/app/pages/account/security/security.component.ts index 6bef044..ac86da5 100644 --- a/src/app/pages/account/security/security.component.ts +++ b/src/app/pages/account/security/security.component.ts @@ -2,8 +2,10 @@ import { Component, Inject, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, NgForm, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { ConfirmDialog } from 'src/app/ui/confirm/confirm.component'; import { Auth2FAService } from './../../../services/auth.2fa.service'; import { UserService } from './../../../services/user.service'; +import { WebAuthnService } from './../../../services/webauthn.service'; import { MatchingValidator } from './../../../utils/matching.validator'; @Component({ @@ -14,12 +16,13 @@ import { MatchingValidator } from './../../../utils/matching.validator'; }) export class SecurityComponent implements OnInit { - - model: any = {}; public working: boolean; public success: boolean; public successStatus: boolean; public totp: boolean = false; + public webauthn: boolean = false; + public webAuthnSupported: boolean = false; + public webAuthnCredentials: any[] = []; statuses = ["NORMAL", "SLEEP", "PURGE"]; @@ -31,6 +34,7 @@ export class SecurityComponent implements OnInit { private formBuilder: FormBuilder, private userService: UserService, private auth2FAService: Auth2FAService, + private webAuthnService: WebAuthnService, public dialog: MatDialog) { } ngOnInit(): void { @@ -49,7 +53,7 @@ export class SecurityComponent implements OnInit { this.userService.get().subscribe({ next: (response: any) => { - this.model.status = response.status; + this.statusForm.get('status').setValue(response.status); }, error: (error) => { } }) @@ -61,13 +65,38 @@ export class SecurityComponent implements OnInit { this.totp = false; } }) + + this.loadWebAuthnCredentials(); + + this.webAuthnSupported = this.webAuthnService.isSupported(); + } + + loadWebAuthnCredentials() { + if (this.webAuthnService.isSupported()) { + this.webAuthnService.getCredentials().subscribe({ + next: (credentials) => { + this.webAuthnCredentials = credentials; + this.webauthn = credentials.length > 0; + }, + error: (error) => { + this.webAuthnCredentials = []; + this.webauthn = false; + } + }); + } } changePassword() { if (this.passwordForm.valid && !this.working) { this.working = true; - this.userService.password(this.model).subscribe({ + const model = { + old: this.passwordForm.get('oldPassword').value, + password: this.passwordForm.get('password').value, + password2: this.passwordForm.get('password2').value + } + + this.userService.password(model).subscribe({ next: (result: any) => { this.passwordFormDirective.resetForm(); this.success = true; @@ -96,7 +125,7 @@ export class SecurityComponent implements OnInit { if (this.statusForm.valid && !this.working) { this.working = true; - this.userService.update({ status: this.model.status }).subscribe({ + this.userService.update({ status: this.statusForm.get('status').value }).subscribe({ next: (result: any) => { this.successStatus = true; this.working = false; @@ -140,21 +169,87 @@ export class SecurityComponent implements OnInit { enableTotp() { - const dialogRef = this.dialog.open(SecurityTotpDialog, { + this.dialog.open(SecurityTotpDialog, { closeOnNavigation: false, - disableClose: true, - data: {} + disableClose: true }); } removeTotp() { - this.auth2FAService.remove('totp').subscribe({ - next: (result: any) => { - this.totp = false; + const dialogRef = this.dialog.open(ConfirmDialog, { + data: { + 'label': 'security.2fa.totp.confirmRemove' } }) + + dialogRef.afterClosed().subscribe({ + next: (result) => { + if (result) { + this.auth2FAService.remove('totp').subscribe({ + next: () => { + this.totp = false; + } + }) + } + } + }); } + createWebAuthn() { + const dialogRef = this.dialog.open(SecurityKeyDialog, { + closeOnNavigation: false, + disableClose: true + }); + + dialogRef.afterClosed().subscribe(nickname => { + if (!!nickname) { + this.webAuthnService.register(nickname).subscribe({ + next: () => { + this.loadWebAuthnCredentials(); + }, + error: (error) => { + console.error('Webauthn registration failed:', error); + } + }); + } + }); + } + + removeWebAuthnCredential(credentialId: number, nickname: string) { + const dialogRef = this.dialog.open(ConfirmDialog, { + data: { + 'label': 'security.webauthn.confirmRemove', + 'args': [nickname] + } + }) + + dialogRef.afterClosed().subscribe({ + next: (result) => { + if (result) { + this.webAuthnService.deleteCredential(credentialId).subscribe({ + next: () => { + this.loadWebAuthnCredentials(); + }, + error: (error) => { + console.error('Failed to remove credential:', error); + } + }); + } + } + }); + + } + + updateCredentialUsage(credentialId: number, usage: string) { + this.webAuthnService.updateUsage(credentialId, usage).subscribe({ + next: () => { + this.loadWebAuthnCredentials(); + }, + error: (error) => { + console.error('Failed to update credential usage:', error); + } + }); + } } @@ -176,4 +271,22 @@ export class SecurityTotpDialog { ngOnInit(): void { this.code = new FormControl('', [Validators.required, Validators.pattern("[0-9]{6}")]); } -} \ No newline at end of file +} + +@Component({ + standalone: false, + selector: 'app-security-key-dialog', + templateUrl: 'security-key.dialog.html', + styleUrls: ['./security.component.scss'] +}) +export class SecurityKeyDialog implements OnInit { + + nickname: FormControl; + + constructor(public dialogRef: MatDialogRef) { } + + ngOnInit(): void { + this.nickname = new FormControl('', []); + } +} + diff --git a/src/app/pages/account/voucher/voucher.component.ts b/src/app/pages/account/voucher/voucher.component.ts index 814918a..0e18f4a 100644 --- a/src/app/pages/account/voucher/voucher.component.ts +++ b/src/app/pages/account/voucher/voucher.component.ts @@ -32,18 +32,21 @@ export class VoucherComponent implements OnInit { } create(name: string) { - this.voucherService.create(name).toPromise().then(data => { - this.model.type = name; - this.model.code = data; - this.vouchers.push(this.model); - this.voucherSource.data = this.vouchers; - const dialogRef = this.dialog.open(VoucherDialog, { - closeOnNavigation: false, - disableClose: true, - data: this.model - }); - }, error => { + this.voucherService.create(name).subscribe({ + next: (data) => { + this.model.type = name; + this.model.code = data; + this.vouchers.push(this.model); + this.voucherSource.data = this.vouchers; + const dialogRef = this.dialog.open(VoucherDialog, { + closeOnNavigation: false, + disableClose: true, + data: this.model + }) + }, error: () => { + + } }) } diff --git a/src/app/pages/admin/users/user.edit.ts b/src/app/pages/admin/users/user.edit.ts index 5dcba7b..bfd5588 100644 --- a/src/app/pages/admin/users/user.edit.ts +++ b/src/app/pages/admin/users/user.edit.ts @@ -61,7 +61,7 @@ export class AdminUserEditDialog implements OnInit { const userData = { ...this.user, - username: this.form.value.username, + username: this.form.value.username || this.user.username, disabled: this.form.value.disabled, locked: this.form.value.locked, status: this.form.value.status diff --git a/src/app/pages/form-login-2fa/form-login-2fa.component.html b/src/app/pages/form-login-2fa/form-login-2fa.component.html index 1c4b722..33d4654 100644 --- a/src/app/pages/form-login-2fa/form-login-2fa.component.html +++ b/src/app/pages/form-login-2fa/form-login-2fa.component.html @@ -1,50 +1,52 @@ -
+

{{'security.2fa.external' | i18n}}open_in_new - -

- @if (loginInvalid) { + + + @if (loginInvalid) { {{'security.2fa.invalid' | i18n}} - } - - - {{'security.2fa.provider' | i18n}} - - @for (provider of providers; track provider) { + } + + + {{'security.2fa.provider' | i18n}} + + @for (provider of providers; track provider) { {{'security.2fa.' + provider.id | i18n}} - } - - - @if (selectedProvider && selectedProvider.request) { - {{'security.2fa.' + selectedProvider.id + - '.request' - | i18n}} - } - - {{'security.2fa.code' | i18n}} - - - {{'security.2fa.missing' | i18n}} - - - @if (keep) { - + } + + + + {{'security.2fa.code' | i18n}} + + + {{'security.2fa.missing' | i18n}} + + + @if (keep) { + {{'security.2fa.keepSession' | i18n}} - } - -
- - {{'security.2fa.login' | i18n}} - open_in_new - - -
+ } + + + + @if (webAuthn) { + {{'security.2fa.' + selectedProvider.id + + '.request' + | i18n}} + } + @if (!webAuthn) { + {{'security.2fa.login' | i18n}} + open_in_new + + } + +
\ No newline at end of file diff --git a/src/app/pages/form-login-2fa/form-login-2fa.component.scss b/src/app/pages/form-login-2fa/form-login-2fa.component.scss index 4edbfb3..d3f2850 100644 --- a/src/app/pages/form-login-2fa/form-login-2fa.component.scss +++ b/src/app/pages/form-login-2fa/form-login-2fa.component.scss @@ -1,7 +1,11 @@ mat-form-field { display: block; + + &.hidden { + display: none; + } } input#keep { display: none; -} +} \ No newline at end of file diff --git a/src/app/pages/form-login-2fa/form-login-2fa.component.ts b/src/app/pages/form-login-2fa/form-login-2fa.component.ts index a23e298..b9f2b26 100644 --- a/src/app/pages/form-login-2fa/form-login-2fa.component.ts +++ b/src/app/pages/form-login-2fa/form-login-2fa.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { environment } from '../../../environments/environment'; import { Auth2FAService } from '../../services/auth.2fa.service'; +import { WebAuthnService } from '../../services/webauthn.service'; @Component({ standalone: false, @@ -18,11 +19,13 @@ export class FormLogin2FAComponent implements OnInit { apiUrl = environment.apiUrl; selectedProvider = { id: "", request: false }; providers = []; + webAuthn: boolean = false; constructor( private router: Router, private route: ActivatedRoute, - private auth2FAService: Auth2FAService) { } + private auth2FAService: Auth2FAService, + private webAuthnService: WebAuthnService) { } async ngOnInit() { this.route.queryParams.subscribe({ @@ -43,15 +46,42 @@ export class FormLogin2FAComponent implements OnInit { this.providers = providers; if (this.providers[0]) { this.selectedProvider = this.providers[0]; + this.changeProvider(); } } }) } + changeProvider() { + this.webAuthn = false; + if (!!this.selectedProvider && this.selectedProvider.id.startsWith('webauthn')) { + this.webAuthn = true; + } + } - request() { - + async webAuthnRequest() { + if (!this.selectedProvider || !this.selectedProvider.request || !this.selectedProvider.id.startsWith('webauthn')) { + return; + } + this.webAuthnService.requestAuthentication(this.selectedProvider.id).subscribe({ + next: async (response) => { + const requestJson = typeof response === 'string' ? JSON.parse(response) : response; + const assertionResponse = await this.webAuthnService.authenticateWithOptions(requestJson); + const codeInput = document.getElementById('code') as HTMLInputElement; + if (codeInput) { + codeInput.value = assertionResponse; + const form2FA = document.getElementById('form2FA') as HTMLFormElement; + if (form2FA) { + form2FA.submit(); + } + } + }, + error: (error) => { + console.error('WebAuthn authentication failed:', error); + console.error('Error details:', error); + } + }); } diff --git a/src/app/pages/form-login/form-login.component.html b/src/app/pages/form-login/form-login.component.html index d391931..e590a02 100644 --- a/src/app/pages/form-login/form-login.component.html +++ b/src/app/pages/form-login/form-login.component.html @@ -2,38 +2,47 @@

{{'login.external' | i18n}}open_in_new - -

- @if (loginInvalid) { + + + @if (loginInvalid) { {{'login.invalid' | i18n}} - } - - {{'username' | i18n}} - - - {{'username.missing' | i18n}} - - - - {{'password' | i18n}} - - - {{'password.invalid.hint' | i18n}} - - - - {{'login.keepSession' | i18n}} - - -
- - - {{'password.forgot' | i18n}} - -
+ } + + {{'username' | i18n}} + + + {{'username.missing' | i18n}} + + + + {{'password' | i18n}} + + + {{'password.invalid.hint' | i18n}} + + + + {{'login.keepSession' | i18n}} + + + + + + {{'password.forgot' | i18n}} + + + {{'login.webauthn' | i18n}} lock + + + + +
+ +
\ No newline at end of file diff --git a/src/app/pages/form-login/form-login.component.ts b/src/app/pages/form-login/form-login.component.ts index 0a28b86..fe1c7b4 100644 --- a/src/app/pages/form-login/form-login.component.ts +++ b/src/app/pages/form-login/form-login.component.ts @@ -1,6 +1,7 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; +import { WebAuthnService } from 'src/app/services/webauthn.service'; import { environment } from '../../../environments/environment'; @Component({ @@ -18,7 +19,9 @@ export class FormLoginComponent implements OnInit { constructor( private router: Router, - private route: ActivatedRoute) { } + private route: ActivatedRoute, + private webAuthnService: WebAuthnService + ) { } async ngOnInit() { this.route.queryParams.subscribe({ @@ -42,5 +45,21 @@ export class FormLoginComponent implements OnInit { } } + webAuthnLogin() { + this.webAuthnService.loginStart().subscribe({ + next: async (result: any) => { + const assertionJson = await this.webAuthnService.authenticateWithOptions(result); + const webAuthnForm = document.getElementById('webAuthnForm') as HTMLFormElement; + const assertionJsonInput = document.getElementById('assertionJson') as HTMLInputElement; + + if (webAuthnForm && assertionJsonInput) { + assertionJsonInput.value = assertionJson; + webAuthnForm.submit(); + } + } + }) + } } + + diff --git a/src/app/services/webauthn.service.ts b/src/app/services/webauthn.service.ts new file mode 100644 index 0000000..0e338ec --- /dev/null +++ b/src/app/services/webauthn.service.ts @@ -0,0 +1,235 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, switchMap } from 'rxjs'; + +import { environment } from '../../environments/environment'; + +/** + * Base64URL encoding/decoding helper + */ +function base64UrlEncode(buffer: ArrayBuffer): string { + const bytes = new Uint8Array(buffer); + let binary = ''; + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]); + } + return btoa(binary) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, ''); +} + +function base64UrlDecode(base64url: string): ArrayBuffer { + const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/'); + const binary = atob(base64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes.buffer; +} + +function sanitizeWebAuthnExtensions(extensions: T | null | undefined): T | undefined { + if (extensions === null || extensions === undefined) { + return undefined; + } + + if (Array.isArray(extensions)) { + const cleaned = extensions + .map(sanitizeWebAuthnExtensions) + .filter((v) => v !== undefined) as unknown as T; + return cleaned; + } + + if (typeof extensions === 'object') { + const cleaned: any = {}; + for (const [key, value] of Object.entries(extensions as any)) { + const sanitized = sanitizeWebAuthnExtensions(value as any); + if (sanitized !== undefined) { + cleaned[key] = sanitized; + } + } + return Object.keys(cleaned).length > 0 ? (cleaned as T) : undefined; + } + + return extensions; +} + +function sanitizeTransports(transports: any): AuthenticatorTransport[] | undefined { + if (!Array.isArray(transports)) { + return undefined; + } + + // Keep only string values; browsers are strict about the sequence type. + return transports.filter((t) => typeof t === 'string') as AuthenticatorTransport[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class WebAuthnService { + + constructor(private http: HttpClient) { } + + isSupported(): boolean { + return window.PublicKeyCredential !== undefined && + navigator.credentials !== undefined; + } + + async isPlatformAuthenticatorAvailable(): Promise { + if (!this.isSupported()) { + return false; + } + try { + return await (window.PublicKeyCredential as any).isUserVerifyingPlatformAuthenticatorAvailable(); + } catch (e) { + return false; + } + } + + register(nickname: string): Observable { + return this.http.post( + `${environment.apiUrl}/auth/webauthn/register/start`, {} + ).pipe( + switchMap(async options => { + const publicKeyOptions = this.convertRegistrationOptions(options); + const credential = await navigator.credentials.create({ publicKey: publicKeyOptions }); + if (!credential) { + throw new Error('Registration failed: No credential received'); + } + const credentialJSON = this.credentialToJSON(credential as PublicKeyCredential); + return this.http.post( + `${environment.apiUrl}/auth/webauthn/register/finish`, + { credential: JSON.stringify(credentialJSON), nickname: nickname } + ); + }), + switchMap(result => result) + ); + } + + getCredentials(): Observable { + return this.http.get(`${environment.apiUrl}/auth/webauthn`); + } + + deleteCredential(credentialId: number): Observable { + return this.http.delete(`${environment.apiUrl}/auth/webauthn/${credentialId}`); + } + + updateNickname(credentialId: number, nickname: string): Observable { + return this.http.patch(`${environment.apiUrl}/auth/webauthn/${credentialId}/nickname`, nickname); + } + + updateUsage(credentialId: number, usage: string): Observable { + return this.http.patch(`${environment.apiUrl}/auth/webauthn/${credentialId}/usage`, usage); + } + + requestAuthentication(provider: string) { + return this.http.post(`${environment.apiUrl}/auth/2fa/${provider}`, {}); + } + + loginStart(): Observable { + return this.http.post( + `${environment.apiUrl}/auth/webauthn/login/start`, {} + ) + } + + async authenticateWithOptions(credentialsGetJson: any): Promise { + const publicKeyOptions = this.convertAuthenticationOptions(credentialsGetJson.publicKey); + const credential = await navigator.credentials.get({ publicKey: publicKeyOptions }); + if (!credential) { + throw new Error('Authentication failed: No credential received'); + } + return JSON.stringify(this.assertionToJSON(credential as PublicKeyCredential)); + } + + async authenticate(options: any): Promise { + const publicKeyOptions = this.convertAuthenticationOptions(options); + const credential = await navigator.credentials.get({ publicKey: publicKeyOptions }); + + if (!credential) { + throw new Error('Authentication failed: No credential received'); + } + + return JSON.stringify(this.assertionToJSON(credential as PublicKeyCredential)); + } + + + private convertAuthenticationOptions(options: any): PublicKeyCredentialRequestOptions { + if (!options || !options.challenge) { + throw new Error('Invalid authentication options: missing challenge'); + } + + return { + challenge: base64UrlDecode(options.challenge), + timeout: options.timeout, + rpId: options.rpId, + allowCredentials: (options.allowCredentials || []).map((cred: any) => ({ + type: cred.type, + id: base64UrlDecode(cred.id), + ...(sanitizeTransports(cred.transports) + ? { transports: sanitizeTransports(cred.transports) } + : {}) + })), + userVerification: options.userVerification, + extensions: sanitizeWebAuthnExtensions(options.extensions) + }; + } + + private assertionToJSON(credential: PublicKeyCredential): any { + const response = credential.response as AuthenticatorAssertionResponse; + + return { + id: credential.id, + rawId: base64UrlEncode(credential.rawId), + type: credential.type, + response: { + clientDataJSON: base64UrlEncode(response.clientDataJSON), + authenticatorData: base64UrlEncode(response.authenticatorData), + signature: base64UrlEncode(response.signature), + userHandle: response.userHandle ? base64UrlEncode(response.userHandle) : null + }, + clientExtensionResults: credential.getClientExtensionResults() + }; + } + + private convertRegistrationOptions(options: any): PublicKeyCredentialCreationOptions { + return { + challenge: base64UrlDecode(options.challenge), + rp: options.rp, + user: { + id: base64UrlDecode(options.user.id), + name: options.user.name, + displayName: options.user.displayName + }, + pubKeyCredParams: options.pubKeyCredParams, + timeout: options.timeout, + excludeCredentials: (options.excludeCredentials || []).map((cred: any) => ({ + type: cred.type, + id: base64UrlDecode(cred.id), + ...(sanitizeTransports(cred.transports) + ? { transports: sanitizeTransports(cred.transports) } + : {}) + })), + authenticatorSelection: options.authenticatorSelection, + attestation: options.attestation, + extensions: sanitizeWebAuthnExtensions(options.extensions) + }; + } + + private credentialToJSON(credential: PublicKeyCredential): any { + const response = credential.response as AuthenticatorAttestationResponse; + + return { + id: credential.id, + rawId: base64UrlEncode(credential.rawId), + type: credential.type, + response: { + clientDataJSON: base64UrlEncode(response.clientDataJSON), + attestationObject: base64UrlEncode(response.attestationObject), + transports: (response as any).getTransports ? (response as any).getTransports() : [] + }, + clientExtensionResults: credential.getClientExtensionResults() + }; + } + +} diff --git a/src/assets/i18n/de-informal.json b/src/assets/i18n/de-informal.json index 8eb83cb..3d0da35 100644 --- a/src/assets/i18n/de-informal.json +++ b/src/assets/i18n/de-informal.json @@ -696,7 +696,8 @@ ".": "Login", "external": "Login", "invalid": "Falscher Username oder Passwort.", - "keepSession": "Eingeloggt bleiben" + "keepSession": "Eingeloggt bleiben", + "webauthn": "Mit Security-Key/Passkey einloggen" }, "logout": "Logout", "minetest": { @@ -1024,6 +1025,7 @@ ".": "2FA (TOTP)", "activate": "Um TOTP als 2FA zu aktivieren, gebe bitte deinen aktuellen Code ein.", "code": "TOTP Code", + "confirmRemove": "Bist du sicher, dass du den TOTP als 2FA deaktivieren möchtest?", "create": "2FA (TOTP) einrichten", "enable": "Aktiviere 2FA (TOTP)", "external": "2FA (TOTP)", @@ -1032,7 +1034,8 @@ "login": "Code verfizieren", "missing": "Bitte TOTP Code eingeben", "remove": "2FA (TOTP) deaktivieren" - } + }, + "webauthn": "Security-Key/Passkey" }, "oidc": { ".": "OpenID Connect Login", @@ -1061,6 +1064,24 @@ "hint": "Dein Account sowie alle gespeicherten Daten werden nicht(!) gelöscht. Du kannst deinen Account also jederzeit wieder reaktivieren." }, "success": "Status erfolgreich geändert" + }, + "webauthn": { + ".": "Security Keys/Passkeys", + "confirmRemove": "Bist du sicher, dass du den Security-Key/Passkey '{0}' löschen möchtest?", + "create": "Security-Key/Passkey hinzufügen", + "dialog": { + "info": "Lege einen Namen für den Security-Key/Passkey fest." + }, + "info": "Verwalte deine Security-Keys/Passkeys definiere die Verwendung als Login oder 2FA.", + "nickname": "Name", + "registered": "Deine Security Keys/Passkeys", + "remove": "Security Key/Passkey löschen", + "usage": { + ".": "Verwendung", + "login": "Login", + "none": "Kein", + "two-fa": "2FA" + } } }, "service": { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index a02fef7..3765845 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -696,7 +696,8 @@ ".": "Login", "external": "Login", "invalid": "Wrong username or password.", - "keepSession": "Stay logged in" + "keepSession": "Stay logged in", + "webauthn": "Login with Security-Key/Passkey" }, "logout": "Logout", "minetest": { @@ -1008,7 +1009,7 @@ ".": "Two-Factor-Authentication (2FA)", "code": "Code", "external": "2FA required", - "info": "You can additionally add a second factor to your password. Please keep in mind, that this only affects your we.bstly-Account and not your email login. Currently only TOTP (also known as Google Authenticator) is supported as 2FA method.", + "info": "You can additionally add a second factor to your password. Please keep in mind, that this only affects your we.bstly-Account and not your email login. Currently only TOTP (also known as Google Authenticator) and Security-Keys/Passkeys supported as 2FA method.", "invalid": "Invalid code", "keepSession": "Remember 2FA for this device", "login": "Verify code", @@ -1018,11 +1019,13 @@ ".": "2FA (TOTP)", "activate": "Please enter your current code to enable TOTP as your 2FA.", "code": "TOTP code", + "confirmRemove": "Are you sure you want to disbale 2FA widh TOTP?", "create": "2FA (TOTP) create", "enable": "Enable 2FA (TOTP)", "hint": "To use TOP as second factor, please scan the shown QR-Code with your TOTP App.", "remove": "Disable 2FA (TOTP)" - } + }, + "webauthn": "Security-Key/Passkey" }, "oidc": { ".": "OpenID Connect Login", @@ -1051,6 +1054,24 @@ "hint": "Your account and all your data will not(!) be deleted. So you have reactivate your account anytime." }, "success": "Status successfully changed" + }, + "webauthn": { + ".": "Security Keys/Passkeys", + "confirmRemove": "Are you sure you want to delete your Security-Key/Passkey '{0}'?", + "create": "Add Security-Key/Passkey", + "dialog": { + "info": "Define a name for your Security-Key/Passkey" + }, + "info": "Manage your Security-Keys/Passkeys and define if the devices should be used for Login or 2FA.", + "nickname": "Name", + "registered": "Your Security Keys/Passkeys", + "remove": "Remove Security Key/Passkey", + "usage": { + ".": "Usage", + "login": "Login", + "none": "None", + "two-fa": "2FA" + } } }, "service": {