From 93abd359a95bf7b73fbd639be67f151b8b1ac912 Mon Sep 17 00:00:00 2001 From: David Barroso Date: Fri, 2 Feb 2024 19:44:10 +0100 Subject: [PATCH] feat: added endpoint to "elevate" permissions using webauthn (#451) --- .changeset/small-pumpkins-joke.md | 5 + package.json | 10 +- pnpm-lock.yaml | 1233 +++++++++++--------- src/routes/elevate/index.ts | 47 + src/routes/elevate/webauthn.ts | 128 ++ src/routes/index.ts | 2 + src/routes/signin/webauthn.ts | 108 +- src/routes/signup/webauthn/verify.ts | 5 +- src/routes/user/webauthn.ts | 9 +- src/utils/__generated__/graphql-request.ts | 12 - src/utils/jwt/generate.ts | 9 +- src/utils/session.ts | 10 +- src/utils/webauthn.ts | 125 +- src/validation/fields.ts | 2 +- test/routes/user/webauthn.test.ts | 11 +- 15 files changed, 1012 insertions(+), 704 deletions(-) create mode 100644 .changeset/small-pumpkins-joke.md create mode 100644 src/routes/elevate/index.ts create mode 100644 src/routes/elevate/webauthn.ts diff --git a/.changeset/small-pumpkins-joke.md b/.changeset/small-pumpkins-joke.md new file mode 100644 index 000000000..162431ae7 --- /dev/null +++ b/.changeset/small-pumpkins-joke.md @@ -0,0 +1,5 @@ +--- +'hasura-auth': minor +--- + +feat: added endpoint to "elevate" permissions using webauthn diff --git a/package.json b/package.json index cf5fc1baf..d84c8c462 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@djgrant/postgres-migrations": "4.1.0-rc.1", - "@simplewebauthn/server": "^5.4.5", + "@simplewebauthn/server": "^7.2.0", "axios": "^1.6.5", "bcryptjs": "^2.4.3", "body-parser": "1.19.0", @@ -32,7 +32,7 @@ "cors": "2.8.5", "dot-prop": "^6.0.1", "dotenv": "8.2.0", - "email-templates": "^10.0.1", + "email-templates": "^11.1.1", "email-validator": "^2.0.4", "express": "4.17.1", "express-jsdoc-swagger": "^1.8.0", @@ -53,11 +53,12 @@ "json-to-graphql-query": "^2.2.5", "jsonata": "^1.8.6", "jsonwebtoken": "^9.0.2", + "jsrsasign": "11.0.0", "libphonenumber-js": "^1.10.53", "micromatch": "^4.0.5", "nocache": "^2.1.0", "node-fetch": "^2.7.0", - "nodemailer": "6.9.3", + "nodemailer": "6.9.9", "otplib": "12.0.1", "pascal-case": "^3.1.2", "pg": "^8.11.3", @@ -78,6 +79,7 @@ "@graphql-codegen/typescript": "^2.8.8", "@graphql-codegen/typescript-graphql-request": "^4.5.9", "@graphql-codegen/typescript-operations": "^2.5.13", + "@simplewebauthn/types": "^9.0.0", "@simplewebauthn/typescript-types": "^5.4.0", "@types/bcryptjs": "^2.4.6", "@types/body-parser": "1.19.0", @@ -95,7 +97,7 @@ "@types/micromatch": "^4.0.6", "@types/node": "^17.0.45", "@types/node-fetch": "^2.6.10", - "@types/nodemailer": "6.4.0", + "@types/nodemailer": "6.4.14", "@types/pg": "^7.14.11", "@types/qrcode": "1.3.4", "@types/random-number-csprng": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05bfb800e..0d29d1762 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,8 +19,8 @@ dependencies: specifier: 4.1.0-rc.1 version: 4.1.0-rc.1 '@simplewebauthn/server': - specifier: ^5.4.5 - version: 5.4.5 + specifier: ^7.2.0 + version: 7.4.0 axios: specifier: ^1.6.5 version: 1.6.5 @@ -43,8 +43,8 @@ dependencies: specifier: 8.2.0 version: 8.2.0 email-templates: - specifier: ^10.0.1 - version: 10.0.1(underscore@1.13.6) + specifier: ^11.1.1 + version: 11.1.1(@babel/core@7.23.9)(underscore@1.13.6) email-validator: specifier: ^2.0.4 version: 2.0.4 @@ -105,6 +105,9 @@ dependencies: jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 + jsrsasign: + specifier: 11.0.0 + version: 11.0.0 libphonenumber-js: specifier: ^1.10.53 version: 1.10.53 @@ -118,8 +121,8 @@ dependencies: specifier: ^2.7.0 version: 2.7.0 nodemailer: - specifier: 6.9.3 - version: 6.9.3 + specifier: 6.9.9 + version: 6.9.9 otplib: specifier: 12.0.1 version: 12.0.1 @@ -166,7 +169,7 @@ devDependencies: version: 3.2.3(graphql@16.2.0) '@graphql-codegen/cli': specifier: ^2.16.5 - version: 2.16.5(@babel/core@7.23.7)(@types/node@17.0.45)(graphql@16.2.0)(typescript@4.5.4) + version: 2.16.5(@babel/core@7.23.9)(@types/node@17.0.45)(graphql@16.2.0)(typescript@4.5.4) '@graphql-codegen/typescript': specifier: ^2.8.8 version: 2.8.8(graphql@16.2.0) @@ -176,6 +179,9 @@ devDependencies: '@graphql-codegen/typescript-operations': specifier: ^2.5.13 version: 2.5.13(graphql@16.2.0) + '@simplewebauthn/types': + specifier: ^9.0.0 + version: 9.0.0 '@simplewebauthn/typescript-types': specifier: ^5.4.0 version: 5.4.0 @@ -228,8 +234,8 @@ devDependencies: specifier: ^2.6.10 version: 2.6.10 '@types/nodemailer': - specifier: 6.4.0 - version: 6.4.0 + specifier: 6.4.14 + version: 6.4.14 '@types/pg': specifier: ^7.14.11 version: 7.14.11 @@ -325,7 +331,7 @@ devDependencies: version: 6.3.3 ts-jest: specifier: ^27.1.5 - version: 27.1.5(@babel/core@7.23.7)(@types/jest@27.5.2)(jest@27.5.1)(typescript@4.5.4) + version: 27.1.5(@babel/core@7.23.9)(@types/jest@27.5.2)(jest@27.5.1)(typescript@4.5.4) ts-node-dev: specifier: ^1.1.8 version: 1.1.8(typescript@4.5.4) @@ -347,7 +353,6 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 - dev: true /@ardatan/relay-compiler@12.0.0(graphql@16.2.0): resolution: {integrity: sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==} @@ -393,12 +398,10 @@ packages: dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 - dev: true /@babel/compat-data@7.23.5: resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} engines: {node: '>=6.9.0'} - dev: true /@babel/core@7.23.7: resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} @@ -423,6 +426,28 @@ packages: - supports-color dev: true + /@babel/core@7.23.9: + resolution: {integrity: sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.9) + '@babel/helpers': 7.23.9 + '@babel/parser': 7.23.9 + '@babel/template': 7.23.9 + '@babel/traverse': 7.23.9 + '@babel/types': 7.23.9 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + /@babel/generator@7.23.6: resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} @@ -431,7 +456,6 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 - dev: true /@babel/helper-annotate-as-pure@7.22.5: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} @@ -449,7 +473,6 @@ packages: browserslist: 4.22.2 lru-cache: 5.1.1 semver: 6.3.1 - dev: true /@babel/helper-create-class-features-plugin@7.23.7(@babel/core@7.23.7): resolution: {integrity: sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==} @@ -472,7 +495,6 @@ packages: /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} @@ -480,14 +502,12 @@ packages: dependencies: '@babel/template': 7.22.15 '@babel/types': 7.23.6 - dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 - dev: true /@babel/helper-member-expression-to-functions@7.23.0: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} @@ -501,7 +521,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 - dev: true /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} @@ -517,6 +536,19 @@ packages: '@babel/helper-validator-identifier': 7.22.20 dev: true + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + /@babel/helper-optimise-call-expression@7.22.5: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} @@ -546,7 +578,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 - dev: true /@babel/helper-skip-transparent-expression-wrappers@7.22.5: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} @@ -560,7 +591,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 - dev: true /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} @@ -573,7 +603,6 @@ packages: /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helpers@7.23.8: resolution: {integrity: sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==} @@ -586,6 +615,16 @@ packages: - supports-color dev: true + /@babel/helpers@7.23.9: + resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.23.9 + '@babel/traverse': 7.23.9 + '@babel/types': 7.23.9 + transitivePeerDependencies: + - supports-color + /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} @@ -593,7 +632,6 @@ packages: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 - dev: true /@babel/parser@7.23.6: resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} @@ -602,6 +640,13 @@ packages: dependencies: '@babel/types': 7.23.6 + /@babel/parser@7.23.9: + resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.9 + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7): resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} @@ -666,13 +711,13 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7): + /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.9): resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 dev: true @@ -1012,7 +1057,14 @@ packages: '@babel/code-frame': 7.23.5 '@babel/parser': 7.23.6 '@babel/types': 7.23.6 - dev: true + + /@babel/template@7.23.9: + resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 /@babel/traverse@7.23.7: resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} @@ -1032,6 +1084,23 @@ packages: - supports-color dev: true + /@babel/traverse@7.23.9: + resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + /@babel/types@7.23.6: resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} engines: {node: '>=6.9.0'} @@ -1040,10 +1109,66 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + /@babel/types@7.23.9: + resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true + /@cbor-extract/cbor-extract-darwin-arm64@2.2.0: + resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-darwin-x64@2.2.0: + resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-linux-arm64@2.2.0: + resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-linux-arm@2.2.0: + resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-linux-x64@2.2.0: + resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cbor-extract/cbor-extract-win32-x64@2.2.0: + resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@changesets/apply-release-plan@7.0.0: resolution: {integrity: sha512-vfi69JR416qC9hWmFGSxj7N6wA5J222XNBmezSVATPWDVPIF7gkd4d8CpbEbXmRWbVrkoli3oerGS6dcL/BGsQ==} dependencies: @@ -1266,12 +1391,12 @@ packages: ajv: 6.12.6 dev: true - /@commitlint/config-validator@18.4.4: - resolution: {integrity: sha512-/QI8KIg/h7O0Eus36fPcEcO3QPBcdXuGfZeCF5m15k0EB2bcU8s6pHNTNEa6xz9PrAefHCL+yzRJj7w20T6Mow==} + /@commitlint/config-validator@18.6.0: + resolution: {integrity: sha512-Ptfa865arNozlkjxrYG3qt6wT9AlhNUHeuDyKEZiTL/l0ftncFhK/KN0t/EAMV2tec+0Mwxo0FmhbESj/bI+1g==} engines: {node: '>=v18'} requiresBuild: true dependencies: - '@commitlint/types': 18.4.4 + '@commitlint/types': 18.6.0 ajv: 8.12.0 dev: true optional: true @@ -1342,15 +1467,15 @@ packages: - '@swc/wasm' dev: true - /@commitlint/load@18.4.4(@types/node@17.0.45)(typescript@4.5.4): - resolution: {integrity: sha512-RaDIa9qwOw2xRJ3Jr2DBXd14rmnHJIX2XdZF4kmoF1rgsg/+7cvrExLSUNAkQUNimyjCn1b/bKX2Omm+GdY0XQ==} + /@commitlint/load@18.6.0(@types/node@17.0.45)(typescript@4.5.4): + resolution: {integrity: sha512-RRssj7TmzT0bowoEKlgwg8uQ7ORXWkw7lYLsZZBMi9aInsJuGNLNWcMxJxRZbwxG3jkCidGUg85WmqJvRjsaDA==} engines: {node: '>=v18'} requiresBuild: true dependencies: - '@commitlint/config-validator': 18.4.4 + '@commitlint/config-validator': 18.6.0 '@commitlint/execute-rule': 18.4.4 - '@commitlint/resolve-extends': 18.4.4 - '@commitlint/types': 18.4.4 + '@commitlint/resolve-extends': 18.6.0 + '@commitlint/types': 18.6.0 chalk: 4.1.2 cosmiconfig: 8.3.6(typescript@4.5.4) cosmiconfig-typescript-loader: 5.0.0(@types/node@17.0.45)(cosmiconfig@8.3.6)(typescript@4.5.4) @@ -1400,13 +1525,13 @@ packages: resolve-global: 1.0.0 dev: true - /@commitlint/resolve-extends@18.4.4: - resolution: {integrity: sha512-RRpIHSbRnFvmGifVk21Gqazf1QF/yeP+Kkg/e3PlkegcOKd/FGOXp/Kx9cvSO2K7ucSn4GD/oBvgasFoy+NCAw==} + /@commitlint/resolve-extends@18.6.0: + resolution: {integrity: sha512-k2Xp+Fxeggki2i90vGrbiLDMefPius3zGSTFFlRAPKce/SWLbZtI+uqE9Mne23mHO5lmcSV8z5m6ziiJwGpOcg==} engines: {node: '>=v18'} requiresBuild: true dependencies: - '@commitlint/config-validator': 18.4.4 - '@commitlint/types': 18.4.4 + '@commitlint/config-validator': 18.6.0 + '@commitlint/types': 18.6.0 import-fresh: 3.3.0 lodash.mergewith: 4.6.2 resolve-from: 5.0.0 @@ -1444,8 +1569,8 @@ packages: chalk: 4.1.2 dev: true - /@commitlint/types@18.4.4: - resolution: {integrity: sha512-/FykLtodD8gKs3+VNkAUwofu4LBHankclj+I8fB2jTRvG6PV7k/OUt4P+VbM7ip853qS4F0g7Z6hLNa6JeMcAQ==} + /@commitlint/types@18.6.0: + resolution: {integrity: sha512-oavoKLML/eJa2rJeyYSbyGAYzTxQ6voG5oeX3OrxpfrkRWhJfm4ACnhoRf5tgiybx2MZ+EVFqC1Lw3W8/uwpZA==} engines: {node: '>=v18'} requiresBuild: true dependencies: @@ -1486,7 +1611,7 @@ packages: tslib: 2.4.1 dev: true - /@graphql-codegen/cli@2.16.5(@babel/core@7.23.7)(@types/node@17.0.45)(graphql@16.2.0)(typescript@4.5.4): + /@graphql-codegen/cli@2.16.5(@babel/core@7.23.9)(@types/node@17.0.45)(graphql@16.2.0)(typescript@4.5.4): resolution: {integrity: sha512-XYPIp+q7fB0xAGSAoRykiTe4oY80VU+z+dw5nuv4mLY0+pv7+pa2C6Nwhdw7a65lXOhFviBApWCCZeqd54SMnA==} hasBin: true peerDependencies: @@ -1498,9 +1623,9 @@ packages: '@graphql-codegen/core': 2.6.8(graphql@16.2.0) '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.2.0) '@graphql-tools/apollo-engine-loader': 7.3.26(graphql@16.2.0) - '@graphql-tools/code-file-loader': 7.3.23(@babel/core@7.23.7)(graphql@16.2.0) - '@graphql-tools/git-loader': 7.3.0(@babel/core@7.23.7)(graphql@16.2.0) - '@graphql-tools/github-loader': 7.3.28(@babel/core@7.23.7)(@types/node@17.0.45)(graphql@16.2.0) + '@graphql-tools/code-file-loader': 7.3.23(@babel/core@7.23.9)(graphql@16.2.0) + '@graphql-tools/git-loader': 7.3.0(@babel/core@7.23.9)(graphql@16.2.0) + '@graphql-tools/github-loader': 7.3.28(@babel/core@7.23.9)(@types/node@17.0.45)(graphql@16.2.0) '@graphql-tools/graphql-file-loader': 7.5.17(graphql@16.2.0) '@graphql-tools/json-file-loader': 7.4.18(graphql@16.2.0) '@graphql-tools/load': 7.8.14(graphql@16.2.0) @@ -1712,12 +1837,12 @@ packages: value-or-promise: 1.0.12 dev: true - /@graphql-tools/code-file-loader@7.3.23(@babel/core@7.23.7)(graphql@16.2.0): + /@graphql-tools/code-file-loader@7.3.23(@babel/core@7.23.9)(graphql@16.2.0): resolution: {integrity: sha512-8Wt1rTtyTEs0p47uzsPJ1vAtfAx0jmxPifiNdmo9EOCuUPyQGEbMaik/YkqZ7QUFIEYEQu+Vgfo8tElwOPtx5Q==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - '@graphql-tools/graphql-tag-pluck': 7.5.2(@babel/core@7.23.7)(graphql@16.2.0) + '@graphql-tools/graphql-tag-pluck': 7.5.2(@babel/core@7.23.9)(graphql@16.2.0) '@graphql-tools/utils': 9.2.1(graphql@16.2.0) globby: 11.1.0 graphql: 16.2.0 @@ -1808,12 +1933,12 @@ packages: value-or-promise: 1.0.12 dev: true - /@graphql-tools/git-loader@7.3.0(@babel/core@7.23.7)(graphql@16.2.0): + /@graphql-tools/git-loader@7.3.0(@babel/core@7.23.9)(graphql@16.2.0): resolution: {integrity: sha512-gcGAK+u16eHkwsMYqqghZbmDquh8QaO24Scsxq+cVR+vx1ekRlsEiXvu+yXVDbZdcJ6PBIbeLcQbEu+xhDLmvQ==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - '@graphql-tools/graphql-tag-pluck': 7.5.2(@babel/core@7.23.7)(graphql@16.2.0) + '@graphql-tools/graphql-tag-pluck': 7.5.2(@babel/core@7.23.9)(graphql@16.2.0) '@graphql-tools/utils': 9.2.1(graphql@16.2.0) graphql: 16.2.0 is-glob: 4.0.3 @@ -1825,14 +1950,14 @@ packages: - supports-color dev: true - /@graphql-tools/github-loader@7.3.28(@babel/core@7.23.7)(@types/node@17.0.45)(graphql@16.2.0): + /@graphql-tools/github-loader@7.3.28(@babel/core@7.23.9)(@types/node@17.0.45)(graphql@16.2.0): resolution: {integrity: sha512-OK92Lf9pmxPQvjUNv05b3tnVhw0JRfPqOf15jZjyQ8BfdEUrJoP32b4dRQQem/wyRL24KY4wOfArJNqzpsbwCA==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: '@ardatan/sync-fetch': 0.0.1 '@graphql-tools/executor-http': 0.1.10(@types/node@17.0.45)(graphql@16.2.0) - '@graphql-tools/graphql-tag-pluck': 7.5.2(@babel/core@7.23.7)(graphql@16.2.0) + '@graphql-tools/graphql-tag-pluck': 7.5.2(@babel/core@7.23.9)(graphql@16.2.0) '@graphql-tools/utils': 9.2.1(graphql@16.2.0) '@whatwg-node/fetch': 0.8.8 graphql: 16.2.0 @@ -1858,13 +1983,13 @@ packages: unixify: 1.0.0 dev: true - /@graphql-tools/graphql-tag-pluck@7.5.2(@babel/core@7.23.7)(graphql@16.2.0): + /@graphql-tools/graphql-tag-pluck@7.5.2(@babel/core@7.23.9)(graphql@16.2.0): resolution: {integrity: sha512-RW+H8FqOOLQw0BPXaahYepVSRjuOHw+7IL8Opaa5G5uYGOBxoXR7DceyQ7BcpMgktAOOmpDNQ2WtcboChOJSRA==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: '@babel/parser': 7.23.6 - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.9) '@babel/traverse': 7.23.7 '@babel/types': 7.23.6 '@graphql-tools/utils': 9.2.1(graphql@16.2.0) @@ -2073,6 +2198,10 @@ packages: '@hapi/hoek': 9.3.0 dev: false + /@hexagon/base64@1.1.28: + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + dev: false + /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -2323,28 +2452,23 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.20 - dev: true /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -2353,6 +2477,161 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /@ladjs/consolidate@1.0.3(@babel/core@7.23.9)(lodash@4.17.21)(underscore@1.13.6): + resolution: {integrity: sha512-zyUeV5nkEFz7FH88pz+moVeMMOygTx1zL5bjXGHCVX5MMpmAtFf5piaQlBDk3nClGoUs8vjYI9TKsbXldGv0VA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.22.5 + arc-templates: ^0.5.3 + atpl: '>=0.7.6' + bracket-template: ^1.1.5 + coffee-script: ^1.12.7 + dot: ^1.1.3 + dust: ^0.3.0 + dustjs-helpers: ^1.7.4 + dustjs-linkedin: ^2.7.5 + eco: ^1.1.0-rc-3 + ect: ^0.5.9 + ejs: ^3.1.5 + haml-coffee: ^1.14.1 + hamlet: ^0.3.3 + hamljs: ^0.6.2 + handlebars: ^4.7.6 + hogan.js: ^3.0.2 + htmling: ^0.0.8 + jazz: ^0.0.18 + jqtpl: ~1.1.0 + just: ^0.1.8 + liquid-node: ^3.0.1 + liquor: ^0.0.5 + lodash: ^4.17.20 + mote: ^0.2.0 + mustache: ^4.0.1 + nunjucks: ^3.2.2 + plates: ~0.4.11 + pug: ^3.0.0 + qejs: ^3.0.5 + ractive: ^1.3.12 + react: '>=16.13.1' + react-dom: '>=16.13.1' + slm: ^2.0.0 + swig: ^1.4.2 + swig-templates: ^2.0.3 + teacup: ^2.0.0 + templayed: '>=0.2.3' + then-pug: '*' + tinyliquid: ^0.2.34 + toffee: ^0.3.6 + twig: ^1.15.2 + twing: ^5.0.2 + underscore: ^1.11.0 + vash: ^0.13.0 + velocityjs: ^2.0.1 + walrus: ^0.10.1 + whiskers: ^0.4.0 + peerDependenciesMeta: + '@babel/core': + optional: true + arc-templates: + optional: true + atpl: + optional: true + bracket-template: + optional: true + coffee-script: + optional: true + dot: + optional: true + dust: + optional: true + dustjs-helpers: + optional: true + dustjs-linkedin: + optional: true + eco: + optional: true + ect: + optional: true + ejs: + optional: true + haml-coffee: + optional: true + hamlet: + optional: true + hamljs: + optional: true + handlebars: + optional: true + hogan.js: + optional: true + htmling: + optional: true + jazz: + optional: true + jqtpl: + optional: true + just: + optional: true + liquid-node: + optional: true + liquor: + optional: true + lodash: + optional: true + mote: + optional: true + mustache: + optional: true + nunjucks: + optional: true + plates: + optional: true + pug: + optional: true + qejs: + optional: true + ractive: + optional: true + react: + optional: true + react-dom: + optional: true + slm: + optional: true + swig: + optional: true + swig-templates: + optional: true + teacup: + optional: true + templayed: + optional: true + then-pug: + optional: true + tinyliquid: + optional: true + toffee: + optional: true + twig: + optional: true + twing: + optional: true + underscore: + optional: true + vash: + optional: true + velocityjs: + optional: true + walrus: + optional: true + whiskers: + optional: true + dependencies: + '@babel/core': 7.23.9 + lodash: 4.17.21 + underscore: 1.13.6 + dev: false + /@ladjs/country-language@0.2.1: resolution: {integrity: sha512-e3AmT7jUnfNE6e2mx2+cPYiWdFW3McySDGRhQEYE6SksjZTMj0PTp+R9x1xG89tHRTsyMNJFl9J4HtZPWZzi1Q==} dependencies: @@ -2379,7 +2658,7 @@ packages: punycode: 2.3.1 qs: 6.11.2 titleize: 2.1.0 - tlds: 1.248.0 + tlds: 1.249.0 transitivePeerDependencies: - supports-color dev: false @@ -2497,6 +2776,24 @@ packages: tslib: 2.6.2 dev: false + /@peculiar/asn1-ecc@2.3.8: + resolution: {integrity: sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==} + dependencies: + '@peculiar/asn1-schema': 2.3.8 + '@peculiar/asn1-x509': 2.3.8 + asn1js: 3.0.5 + tslib: 2.6.2 + dev: false + + /@peculiar/asn1-rsa@2.3.8: + resolution: {integrity: sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==} + dependencies: + '@peculiar/asn1-schema': 2.3.8 + '@peculiar/asn1-x509': 2.3.8 + asn1js: 3.0.5 + tslib: 2.6.2 + dev: false + /@peculiar/asn1-schema@2.3.8: resolution: {integrity: sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==} dependencies: @@ -2565,13 +2862,6 @@ packages: selderee: 0.11.0 dev: false - /@selderee/plugin-htmlparser2@0.6.0: - resolution: {integrity: sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==} - dependencies: - domhandler: 4.3.1 - selderee: 0.6.0 - dev: false - /@sideway/address@4.1.4: resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} dependencies: @@ -2586,29 +2876,48 @@ packages: resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} dev: false - /@simplewebauthn/server@5.4.5: - resolution: {integrity: sha512-o7Tn0X8s2465ijG25Ehmckoxqgx94R8jtMHNxoxd6zXXme2fgSC1nRLnZz8bUBoho1jeG3eZ516LiRtmsOdQZw==} - engines: {node: '>=10.0.0'} + /@simplewebauthn/iso-webcrypto@7.4.0: + resolution: {integrity: sha512-LSx8zghjH+z9IFOhBdDv2AyhqnzDUCYFxFiwJbToowOigCgf4Y8fyZle9Y+0NS232bIoU6j/lgv5iT32m3eGyA==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + dependencies: + '@simplewebauthn/typescript-types': 7.4.0 + '@types/node': 18.19.9 + dev: false + + /@simplewebauthn/server@7.4.0: + resolution: {integrity: sha512-Y6jj2WsE3zBDagSdOg3b7+SMw7zHku0Od45Q1ZpA19Wd5aUbV2mH281SbdhFN4UuKcGQSeeAgUObAWHvgxNOVA==} + engines: {node: '>=16.0.0'} dependencies: + '@hexagon/base64': 1.1.28 '@peculiar/asn1-android': 2.3.10 + '@peculiar/asn1-ecc': 2.3.8 + '@peculiar/asn1-rsa': 2.3.8 '@peculiar/asn1-schema': 2.3.8 '@peculiar/asn1-x509': 2.3.8 - '@simplewebauthn/typescript-types': 5.4.0 - base64url: 3.0.1 - cbor: 5.2.0 + '@simplewebauthn/iso-webcrypto': 7.4.0 + '@simplewebauthn/typescript-types': 7.4.0 + '@types/debug': 4.1.12 + '@types/node': 18.19.9 + cbor-x: 1.5.8 + cross-fetch: 3.1.8 debug: 4.3.4 - elliptic: 6.5.4 - jsrsasign: 10.9.0 - jwk-to-pem: 2.0.5 - node-fetch: 2.7.0 - node-rsa: 1.1.1 transitivePeerDependencies: - encoding - supports-color dev: false + /@simplewebauthn/types@9.0.0: + resolution: {integrity: sha512-Lo6LLNQee66D//KueYy9AyX7oiQ7BBKJgdLzP3l0HJDrV4GRSzSAii8AtigBGOeNc8hOQsF/D8itItyuZX9djA==} + dev: true + /@simplewebauthn/typescript-types@5.4.0: resolution: {integrity: sha512-LeJq6Jx+o7D6iIlCy8CH5jCjwVcUvAReEo66VcF3nysfc/yKW5yCAPLSRmPITF4CRZTfnVPxUBUcveUQL6aBMA==} + dev: true + + /@simplewebauthn/typescript-types@7.4.0: + resolution: {integrity: sha512-8/ZjHeUPe210Bt5oyaOIGx4h8lHdsQs19BiOT44gi/jBEgK7uBGA0Fy7NRsyh777al3m6WM0mBf0UR7xd4R7WQ==} + deprecated: This package has been renamed to @simplewebauthn/types. Please install @simplewebauthn/types instead to ensure you receive future updates. + dev: false /@sinonjs/commons@1.8.6: resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} @@ -2703,6 +3012,12 @@ packages: '@types/express': 4.17.6 dev: true + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 0.7.34 + dev: false + /@types/ejs@3.0.2: resolution: {integrity: sha512-+nriFZYDz+C+6SWzJp0jHrGvyzL3Sg63u1vRlH1AfViyaT4oTod+MtfZ0YMNYXzO7ybFkdx4ZaBwBtLwdYkReQ==} dev: true @@ -2711,7 +3026,7 @@ packages: resolution: {integrity: sha512-dO/luzyN+O60lVi9njcmh5AoofwxKz0yZiIZEbw0F2fcfe3RsAU/BUNlJDR8ry2gyjR0qn3PoOrUNJblcu9PmQ==} dependencies: '@types/html-to-text': 9.0.4 - '@types/nodemailer': 6.4.0 + '@types/nodemailer': 6.4.14 dev: true /@types/eslint-visitor-keys@1.0.0: @@ -2852,6 +3167,10 @@ packages: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} dev: true + /@types/ms@0.7.34: + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + dev: false + /@types/node-fetch@2.6.10: resolution: {integrity: sha512-PPpPK6F9ALFTn59Ka3BaL+qGuipRfxNE8qVgkp0bVixeiR2c2/L+IVOiBdu9JhhT22sWnQEp6YyHGI2b2+CMcA==} dependencies: @@ -2867,8 +3186,14 @@ packages: resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} dev: true - /@types/nodemailer@6.4.0: - resolution: {integrity: sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==} + /@types/node@18.19.9: + resolution: {integrity: sha512-oZFKlC8l5YtzGQNT4zC2PiSSKzQVZ8bAwwd+EYdPLtyk0nSEq6O16SkK+rkkT2eflDAbormJgEF3QnH3oDrTSw==} + dependencies: + undici-types: 5.26.5 + dev: false + + /@types/nodemailer@6.4.14: + resolution: {integrity: sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==} dependencies: '@types/node': 17.0.45 dev: true @@ -3475,12 +3800,7 @@ packages: minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 dev: false - - /asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - dependencies: - safer-buffer: 2.1.2 - dev: false + optional: true /asn1js@3.0.5: resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} @@ -3663,7 +3983,7 @@ packages: resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.23.9 dev: false /balanced-match@1.0.2: @@ -3672,11 +3992,6 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - /base64url@3.0.1: - resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} - engines: {node: '>=6.0.0'} - dev: false - /base@0.11.2: resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} engines: {node: '>=0.10.0'} @@ -3701,10 +4016,6 @@ packages: is-windows: 1.0.2 dev: true - /bignumber.js@9.1.2: - resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} - dev: false - /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -3728,7 +4039,9 @@ packages: /bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + requiresBuild: true dev: false + optional: true /body-parser@1.19.0: resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==} @@ -3798,7 +4111,9 @@ packages: /brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + requiresBuild: true dev: false + optional: true /browser-process-hrtime@1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} @@ -3813,7 +4128,6 @@ packages: electron-to-chromium: 1.4.628 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) - dev: true /bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} @@ -3909,7 +4223,7 @@ packages: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} dependencies: pascal-case: 3.1.2 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /camelcase-keys@6.2.2: @@ -3936,22 +4250,35 @@ packages: /caniuse-lite@1.0.30001576: resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==} - dev: true /capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case-first: 2.0.2 dev: true - /cbor@5.2.0: - resolution: {integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==} - engines: {node: '>=6.0.0'} + /cbor-extract@2.2.0: + resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} + hasBin: true + requiresBuild: true dependencies: - bignumber.js: 9.1.2 - nofilter: 1.0.4 + node-gyp-build-optional-packages: 5.1.1 + optionalDependencies: + '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 + '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 + '@cbor-extract/cbor-extract-linux-x64': 2.2.0 + '@cbor-extract/cbor-extract-win32-x64': 2.2.0 + dev: false + optional: true + + /cbor-x@1.5.8: + resolution: {integrity: sha512-gc3bHBsvG6GClCY6c0/iip+ghlqizkVp+TtaL927lwvP4VP9xBdi1HmqPR5uj/Mj/0TOlngMkIYa25wKg+VNrQ==} + optionalDependencies: + cbor-extract: 2.2.0 dev: false /chalk@1.1.3: @@ -4049,27 +4376,28 @@ packages: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true - /cheerio-select@1.6.0: - resolution: {integrity: sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==} + /cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} dependencies: - css-select: 4.3.0 + boolbase: 1.0.0 + css-select: 5.1.0 css-what: 6.1.0 domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 + domhandler: 5.0.3 + domutils: 3.1.0 dev: false - /cheerio@1.0.0-rc.10: - resolution: {integrity: sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==} + /cheerio@1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} engines: {node: '>= 6'} dependencies: - cheerio-select: 1.6.0 - dom-serializer: 1.4.1 - domhandler: 4.3.1 - htmlparser2: 6.1.0 - parse5: 6.0.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - tslib: 2.6.2 + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.1.0 + htmlparser2: 8.0.2 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 dev: false /chokidar@3.5.3: @@ -4200,332 +4528,157 @@ packages: /codecov@3.8.3: resolution: {integrity: sha512-Y8Hw+V3HgR7V71xWH2vQ9lyS358CbGCldWlJFR0JirqoGtOoas3R3/OclRTvgUYFK29mmJICDPauVKmpqbwhOA==} engines: {node: '>=4.0'} - deprecated: https://about.codecov.io/blog/codecov-uploader-deprecation-plan/ - hasBin: true - dependencies: - argv: 0.0.2 - ignore-walk: 3.0.4 - js-yaml: 3.14.1 - teeny-request: 7.1.1 - urlgrey: 1.0.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - - /collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - dev: true - - /collection-visit@1.0.0: - resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} - engines: {node: '>=0.10.0'} - dependencies: - map-visit: 1.0.0 - object-visit: 1.0.1 - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - /color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - dev: false - - /color@3.2.1: - resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} - dependencies: - color-convert: 1.9.3 - color-string: 1.9.1 - dev: false - - /colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - dev: true - - /colorspace@1.1.4: - resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} - dependencies: - color: 3.2.1 - text-hex: 1.0.0 - dev: false - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: false - - /commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - dev: true - - /commander@6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - dev: false - - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - dev: true - - /commitizen@4.3.0(@types/node@17.0.45)(typescript@4.5.4): - resolution: {integrity: sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==} - engines: {node: '>= 12'} - hasBin: true - dependencies: - cachedir: 2.3.0 - cz-conventional-changelog: 3.3.0(@types/node@17.0.45)(typescript@4.5.4) - dedent: 0.7.0 - detect-indent: 6.1.0 - find-node-modules: 2.1.3 - find-root: 1.1.0 - fs-extra: 9.1.0 - glob: 7.2.3 - inquirer: 8.2.5 - is-utf8: 0.2.1 - lodash: 4.17.21 - minimist: 1.2.7 - strip-bom: 4.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - '@types/node' - - typescript - dev: true - - /common-tags@1.8.2: - resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} - engines: {node: '>=4.0.0'} - dev: true - - /compare-func@2.0.0: - resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - dependencies: - array-ify: 1.0.0 - dot-prop: 5.3.0 - dev: true - - /compare-urls@2.0.0: - resolution: {integrity: sha512-eCJcWn2OYFEIqbm70ta7LQowJOOZZqq1a2YbbFCFI1uwSvj+TWMwXVn7vPR1ceFNcAIt5RSTDbwdlX82gYLTkA==} - engines: {node: '>=6'} - dependencies: - normalize-url: 2.0.1 - dev: false - - /component-emitter@1.3.1: - resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - /consolidate@0.16.0(lodash@4.17.21)(underscore@1.13.6): - resolution: {integrity: sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==} - engines: {node: '>= 0.10.0'} - deprecated: Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog - peerDependencies: - arc-templates: ^0.5.3 - atpl: '>=0.7.6' - babel-core: ^6.26.3 - bracket-template: ^1.1.5 - coffee-script: ^1.12.7 - dot: ^1.1.3 - dust: ^0.3.0 - dustjs-helpers: ^1.7.4 - dustjs-linkedin: ^2.7.5 - eco: ^1.1.0-rc-3 - ect: ^0.5.9 - ejs: ^3.1.5 - haml-coffee: ^1.14.1 - hamlet: ^0.3.3 - hamljs: ^0.6.2 - handlebars: ^4.7.6 - hogan.js: ^3.0.2 - htmling: ^0.0.8 - jade: ^1.11.0 - jazz: ^0.0.18 - jqtpl: ~1.1.0 - just: ^0.1.8 - liquid-node: ^3.0.1 - liquor: ^0.0.5 - lodash: ^4.17.20 - marko: ^3.14.4 - mote: ^0.2.0 - mustache: ^4.0.1 - nunjucks: ^3.2.2 - plates: ~0.4.11 - pug: ^3.0.0 - qejs: ^3.0.5 - ractive: ^1.3.12 - razor-tmpl: ^1.3.1 - react: ^16.13.1 - react-dom: ^16.13.1 - slm: ^2.0.0 - squirrelly: ^5.1.0 - swig: ^1.4.2 - swig-templates: ^2.0.3 - teacup: ^2.0.0 - templayed: '>=0.2.3' - then-jade: '*' - then-pug: '*' - tinyliquid: ^0.2.34 - toffee: ^0.3.6 - twig: ^1.15.2 - twing: ^5.0.2 - underscore: ^1.11.0 - vash: ^0.13.0 - velocityjs: ^2.0.1 - walrus: ^0.10.1 - whiskers: ^0.4.0 - peerDependenciesMeta: - arc-templates: - optional: true - atpl: - optional: true - babel-core: - optional: true - bracket-template: - optional: true - coffee-script: - optional: true - dot: - optional: true - dust: - optional: true - dustjs-helpers: - optional: true - dustjs-linkedin: - optional: true - eco: - optional: true - ect: - optional: true - ejs: - optional: true - haml-coffee: - optional: true - hamlet: - optional: true - hamljs: - optional: true - handlebars: - optional: true - hogan.js: - optional: true - htmling: - optional: true - jade: - optional: true - jazz: - optional: true - jqtpl: - optional: true - just: - optional: true - liquid-node: - optional: true - liquor: - optional: true - lodash: - optional: true - marko: - optional: true - mote: - optional: true - mustache: - optional: true - nunjucks: - optional: true - plates: - optional: true - pug: - optional: true - qejs: - optional: true - ractive: - optional: true - razor-tmpl: - optional: true - react: - optional: true - react-dom: - optional: true - slm: - optional: true - squirrelly: - optional: true - swig: - optional: true - swig-templates: - optional: true - teacup: - optional: true - templayed: - optional: true - then-jade: - optional: true - then-pug: - optional: true - tinyliquid: - optional: true - toffee: - optional: true - twig: - optional: true - twing: - optional: true - underscore: - optional: true - vash: - optional: true - velocityjs: - optional: true - walrus: - optional: true - whiskers: - optional: true + deprecated: https://about.codecov.io/blog/codecov-uploader-deprecation-plan/ + hasBin: true dependencies: - bluebird: 3.7.2 + argv: 0.0.2 + ignore-walk: 3.0.4 + js-yaml: 3.14.1 + teeny-request: 7.1.1 + urlgrey: 1.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: true + + /collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + dev: false + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /colorspace@1.1.4: + resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + dependencies: + color: 3.2.1 + text-hex: 1.0.0 + dev: false + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + dev: false + + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + + /commitizen@4.3.0(@types/node@17.0.45)(typescript@4.5.4): + resolution: {integrity: sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==} + engines: {node: '>= 12'} + hasBin: true + dependencies: + cachedir: 2.3.0 + cz-conventional-changelog: 3.3.0(@types/node@17.0.45)(typescript@4.5.4) + dedent: 0.7.0 + detect-indent: 6.1.0 + find-node-modules: 2.1.3 + find-root: 1.1.0 + fs-extra: 9.1.0 + glob: 7.2.3 + inquirer: 8.2.5 + is-utf8: 0.2.1 lodash: 4.17.21 - underscore: 1.13.6 + minimist: 1.2.7 + strip-bom: 4.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - '@types/node' + - typescript + dev: true + + /common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + + /compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + dev: true + + /compare-urls@2.0.0: + resolution: {integrity: sha512-eCJcWn2OYFEIqbm70ta7LQowJOOZZqq1a2YbbFCFI1uwSvj+TWMwXVn7vPR1ceFNcAIt5RSTDbwdlX82gYLTkA==} + engines: {node: '>=6'} + dependencies: + normalize-url: 2.0.1 dev: false + /component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + /constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case: 2.0.2 dev: true /constantinople@4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 dev: false /content-disposition@0.5.3: @@ -4585,7 +4738,6 @@ packages: /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -4760,7 +4912,7 @@ packages: dependencies: nice-try: 1.0.5 path-key: 2.0.1 - semver: 6.3.1 + semver: 7.5.4 shebang-command: 1.2.0 which: 1.3.1 @@ -4773,13 +4925,13 @@ packages: which: 2.0.2 dev: true - /css-select@4.3.0: - resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + /css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} dependencies: boolbase: 1.0.0 css-what: 6.1.0 - domhandler: 4.3.1 - domutils: 2.8.0 + domhandler: 5.0.3 + domutils: 3.1.0 nth-check: 2.1.1 dev: false @@ -4837,7 +4989,7 @@ packages: right-pad: 1.0.1 word-wrap: 1.2.5 optionalDependencies: - '@commitlint/load': 18.4.4(@types/node@17.0.45)(typescript@4.5.4) + '@commitlint/load': 18.6.0(@types/node@17.0.45)(typescript@4.5.4) transitivePeerDependencies: - '@types/node' - typescript @@ -4854,7 +5006,7 @@ packages: longest: 2.0.1 word-wrap: 1.2.5 optionalDependencies: - '@commitlint/load': 18.4.4(@types/node@17.0.45)(typescript@4.5.4) + '@commitlint/load': 18.6.0(@types/node@17.0.45)(typescript@4.5.4) transitivePeerDependencies: - '@types/node' - typescript @@ -5029,6 +5181,13 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + requiresBuild: true + dev: false + optional: true + /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -5066,10 +5225,6 @@ packages: path-type: 4.0.0 dev: true - /discontinuous-range@1.0.0: - resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==} - dev: false - /display-notification@2.0.0: resolution: {integrity: sha512-TdmtlAcdqy1NU+j7zlkDdMnCL878zriLaBmoD9quOoq1ySSSGv03l0hXK5CvIFZlIfFI/hizqdQuW+Num7xuhw==} engines: {node: '>=4'} @@ -5167,7 +5322,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /dot-prop@5.3.0: @@ -5230,7 +5385,6 @@ packages: /electron-to-chromium@1.4.628: resolution: {integrity: sha512-2k7t5PHvLsufpP6Zwk0nof62yLOsCf032wZx7/q0mv8gwlXjhcxI3lz6f0jBr0GrnWKcm3burXzI3t5IrcdUxw==} - dev: true /elegant-spinner@1.0.1: resolution: {integrity: sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ==} @@ -5239,6 +5393,7 @@ packages: /elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + requiresBuild: true dependencies: bn.js: 4.12.0 brorand: 1.1.0 @@ -5248,24 +5403,24 @@ packages: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 dev: false + optional: true - /email-templates@10.0.1(underscore@1.13.6): - resolution: {integrity: sha512-LNZKS0WW9XQkjuDZd/4p/1Q/pwqaqXOP3iDxTIVIQY9vuHlIUEcRLFo8/Xh3GtZCBnm181VgvOXIABKTVyTePA==} + /email-templates@11.1.1(@babel/core@7.23.9)(underscore@1.13.6): + resolution: {integrity: sha512-MEf/KlM/FokY7Hy3MBLZI5S4lOna0a2SX0tVzKc+VWSIc5/dq19wDkRVl28RgWtKK0Dfb+Z0iqbuk2BnIRfyDg==} engines: {node: '>=14'} - deprecated: We just released outbound SMTP support! Try it out at @ https://forwardemail.net/docs/how-to-javascript-contact-forms-node-js 🚀 ✉️ 👽 dependencies: + '@ladjs/consolidate': 1.0.3(@babel/core@7.23.9)(lodash@4.17.21)(underscore@1.13.6) '@ladjs/i18n': 8.0.3 - consolidate: 0.16.0(lodash@4.17.21)(underscore@1.13.6) get-paths: 0.0.7 - html-to-text: 8.2.1 - juice: 8.1.0 + html-to-text: 9.0.5 + juice: 9.1.0 lodash: 4.17.21 - nodemailer: 6.9.3 + nodemailer: 6.9.9 preview-email: 3.0.19 transitivePeerDependencies: + - '@babel/core' - arc-templates - atpl - - babel-core - bracket-template - coffee-script - dot @@ -5282,13 +5437,11 @@ packages: - handlebars - hogan.js - htmling - - jade - jazz - jqtpl - just - liquid-node - liquor - - marko - mote - mustache - nunjucks @@ -5296,17 +5449,14 @@ packages: - pug - qejs - ractive - - razor-tmpl - react - react-dom - slm - - squirrelly - supports-color - swig - swig-templates - teacup - templayed - - then-jade - then-pug - tinyliquid - toffee @@ -5450,7 +5600,6 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - dev: true /escape-goat@3.0.0: resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==} @@ -6265,7 +6414,6 @@ packages: /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -6398,7 +6546,6 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals@12.4.0: resolution: {integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==} @@ -6615,10 +6762,12 @@ packages: /hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + requiresBuild: true dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 dev: false + optional: true /hasown@2.0.0: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} @@ -6635,7 +6784,7 @@ packages: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} dependencies: capital-case: 1.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /helmet-crossdomain@0.4.0: @@ -6696,11 +6845,13 @@ packages: /hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + requiresBuild: true dependencies: hash.js: 1.1.7 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 dev: false + optional: true /homedir-polyfill@1.0.3: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} @@ -6742,19 +6893,6 @@ packages: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true - /html-to-text@8.2.1: - resolution: {integrity: sha512-aN/3JvAk8qFsWVeE9InWAWueLXrbkoVZy0TkzaGhoRBC2gCFEeRLDDJN3/ijIGHohy6H+SZzUQWN/hcYtaPK8w==} - engines: {node: '>=10.23.2'} - hasBin: true - dependencies: - '@selderee/plugin-htmlparser2': 0.6.0 - deepmerge: 4.3.1 - he: 1.2.0 - htmlparser2: 6.1.0 - minimist: 1.2.8 - selderee: 0.6.0 - dev: false - /html-to-text@9.0.5: resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} engines: {node: '>=14'} @@ -6775,15 +6913,6 @@ packages: entities: 2.2.0 dev: false - /htmlparser2@6.1.0: - resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 - entities: 2.2.0 - dev: false - /htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} dependencies: @@ -8092,7 +8221,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@3.13.1: resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} @@ -8162,7 +8290,6 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} @@ -8219,7 +8346,6 @@ packages: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true /jsonata@1.8.6: resolution: {integrity: sha512-ZH2TPYdNP2JecOl/HvrH47Xc+9imibEMQ4YqKy/F/FrM+2a6vfbGxeCX23dB9Fr6uvGwv+ghf1KxWB3iZk09wA==} @@ -8265,8 +8391,8 @@ packages: semver: 7.5.4 dev: false - /jsrsasign@10.9.0: - resolution: {integrity: sha512-QWLUikj1SBJGuyGK8tjKSx3K7Y69KYJnrs/pQ1KZ6wvZIkHkWjZ1PJDpuvc1/28c1uP0KW9qn1eI1LzHQqDOwQ==} + /jsrsasign@11.0.0: + resolution: {integrity: sha512-BtRwVKS+5dsgPpAtzJcpo5OoWjSs1/zllSBG0+8o8/aV0Ki76m6iZwHnwnsqoTdhfFZDN1XIdcaZr5ZkP+H2gg==} dev: false /jssha@2.4.2: @@ -8281,12 +8407,12 @@ packages: promise: 7.3.1 dev: false - /juice@8.1.0: - resolution: {integrity: sha512-FLzurJrx5Iv1e7CfBSZH68dC04EEvXvvVvPYB7Vx1WAuhCp1ZPIMtqxc+WTWxVkpTIC2Ach/GAv0rQbtGf6YMA==} + /juice@9.1.0: + resolution: {integrity: sha512-odblShmPrUoHUwRuC8EmLji5bPP2MLO1GL+gt4XU3tT2ECmbSrrMjtMQaqg3wgMFP2zvUzdPZGfxc5Trk3Z+fQ==} engines: {node: '>=10.0.0'} hasBin: true dependencies: - cheerio: 1.0.0-rc.10 + cheerio: 1.0.0-rc.12 commander: 6.2.1 mensch: 0.3.4 slick: 1.12.2 @@ -8315,11 +8441,13 @@ packages: /jwk-to-pem@2.0.5: resolution: {integrity: sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==} + requiresBuild: true dependencies: asn1.js: 5.4.1 elliptic: 6.5.4 safe-buffer: 5.2.1 dev: false + optional: true /jws@3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} @@ -8711,7 +8839,6 @@ packages: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 - dev: true /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} @@ -8719,8 +8846,8 @@ packages: dependencies: yallist: 4.0.0 - /mailparser@3.6.6: - resolution: {integrity: sha512-noCjBl3FToxmqTP2fp7z17hQsiCroWNntfTd8O+UejOAF59xeN5WGZK27ilexXV2e2X/cbUhG3L8sfEKaz0/sw==} + /mailparser@3.6.7: + resolution: {integrity: sha512-/3x8HW70DNehw+3vdOPKdlLuxOHoWcGB5jfx5vJ5XUbY9/2jUJbrrhda5Si8Dj/3w08U0y5uGAkqs5+SPTPKoA==} dependencies: encoding-japanese: 2.0.0 he: 1.2.0 @@ -8729,7 +8856,7 @@ packages: libmime: 5.2.1 linkify-it: 5.0.0 mailsplit: 5.4.0 - nodemailer: 6.9.8 + nodemailer: 6.9.9 tlds: 1.248.0 dev: false @@ -8935,11 +9062,15 @@ packages: /minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + requiresBuild: true dev: false + optional: true /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + requiresBuild: true dev: false + optional: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -9062,16 +9193,6 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /nearley@2.20.1: - resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==} - hasBin: true - dependencies: - commander: 2.20.3 - moo: 0.5.2 - railroad-diagrams: 1.0.0 - randexp: 0.4.6 - dev: false - /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -9102,35 +9223,27 @@ packages: dependencies: whatwg-url: 5.0.0 + /node-gyp-build-optional-packages@5.1.1: + resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} + hasBin: true + requiresBuild: true + dependencies: + detect-libc: 2.0.2 + dev: false + optional: true + /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true - - /node-rsa@1.1.1: - resolution: {integrity: sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==} - dependencies: - asn1: 0.2.6 - dev: false - - /nodemailer@6.9.3: - resolution: {integrity: sha512-fy9v3NgTzBngrMFkDsKEj0r02U7jm6XfC3b52eoNV+GCrGj+s8pt5OqhiJdWKuw51zCTdiNR/IUD1z33LIIGpg==} - engines: {node: '>=6.0.0'} - dev: false - /nodemailer@6.9.8: - resolution: {integrity: sha512-cfrYUk16e67Ks051i4CntM9kshRYei1/o/Gi8K1d+R34OIs21xdFnW7Pt7EucmVKA0LKtqUGNcjMZ7ehjl49mQ==} + /nodemailer@6.9.9: + resolution: {integrity: sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA==} engines: {node: '>=6.0.0'} dev: false - /nofilter@1.0.4: - resolution: {integrity: sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==} - engines: {node: '>=8'} - dev: false - /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -9453,7 +9566,7 @@ packages: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /parent-module@1.0.1: @@ -9495,14 +9608,22 @@ packages: engines: {node: '>=0.10.0'} dev: true - /parse5-htmlparser2-tree-adapter@6.0.1: - resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + /parse5-htmlparser2-tree-adapter@7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} dependencies: - parse5: 6.0.1 + domhandler: 5.0.3 + parse5: 7.1.2 dev: false /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: true + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: false /parseley@0.12.1: resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} @@ -9511,13 +9632,6 @@ packages: peberminta: 0.9.0 dev: false - /parseley@0.7.0: - resolution: {integrity: sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==} - dependencies: - moo: 0.5.2 - nearley: 2.20.1 - dev: false - /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -9538,7 +9652,7 @@ packages: resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /path-exists@3.0.0: @@ -9691,7 +9805,6 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -9841,8 +9954,8 @@ packages: display-notification: 2.0.0 fixpack: 4.0.0 get-port: 5.1.1 - mailparser: 3.6.6 - nodemailer: 6.9.3 + mailparser: 3.6.7 + nodemailer: 6.9.9 open: 7.4.2 p-event: 4.2.0 p-wait-for: 3.2.0 @@ -10068,18 +10181,6 @@ packages: engines: {node: '>=8'} dev: true - /railroad-diagrams@1.0.0: - resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==} - dev: false - - /randexp@0.4.6: - resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==} - engines: {node: '>=0.12'} - dependencies: - discontinuous-range: 1.0.0 - ret: 0.1.15 - dev: false - /random-bytes@1.0.0: resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} engines: {node: '>= 0.8'} @@ -10354,6 +10455,7 @@ packages: /ret@0.1.15: resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} engines: {node: '>=0.12'} + dev: true /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -10496,12 +10598,6 @@ packages: parseley: 0.12.1 dev: false - /selderee@0.6.0: - resolution: {integrity: sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==} - dependencies: - parseley: 0.7.0 - dev: false - /semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} dev: true @@ -10542,7 +10638,7 @@ packages: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case-first: 2.0.2 dev: true @@ -10710,7 +10806,7 @@ packages: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /snapdragon-node@2.1.1: @@ -11255,6 +11351,11 @@ packages: hasBin: true dev: false + /tlds@1.249.0: + resolution: {integrity: sha512-PfcE+oqaEhs0U3RDNg4uGg37793cGvlK6+aLAetwR0ImFyV3R2ts1KvU2RfJdtoLn7IFnUEftFFz4br5Wr3caA==} + hasBin: true + dev: false + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -11345,7 +11446,7 @@ packages: engines: {node: '>= 14.0.0'} dev: false - /ts-jest@27.1.5(@babel/core@7.23.7)(@types/jest@27.5.2)(jest@27.5.1)(typescript@4.5.4): + /ts-jest@27.1.5(@babel/core@7.23.9)(@types/jest@27.5.2)(jest@27.5.1)(typescript@4.5.4): resolution: {integrity: sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true @@ -11366,7 +11467,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.23.9 '@types/jest': 27.5.2 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -11677,6 +11778,10 @@ packages: resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} dev: false + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: false + /unfetch@4.2.0: resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} dev: false @@ -11735,7 +11840,6 @@ packages: browserslist: 4.22.2 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -12030,8 +12134,8 @@ packages: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 assert-never: 1.2.1 babel-walk: 3.0.0-canary-5 dev: false @@ -12169,7 +12273,6 @@ packages: /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} diff --git a/src/routes/elevate/index.ts b/src/routes/elevate/index.ts new file mode 100644 index 000000000..be0a837da --- /dev/null +++ b/src/routes/elevate/index.ts @@ -0,0 +1,47 @@ +import { Router } from 'express'; + +import { asyncWrapper as aw } from '@/utils'; +import { bodyValidator } from '@/validation'; + +import { + elevateVerifyWebauthnHandler, + elevateVerifyWebauthnSchema, + elevateWebauthnHandler, + elevateWebauthnSchema, +} from './webauthn'; + +const router = Router(); + +// TODO add @return payload on success +/** + * POST /elevate/webauthn + * @summary Elevate access for an already signed in user using FIDO2 Webauthn + * @param {ElevateWebauthnSchema} request.body.required + * @return {InvalidRequestError} 400 - The payload is invalid - application/json + * @return {DisabledEndpointError} 404 - The feature is not activated - application/json + * @tags Authentication + */ +router.post( + '/elevate/webauthn', + bodyValidator(elevateWebauthnSchema), + aw(elevateWebauthnHandler) +); + +/** + * POST /elevate/webauthn/verify + * @summary Verfiy FIDO2 Webauthn authentication using public-key cryptography + * @param {ElevateVerifyWebauthnSchema} request.body.required + * @return {SessionPayload} 200 - Signed in successfully - application/json + * @return {InvalidRequestError} 400 - The payload is invalid - application/json + * @return {UnauthorizedError} 401 - Invalid email or password, or user is not verified - application/json + * @return {DisabledEndpointError} 404 - The feature is not activated - application/json + * @tags Authentication + */ +router.post( + '/elevate/webauthn/verify', + bodyValidator(elevateVerifyWebauthnSchema), + aw(elevateVerifyWebauthnHandler) +); + +const elevateRouter = router; +export { elevateRouter }; diff --git a/src/routes/elevate/webauthn.ts b/src/routes/elevate/webauthn.ts new file mode 100644 index 000000000..4b7bfac0c --- /dev/null +++ b/src/routes/elevate/webauthn.ts @@ -0,0 +1,128 @@ +import { sendError } from '@/errors'; +import { + ENV, + getUser, + getUserByEmail, + performWebAuthn, + verifyWebAuthn, +} from '@/utils'; +import { RequestHandler } from 'express'; + +import { SignInResponse } from '@/types'; +import { Joi, email } from '@/validation'; + +import { + AuthenticationResponseJSON, + PublicKeyCredentialRequestOptionsJSON, +} from '@simplewebauthn/types'; + +export type ElevateWebAuthnRequestBody = { email: string }; +export type ElevateWebAuthnResponseBody = PublicKeyCredentialRequestOptionsJSON; + +export const elevateWebauthnSchema = Joi.object({ + email: email.required(), +}).meta({ className: 'ElevateWebauthnSchema' }); + +export const elevateWebauthnHandler: RequestHandler< + {}, + ElevateWebAuthnResponseBody, + ElevateWebAuthnRequestBody +> = async (req, res) => { + if (!ENV.AUTH_WEBAUTHN_ENABLED) { + return sendError(res, 'disabled-endpoint'); + } + + const { userId } = req.auth as RequestAuth; + + const userRequestAuth = await getUser({ userId }); + + if (!userRequestAuth) { + return sendError(res, 'user-not-found'); + } + + const { email } = req.body; + + const user = await getUserByEmail(email); + + // ? Do we know to let anyone know if the user doesn't exist? + if (!user) { + return sendError(res, 'user-not-found'); + } + + if (user.id !== userRequestAuth.id) { + return sendError(res, 'bad-request'); + } + + if (user.disabled) { + return sendError(res, 'disabled-user'); + } + + if (ENV.AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED && !user.emailVerified) { + return sendError(res, 'unverified-user'); + } + + const options = await performWebAuthn(user.id); + + return res.send(options); +}; + +export type ElevateVerifyWebAuthnRequestBody = { + credential: AuthenticationResponseJSON; + email: string; +}; + +export type ElevateVerifyWebAuthnResponseBody = SignInResponse; + +export const elevateVerifyWebauthnSchema = + Joi.object({ + email: email.required(), + credential: Joi.object().required(), + }).meta({ className: 'ElevateVerifyWebauthnSchema' }); + +export const elevateVerifyWebauthnHandler: RequestHandler< + {}, + ElevateVerifyWebAuthnResponseBody, + ElevateVerifyWebAuthnRequestBody +> = async (req, res) => { + if (!ENV.AUTH_WEBAUTHN_ENABLED) { + return sendError(res, 'disabled-endpoint'); + } + + const { userId } = req.auth as RequestAuth; + + const userRequestAuth = await getUser({ userId }); + + if (!userRequestAuth) { + return sendError(res, 'user-not-found'); + } + + const { credential, email } = req.body; + + const user = await getUserByEmail(email); + + if (!user) { + return sendError(res, 'user-not-found'); + } + + if (user.id !== userRequestAuth.id) { + return sendError(res, 'bad-request'); + } + + if (user.disabled) { + return sendError(res, 'disabled-user'); + } + + if (ENV.AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED && !user.emailVerified) { + return sendError(res, 'unverified-user'); + } + + await verifyWebAuthn( + user.id, + credential, + (code, payload) => sendError(res, code, payload), + (signInResponse) => res.send(signInResponse), + { + [`x-hasura-auth-elevated`]: user.id, + } + ); +}; diff --git a/src/routes/index.ts b/src/routes/index.ts index 3fd43310e..a4602f761 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -5,6 +5,7 @@ import { mfaRouter } from './mfa'; import { oauthProviders } from './oauth'; import { patRouter } from './pat'; import { signInRouter } from './signin'; +import { elevateRouter } from './elevate'; import { signOutRouter } from './signout'; import { signUpRouter } from './signup'; import { tokenRouter } from './token'; @@ -28,6 +29,7 @@ router.get('/version', (_req, res) => router.use(signUpRouter); router.use(signInRouter); router.use(signOutRouter); +router.use(elevateRouter); router.use(userRouter); router.use(mfaRouter); router.use(tokenRouter); diff --git a/src/routes/signin/webauthn.ts b/src/routes/signin/webauthn.ts index 5fd6d1f99..675465604 100644 --- a/src/routes/signin/webauthn.ts +++ b/src/routes/signin/webauthn.ts @@ -1,24 +1,14 @@ import { sendError } from '@/errors'; -import { - ENV, - getSignInResponse, - getUserByEmail, - gqlSdk, - getWebAuthnRelyingParty, - getCurrentChallenge, -} from '@/utils'; +import { ENV, getUserByEmail, performWebAuthn, verifyWebAuthn } from '@/utils'; import { RequestHandler } from 'express'; +import { SignInResponse } from '@/types'; +import { Joi, email } from '@/validation'; + import { - generateAuthenticationOptions, - verifyAuthenticationResponse, -} from '@simplewebauthn/server'; -import { - AuthenticationCredentialJSON, + AuthenticationResponseJSON, PublicKeyCredentialRequestOptionsJSON, -} from '@simplewebauthn/typescript-types'; -import { email, Joi } from '@/validation'; -import { SignInResponse } from '@/types'; +} from '@simplewebauthn/types'; export type SignInWebAuthnRequestBody = { email: string }; export type SignInWebAuthnResponseBody = PublicKeyCredentialRequestOptionsJSON; @@ -54,30 +44,13 @@ export const signInWebauthnHandler: RequestHandler< return sendError(res, 'unverified-user'); } - const { authUserSecurityKeys } = await gqlSdk.getUserSecurityKeys({ - id: user.id, - }); - - const options = generateAuthenticationOptions({ - rpID: getWebAuthnRelyingParty(), - userVerification: 'preferred', - timeout: ENV.AUTH_WEBAUTHN_ATTESTATION_TIMEOUT, - allowCredentials: authUserSecurityKeys.map((securityKey) => ({ - id: Buffer.from(securityKey.credentialId, 'base64url'), - type: 'public-key', - })), - }); - - await gqlSdk.updateUserChallenge({ - userId: user.id, - challenge: options.challenge, - }); + const options = await performWebAuthn(user.id); return res.send(options); }; export type SignInVerifyWebAuthnRequestBody = { - credential: AuthenticationCredentialJSON; + credential: AuthenticationResponseJSON; email: string; }; @@ -114,65 +87,10 @@ export const signInVerifyWebauthnHandler: RequestHandler< return sendError(res, 'unverified-user'); } - const expectedChallenge = await getCurrentChallenge(user.id); - - const { authUserSecurityKeys } = await gqlSdk.getUserSecurityKeys({ - id: user.id, - }); - const securityKey = authUserSecurityKeys?.find( - ({ credentialId }) => credentialId === credential.id + await verifyWebAuthn( + user.id, + credential, + (code, payload) => sendError(res, code, payload), + (signInResponse) => res.send(signInResponse) ); - - if (!securityKey) { - return sendError(res, 'invalid-request'); - } - - const securityKeyDevice = { - counter: securityKey.counter, - credentialID: Buffer.from(securityKey.credentialId, 'base64url'), - credentialPublicKey: Buffer.from( - securityKey.credentialPublicKey.substr(2), - 'hex' - ), - }; - - let verification; - try { - verification = verifyAuthenticationResponse({ - credential, - expectedChallenge, - expectedOrigin: ENV.AUTH_WEBAUTHN_RP_ORIGINS, - expectedRPID: getWebAuthnRelyingParty(), - authenticator: securityKeyDevice, - requireUserVerification: true, - }); - } catch (e) { - const error = e as Error; - return sendError(res, 'invalid-webauthn-security-key', { - customMessage: error.message, - }); - } - - const { verified } = verification; - - if (!verified) { - return sendError(res, 'invalid-webauthn-verification'); - } - - const { authenticationInfo } = verification; - const { newCounter } = authenticationInfo; - - if (securityKey.counter != newCounter) { - await gqlSdk.updateUserSecurityKey({ - id: securityKey.id, - counter: newCounter, - }); - } - - const signInResponse = await getSignInResponse({ - userId: user.id, - checkMFA: false, - }); - - return res.send(signInResponse); }; diff --git a/src/routes/signup/webauthn/verify.ts b/src/routes/signup/webauthn/verify.ts index bb62b8324..6fcef456e 100644 --- a/src/routes/signup/webauthn/verify.ts +++ b/src/routes/signup/webauthn/verify.ts @@ -10,7 +10,8 @@ import { } from '@/utils'; import { RequestHandler } from 'express'; -import { RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; +import { RegistrationResponseJSON } from '@simplewebauthn/types'; + import { Joi, redirectTo } from '@/validation'; import { EMAIL_TYPES, @@ -20,7 +21,7 @@ import { import { sendEmail } from '@/email'; export type SignUpVerifyWebAuthnRequestBody = { - credential: RegistrationCredentialJSON; + credential: RegistrationResponseJSON; options: Pick & { nickname?: string; }; diff --git a/src/routes/user/webauthn.ts b/src/routes/user/webauthn.ts index 0cbcb75d0..e8943c4a4 100644 --- a/src/routes/user/webauthn.ts +++ b/src/routes/user/webauthn.ts @@ -1,9 +1,10 @@ import { RequestHandler } from 'express'; + +import { generateRegistrationOptions } from '@simplewebauthn/server'; import { + RegistrationResponseJSON, PublicKeyCredentialCreationOptionsJSON, - RegistrationCredentialJSON, -} from '@simplewebauthn/typescript-types'; -import { generateRegistrationOptions } from '@simplewebauthn/server'; +} from '@simplewebauthn/types'; import { Joi } from '@/validation'; import { sendError, sendUnspecifiedError } from '@/errors'; @@ -63,7 +64,7 @@ export const addSecurityKeyHandler: RequestHandler< }; export type VerifySecurityKeyRequestBody = { - credential: RegistrationCredentialJSON; + credential: RegistrationResponseJSON; nickname?: string; }; diff --git a/src/utils/__generated__/graphql-request.ts b/src/utils/__generated__/graphql-request.ts index 70af2c9e4..27f05a81b 100644 --- a/src/utils/__generated__/graphql-request.ts +++ b/src/utils/__generated__/graphql-request.ts @@ -525,13 +525,6 @@ export type AuthRefreshTokenTypes_Mutation_Response = { returning: Array; }; -/** input type for inserting object relation for remote table "auth.refresh_token_types" */ -export type AuthRefreshTokenTypes_Obj_Rel_Insert_Input = { - data: AuthRefreshTokenTypes_Insert_Input; - /** upsert condition */ - on_conflict?: InputMaybe; -}; - /** on_conflict condition type for table "auth.refresh_token_types" */ export type AuthRefreshTokenTypes_On_Conflict = { constraint: AuthRefreshTokenTypes_Constraint; @@ -601,8 +594,6 @@ export type AuthRefreshTokens = { id: Scalars['uuid']; metadata?: Maybe; refreshTokenHash?: Maybe; - /** An object relationship */ - refresh_token_type: AuthRefreshTokenTypes; type: AuthRefreshTokenTypes_Enum; /** An object relationship */ user: Users; @@ -677,7 +668,6 @@ export type AuthRefreshTokens_Bool_Exp = { id?: InputMaybe; metadata?: InputMaybe; refreshTokenHash?: InputMaybe; - refresh_token_type?: InputMaybe; type?: InputMaybe; user?: InputMaybe; userId?: InputMaybe; @@ -711,7 +701,6 @@ export type AuthRefreshTokens_Insert_Input = { id?: InputMaybe; metadata?: InputMaybe; refreshTokenHash?: InputMaybe; - refresh_token_type?: InputMaybe; type?: InputMaybe; user?: InputMaybe; userId?: InputMaybe; @@ -778,7 +767,6 @@ export type AuthRefreshTokens_Order_By = { id?: InputMaybe; metadata?: InputMaybe; refreshTokenHash?: InputMaybe; - refresh_token_type?: InputMaybe; type?: InputMaybe; user?: InputMaybe; userId?: InputMaybe; diff --git a/src/utils/jwt/generate.ts b/src/utils/jwt/generate.ts index 2f05a327e..5338c4b77 100644 --- a/src/utils/jwt/generate.ts +++ b/src/utils/jwt/generate.ts @@ -33,7 +33,8 @@ export const sign = async ({ * @param jwt if true, add a 'x-hasura-' prefix to the property names, and stringifies the values (required by Hasura) */ const generateHasuraClaims = async ( - user: UserFieldsFragment + user: UserFieldsFragment, + extraClaims?: { [key: string]: ClaimValueType }, ): Promise<{ [key: string]: ClaimValueType; }> => { @@ -47,6 +48,7 @@ const generateHasuraClaims = async ( const customClaims = await generateCustomClaims(user.id); return { ...customClaims, + ...extraClaims, [`x-hasura-allowed-roles`]: allowedRoles, [`x-hasura-default-role`]: user.defaultRole, [`x-hasura-user-id`]: user.id, @@ -57,7 +59,8 @@ const generateHasuraClaims = async ( * Create JWT ENV. */ export const createHasuraAccessToken = async ( - user: UserFieldsFragment + user: UserFieldsFragment, + extraClaims?: { [key: string]: ClaimValueType }, ): Promise => { const namespace = ENV.HASURA_GRAPHQL_JWT_SECRET.claims_namespace || @@ -65,7 +68,7 @@ export const createHasuraAccessToken = async ( return sign({ payload: { - [namespace]: await generateHasuraClaims(user), + [namespace]: await generateHasuraClaims(user, extraClaims), }, user, }); diff --git a/src/utils/session.ts b/src/utils/session.ts index 241520dd9..0701c6130 100644 --- a/src/utils/session.ts +++ b/src/utils/session.ts @@ -1,4 +1,4 @@ -import { Session, SignInResponse } from '@/types'; +import { ClaimValueType, Session, SignInResponse } from '@/types'; import { v4 as uuidv4 } from 'uuid'; import { UserFieldsFragment } from './__generated__/graphql-request'; import { ENV } from './env'; @@ -17,9 +17,11 @@ import { getUser } from './user'; export const getNewOrUpdateCurrentSession = async ({ user, currentRefreshToken, + extraClaims, }: { user: UserFieldsFragment; currentRefreshToken?: string; + extraClaims?: { [key: string]: ClaimValueType }, }): Promise => { // update user's last seen gqlSdk.updateUser({ @@ -29,7 +31,7 @@ export const getNewOrUpdateCurrentSession = async ({ }, }); const sessionUser = await getUser({ userId: user.id }); - const accessToken = await createHasuraAccessToken(user); + const accessToken = await createHasuraAccessToken(user, extraClaims); const { refreshToken, id: refreshTokenId } = (currentRefreshToken && (await updateRefreshTokenExpiry(currentRefreshToken))) || @@ -46,9 +48,11 @@ export const getNewOrUpdateCurrentSession = async ({ export const getSignInResponse = async ({ userId, checkMFA, + extraClaims, }: { userId: string; checkMFA: boolean; + extraClaims?: { [key: string]: ClaimValueType }, }): Promise => { const { user } = await gqlSdk.user({ id: userId, @@ -74,7 +78,7 @@ export const getSignInResponse = async ({ }, }; } - const session = await getNewOrUpdateCurrentSession({ user }); + const session = await getNewOrUpdateCurrentSession({ user, extraClaims }); return { session, mfa: null, diff --git a/src/utils/webauthn.ts b/src/utils/webauthn.ts index 7f26d263b..df36f8179 100644 --- a/src/utils/webauthn.ts +++ b/src/utils/webauthn.ts @@ -1,13 +1,23 @@ -import { User } from '@/types'; +import { ClaimValueType, SignInResponse, User } from '@/types'; +import { type Response } from 'express'; + import { VerifiedRegistrationResponse, + generateAuthenticationOptions, + verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server'; -import { RegistrationCredentialJSON } from '@simplewebauthn/typescript-types'; +import { + AuthenticationResponseJSON, + RegistrationResponseJSON, +} from '@simplewebauthn/types'; + +import { ERRORS } from '@/errors'; +import { AuthUserSecurityKeys_Insert_Input } from './__generated__/graphql-request'; import { ENV } from './env'; import { gqlSdk } from './gql-sdk'; -import { AuthUserSecurityKeys_Insert_Input } from './__generated__/graphql-request'; +import { getSignInResponse } from './session'; export const getWebAuthnRelyingParty = () => { if (ENV.AUTH_WEBAUTHN_RP_ID) { @@ -28,14 +38,14 @@ export const getCurrentChallenge = async (id: string) => { export const verifyWebAuthnRegistration = async ( { id }: Pick, - credential: RegistrationCredentialJSON, + response: RegistrationResponseJSON, nickname?: string ) => { const expectedChallenge = await getCurrentChallenge(id); let verification: VerifiedRegistrationResponse; try { verification = await verifyRegistrationResponse({ - credential, + response, expectedChallenge, expectedOrigin: ENV.AUTH_WEBAUTHN_RP_ORIGINS, expectedRPID: getWebAuthnRelyingParty(), @@ -61,9 +71,9 @@ export const verifyWebAuthnRegistration = async ( } = registrationInfo; const newSecurityKey: AuthUserSecurityKeys_Insert_Input = { - credentialId: credentialId.toString('base64url'), + credentialId: Buffer.from(credentialId).toString('base64url'), credentialPublicKey: Buffer.from( - '\\x' + credentialPublicKey.toString('hex') + '\\x' + Buffer.from(credentialPublicKey).toString('hex') ).toString(), counter, nickname, @@ -91,3 +101,104 @@ export const verifyWebAuthnRegistration = async ( return insertAuthUserSecurityKey.id; }; + +export const performWebAuthn = async (userId: string) => { + const { authUserSecurityKeys } = await gqlSdk.getUserSecurityKeys({ + id: userId, + }); + + const options = generateAuthenticationOptions({ + rpID: getWebAuthnRelyingParty(), + userVerification: 'preferred', + timeout: ENV.AUTH_WEBAUTHN_ATTESTATION_TIMEOUT, + allowCredentials: authUserSecurityKeys.map((securityKey) => ({ + id: Buffer.from(securityKey.credentialId, 'base64url'), + type: 'public-key', + })), + }); + + await gqlSdk.updateUserChallenge({ + userId: userId, + challenge: options.challenge, + }); + + return options; +}; + +export const verifyWebAuthn = async ( + userId: string, + response: AuthenticationResponseJSON, + onError: ( + code: keyof typeof ERRORS, + payload?: { customMessage?: string; redirectTo?: string } + ) => void | Response, + onSuccess: (signInResponse: SignInResponse) => Response, + extraClaims?: { + [key: string]: ClaimValueType; + } +) => { + const expectedChallenge = await getCurrentChallenge(userId); + + const { authUserSecurityKeys } = await gqlSdk.getUserSecurityKeys({ + id: userId, + }); + + const securityKey = authUserSecurityKeys?.find( + ({ credentialId }) => credentialId === response.id + ); + + if (!securityKey) { + return onError('invalid-request'); + } + + const securityKeyDevice = { + counter: securityKey.counter, + credentialID: Buffer.from(securityKey.credentialId, 'base64url'), + credentialPublicKey: Buffer.from( + securityKey.credentialPublicKey.substr(2), + 'hex' + ), + }; + + let verification; + try { + verification = await verifyAuthenticationResponse({ + response, + expectedChallenge, + expectedOrigin: ENV.AUTH_WEBAUTHN_RP_ORIGINS, + expectedRPID: getWebAuthnRelyingParty(), + authenticator: securityKeyDevice, + requireUserVerification: true, + }); + } catch (e) { + const error = e as Error; + + return onError('invalid-webauthn-security-key', { + customMessage: error.message, + }); + } + + const { verified } = verification; + + if (!verified) { + return onError('invalid-webauthn-verification'); + } + + const { authenticationInfo } = verification; + const { newCounter } = authenticationInfo; + + if (securityKey.counter != newCounter) { + await gqlSdk.updateUserSecurityKey({ + id: securityKey.id, + counter: newCounter, + }); + } + + const signInResponse = await getSignInResponse({ + userId: userId, + checkMFA: false, + extraClaims: extraClaims, + }); + + return onSuccess(signInResponse); +}; diff --git a/src/validation/fields.ts b/src/validation/fields.ts index ac24c8a32..fd507ba44 100644 --- a/src/validation/fields.ts +++ b/src/validation/fields.ts @@ -90,7 +90,7 @@ export const redirectTo = Joi.string() // * We allow any sub-path of the client url // * With optional hash and query params if ( - new RegExp(`^${ENV.AUTH_CLIENT_URL}(\/.*)?([?].*)?([#].*)?$`).test(value) + new RegExp(`^${ENV.AUTH_CLIENT_URL}(/.*)?([?].*)?([#].*)?$`).test(value) ) { return value; } diff --git a/test/routes/user/webauthn.test.ts b/test/routes/user/webauthn.test.ts index b27e6efee..e6847ee8f 100644 --- a/test/routes/user/webauthn.test.ts +++ b/test/routes/user/webauthn.test.ts @@ -110,24 +110,19 @@ describe('webauthn', () => { displayName, }, pubKeyCredParams: [ - { alg: -7, type: 'public-key' }, { alg: -8, type: 'public-key' }, - { alg: -36, type: 'public-key' }, - { alg: -37, type: 'public-key' }, - { alg: -38, type: 'public-key' }, - { alg: -39, type: 'public-key' }, + { alg: -7, type: 'public-key' }, { alg: -257, type: 'public-key' }, - { alg: -258, type: 'public-key' }, - { alg: -259, type: 'public-key' }, ], timeout: 60000, attestation: 'indirect', excludeCredentials: [], authenticatorSelection: { requireResidentKey: false, - // residentKey: 'required', + residentKey: 'preferred', userVerification: 'preferred', }, + extensions: { credProps: true }, }); });