From fae5a11bfb3b3e1e7a9397d579b3842eef55eff1 Mon Sep 17 00:00:00 2001 From: Pierre Troger Date: Thu, 8 Feb 2024 01:16:19 -0400 Subject: [PATCH 1/3] signing lib running --- package-lock.json | 137 +++++++ package.json | 3 + packages/signature-verifier/.babelrc | 3 + packages/signature-verifier/.eslintrc.json | 18 + packages/signature-verifier/Makefile | 29 ++ packages/signature-verifier/README.md | 24 ++ packages/signature-verifier/jest.config.ts | 18 + packages/signature-verifier/jest.unit.ts | 9 + packages/signature-verifier/project.json | 24 ++ packages/signature-verifier/src/index.ts | 2 + .../src/lib/__test__/mock.ts | 341 ++++++++++++++++++ .../src/lib/__test__/unit/jwt.spec.ts | 52 +++ .../src/lib/signature/signRequest.ts | 26 ++ .../src/lib/signature/verifySignature.ts | 31 ++ .../signature-verifier/src/lib/types/index.ts | 67 ++++ packages/signature-verifier/tsconfig.json | 20 + packages/signature-verifier/tsconfig.lib.json | 13 + .../signature-verifier/tsconfig.spec.json | 20 + tsconfig.base.json | 1 + 19 files changed, 838 insertions(+) create mode 100644 packages/signature-verifier/.babelrc create mode 100644 packages/signature-verifier/.eslintrc.json create mode 100644 packages/signature-verifier/Makefile create mode 100644 packages/signature-verifier/README.md create mode 100644 packages/signature-verifier/jest.config.ts create mode 100644 packages/signature-verifier/jest.unit.ts create mode 100644 packages/signature-verifier/project.json create mode 100644 packages/signature-verifier/src/index.ts create mode 100644 packages/signature-verifier/src/lib/__test__/mock.ts create mode 100644 packages/signature-verifier/src/lib/__test__/unit/jwt.spec.ts create mode 100644 packages/signature-verifier/src/lib/signature/signRequest.ts create mode 100644 packages/signature-verifier/src/lib/signature/verifySignature.ts create mode 100644 packages/signature-verifier/src/lib/types/index.ts create mode 100644 packages/signature-verifier/tsconfig.json create mode 100644 packages/signature-verifier/tsconfig.lib.json create mode 100644 packages/signature-verifier/tsconfig.spec.json diff --git a/package-lock.json b/package-lock.json index ed3b1eb08..1dbe474ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@nestjs/swagger": "^7.2.0", "@open-policy-agent/opa-wasm": "^1.8.0", "@prisma/client": "^5.7.1", + "@types/jsonwebtoken": "^9.0.5", "axios": "^1.6.7", "bull": "^4.12.1", "caip": "^1.1.0", @@ -35,6 +36,8 @@ "clsx": "^1.2.1", "date-fns": "^3.3.1", "handlebars": "^4.7.8", + "jose": "^5.2.1", + "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "prism-react-renderer": "^2.3.1", "react": "18.2.0", @@ -9982,6 +9985,14 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", + "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", @@ -12095,6 +12106,11 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -14683,6 +14699,14 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -19276,6 +19300,14 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/jose": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.1.tgz", + "integrity": "sha512-qiaQhtQRw6YrOaOj0v59h3R6hUY9NvxBmmnMfKemkqYmBB0tEc97NbLP7ix44VP5p9/0YHG8Vyhzuo5YBNwviA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -19467,6 +19499,57 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsonwebtoken/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -19482,6 +19565,25 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -20046,17 +20148,47 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", "dev": true }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -20068,6 +20200,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "devOptional": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", diff --git a/package.json b/package.json index e203ec1c9..ad1305e84 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "@nestjs/swagger": "^7.2.0", "@open-policy-agent/opa-wasm": "^1.8.0", "@prisma/client": "^5.7.1", + "@types/jsonwebtoken": "^9.0.5", "axios": "^1.6.7", "bull": "^4.12.1", "caip": "^1.1.0", @@ -91,6 +92,8 @@ "clsx": "^1.2.1", "date-fns": "^3.3.1", "handlebars": "^4.7.8", + "jose": "^5.2.1", + "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "prism-react-renderer": "^2.3.1", "react": "18.2.0", diff --git a/packages/signature-verifier/.babelrc b/packages/signature-verifier/.babelrc new file mode 100644 index 000000000..9cbf9798b --- /dev/null +++ b/packages/signature-verifier/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": [["@nrwl/js/babel", { "useBuiltIns": "usage" }]] +} diff --git a/packages/signature-verifier/.eslintrc.json b/packages/signature-verifier/.eslintrc.json new file mode 100644 index 000000000..9d9c0db55 --- /dev/null +++ b/packages/signature-verifier/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/packages/signature-verifier/Makefile b/packages/signature-verifier/Makefile new file mode 100644 index 000000000..5c995e3c7 --- /dev/null +++ b/packages/signature-verifier/Makefile @@ -0,0 +1,29 @@ +TRI_PROJECT_NAME := signature-verifier +TRI_PROJECT_DIR := ./packages/signature-verifier + +# == Code format == + +signature-verifier/format: + npx nx format:write --projects ${TRI_PROJECT_NAME} + +signature-verifier/lint: + npx nx lint ${TRI_PROJECT_NAME} -- --fix + +signature-verifier/format/check: + npx nx format:check --projects ${TRI_PROJECT_NAME} + +signature-verifier/lint/check: + npx nx lint ${TRI_PROJECT_NAME} + +# == Testing == + +signature-verifier/test/type: + npx tsc \ + --project ${TRI_PROJECT_DIR}/tsconfig.lib.json \ + --noEmit + +signature-verifier/test/unit: + npx nx test:unit ${TRI_PROJECT_NAME} -- ${ARGS} + +signature-verifier/test/unit/watch: + make signature-verifier/test/unit ARGS=--watch diff --git a/packages/signature-verifier/README.md b/packages/signature-verifier/README.md new file mode 100644 index 000000000..34c7f8687 --- /dev/null +++ b/packages/signature-verifier/README.md @@ -0,0 +1,24 @@ +# Transaction Request Intent + +[![Transaction Request Intent CI](https://github.com/narval-xyz/narval/actions/workflows/transaction_request_intent_ci.yml/badge.svg?branch=main)](https://github.com/narval-xyz/narval/actions/workflows/transaction_request_intent_ci.yml) + +Library to decode a +[TransactionRequest](https://viem.sh/docs/glossary/types#transactionrequest) +into an object with granular information. + +## Testing + +```bash + make signature-verifier/test/unit + make signature-verifier/test/unit/watch +``` + +## Formatting + +```bash +make signature-verifier/format +make signature-verifier/lint + +make signature-verifier/format/check +make signature-verifier/lint/check +``` diff --git a/packages/signature-verifier/jest.config.ts b/packages/signature-verifier/jest.config.ts new file mode 100644 index 000000000..e121f0c9f --- /dev/null +++ b/packages/signature-verifier/jest.config.ts @@ -0,0 +1,18 @@ +import type { Config } from 'jest' + +const config: Config = { + displayName: 'signature-verifier', + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]sx?$': [ + 'ts-jest', + { + tsconfig: '/tsconfig.spec.json' + } + ] + } +} + +export default config diff --git a/packages/signature-verifier/jest.unit.ts b/packages/signature-verifier/jest.unit.ts new file mode 100644 index 000000000..9376919b3 --- /dev/null +++ b/packages/signature-verifier/jest.unit.ts @@ -0,0 +1,9 @@ +import type { Config } from 'jest' +import sharedConfig from './jest.config' + +const config: Config = { + ...sharedConfig, + testMatch: ['/**/__test__/unit/**/*.spec.ts'] +} + +export default config diff --git a/packages/signature-verifier/project.json b/packages/signature-verifier/project.json new file mode 100644 index 000000000..7b23a4e22 --- /dev/null +++ b/packages/signature-verifier/project.json @@ -0,0 +1,24 @@ +{ + "name": "signature-verifier", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/signature-verifier/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["packages/signature-verifier/**/*.ts"] + } + }, + "test:unit": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "packages/signature-verifier/jest.unit.ts", + "verbose": true + } + } + }, + "tags": [] +} diff --git a/packages/signature-verifier/src/index.ts b/packages/signature-verifier/src/index.ts new file mode 100644 index 000000000..897e2e981 --- /dev/null +++ b/packages/signature-verifier/src/index.ts @@ -0,0 +1,2 @@ +export { sign } from './src/lib/signature/signRequest' +export { verify } from './src/lib/signature/verifySignature' diff --git a/packages/signature-verifier/src/lib/__test__/mock.ts b/packages/signature-verifier/src/lib/__test__/mock.ts new file mode 100644 index 000000000..2ba7f87b3 --- /dev/null +++ b/packages/signature-verifier/src/lib/__test__/mock.ts @@ -0,0 +1,341 @@ +import { RegoInput } from '@app/authz/shared/types/domain.type' +import { + AddressBookAccount, + RegoData, + User, + UserGroup, + Wallet, + WalletGroup +} from '@app/authz/shared/types/entities.types' +import { + AccountClassification, + AccountId, + AccountType, + Action, + Alg, + AssetId, + AuthCredential, + EvaluationRequest, + Request, + TransactionRequest, + UserRole, + hashRequest +} from '@narval/authz-shared' +import { Intents } from 'packages/transaction-request-intent/src/lib/domain' +import { TransferNative } from 'packages/transaction-request-intent/src/lib/intent.types' +import { Address, sha256, toHex } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' + +export const ONE_ETH = BigInt('1000000000000000000') + +export const USDC_TOKEN = { + uid: 'eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + address: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + symbol: 'USDC', + chain_id: 137, + decimals: 6 +} + +/** + * User & User Groups + */ + +export const ROOT_USER: User = { + uid: 'u:root_user', + role: UserRole.ROOT +} + +export const MATT: User = { + uid: 'matt@narval.xyz', + role: UserRole.ADMIN +} + +export const MATT_CREDENTIAL_1: AuthCredential = { + uid: sha256('0xd75D626a116D4a1959fE3bB938B2e7c116A05890'), + alg: Alg.ES256K, + userId: MATT.uid, + pubKey: '0xd75D626a116D4a1959fE3bB938B2e7c116A05890' +} + +export const AAUser: User = { + uid: 'aa@narval.xyz', + role: UserRole.ADMIN +} + +export const AAUser_Credential_1: AuthCredential = { + uid: sha256('0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06'), + userId: AAUser.uid, + alg: Alg.ES256K, + pubKey: '0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06' +} + +export const BBUser: User = { + uid: 'bb@narval.xyz', + role: UserRole.ADMIN +} + +export const BBUser_Credential_1: AuthCredential = { + uid: sha256('0xab88c8785D0C00082dE75D801Fcb1d5066a6311e'), + userId: BBUser.uid, + alg: Alg.ES256K, + pubKey: '0xab88c8785D0C00082dE75D801Fcb1d5066a6311e' +} + +export const DEV_USER_GROUP: UserGroup = { + uid: 'ug:dev-group', + users: [MATT.uid] +} + +export const TREASURY_USER_GROUP: UserGroup = { + uid: 'ug:treasury-group', + users: [BBUser.uid, MATT.uid] +} + +/** + * User<>Authn mapping store + */ + +// Private keys used for USER AUTHN; these are _not_ "wallets" in our system. +export const UNSAFE_PRIVATE_KEY_MATT = '0x5f1049fa330544680cfa495285000d7a597adae224c070ccb9f1dc2d5f9204d1' // 0xd75D626a116D4a1959fE3bB938B2e7c116A05890 +export const UNSAFE_PRIVATE_KEY_AAUSER = '0x2f069925bbd2bc2a9fddeab641dea34f7893dd97013cd6282909897740e07539' // 0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06 +export const UNSAFE_PRIVATE_KEY_BBUSER = '0xa1f1830a6d1765aa1b57ad76731d1c3463658523e11dc853b7af7827549096c3' // 0xab88c8785D0C00082dE75D801Fcb1d5066a6311e + +// User AuthN Address <> UserId mapping; one user can have multiple authn pubkeys +// @deprecated, use Credential store +export const userAddressStore: { [key: string]: string } = { + '0xd75D626a116D4a1959fE3bB938B2e7c116A05890': MATT.uid, + '0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06': AAUser.uid, + '0xab88c8785D0C00082dE75D801Fcb1d5066a6311e': BBUser.uid +} + +export const userCredentialStore: { [key: string]: AuthCredential } = { + '0xd75D626a116D4a1959fE3bB938B2e7c116A05890': MATT_CREDENTIAL_1, + '0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06': AAUser_Credential_1, + '0xab88c8785D0C00082dE75D801Fcb1d5066a6311e': BBUser_Credential_1 +} + +/** + * Wallet & Wallet Groups & Accounts + */ + +// Wallets +export const SHY_ACCOUNT_WALLET: Wallet = { + uid: 'eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + address: '0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + accountType: AccountType.EOA, + assignees: [MATT.uid] +} + +export const PIERRE_WALLET: Wallet = { + uid: 'eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + address: '0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + accountType: AccountType.EOA +} + +export const WALLET_Q: Wallet = { + uid: 'eip155:eoa:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + address: '0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + accountType: AccountType.EOA, + assignees: [MATT.uid] +} + +export const TREASURY_WALLET_X: Wallet = { + uid: 'eip155:eoa:0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', // Prod guild 58 - treasury wallet + address: '0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', + accountType: AccountType.EOA, + assignees: [MATT.uid] +} + +// Wallet Groups + +export const DEV_WALLET_GROUP: WalletGroup = { + uid: 'wg:dev-group', + wallets: [SHY_ACCOUNT_WALLET.uid] +} + +export const TREASURY_WALLET_GROUP: WalletGroup = { + uid: 'wg:treasury-group', + wallets: [TREASURY_WALLET_X.uid] +} + +// Address Book + +export const SHY_ACCOUNT_137: AddressBookAccount = { + uid: 'eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + address: '0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + chainId: 137, + classification: AccountClassification.WALLET +} + +export const SHY_ACCOUNT_1: AddressBookAccount = { + uid: 'eip155:1:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + address: '0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + chainId: 1, + classification: AccountClassification.WALLET +} + +export const ACCOUNT_Q_137: AddressBookAccount = { + uid: 'eip155:137:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + address: '0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + chainId: 137, + classification: AccountClassification.WALLET +} + +export const ACCOUNT_INTERNAL_WXZ_137: AddressBookAccount = { + uid: 'eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3', + address: '0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3', + chainId: 137, + classification: AccountClassification.INTERNAL +} + +export const NATIVE_TRANSFER_INTENT: TransferNative = { + from: TREASURY_WALLET_X.uid as AccountId, + to: ACCOUNT_Q_137.uid as AccountId, + type: Intents.TRANSFER_NATIVE, + amount: toHex(ONE_ETH), + token: 'eip155:1/slip44:60' as AssetId // Caip19 for ETH +} + +export const ERC20_TRANSFER_TX_REQUEST: TransactionRequest = { + from: TREASURY_WALLET_X.address as Address, + to: '0x031d8C0cA142921c459bCB28104c0FF37928F9eD' as Address, + chainId: ACCOUNT_Q_137.chainId, + data: '0xa9059cbb000000000000000000000000031d8c0ca142921c459bcb28104c0ff37928f9ed000000000000000000000000000000000000000000005ab7f55035d1e7b4fe6d', + nonce: 192, + type: '2' +} + +export const NATIVE_TRANSFER_TX_REQUEST: TransactionRequest = { + from: TREASURY_WALLET_X.address as Address, + to: ACCOUNT_Q_137.address as Address, + chainId: ACCOUNT_Q_137.chainId, + value: toHex(ONE_ETH), + data: '0x00000000', + nonce: 192, + type: '2' +} + +export const REGO_REQUEST: RegoInput = { + action: Action.SIGN_TRANSACTION, + transactionRequest: NATIVE_TRANSFER_TX_REQUEST, + intent: NATIVE_TRANSFER_INTENT, + resource: { + uid: TREASURY_WALLET_X.uid + }, + principal: MATT_CREDENTIAL_1, + approvals: [], + transfers: [] +} + +export const mockEntityData: RegoData = { + entities: { + users: { + [ROOT_USER.uid]: ROOT_USER, + [MATT.uid]: MATT, + [AAUser.uid]: AAUser, + [BBUser.uid]: BBUser + }, + userGroups: { + [DEV_USER_GROUP.uid]: DEV_USER_GROUP, + [TREASURY_USER_GROUP.uid]: TREASURY_USER_GROUP + }, + wallets: { + [SHY_ACCOUNT_WALLET.uid]: SHY_ACCOUNT_WALLET, + [PIERRE_WALLET.uid]: PIERRE_WALLET, + [WALLET_Q.uid]: WALLET_Q, + [TREASURY_WALLET_X.uid]: TREASURY_WALLET_X + }, + walletGroups: { + [DEV_WALLET_GROUP.uid]: DEV_WALLET_GROUP, + [TREASURY_WALLET_GROUP.uid]: TREASURY_WALLET_GROUP + }, + addressBook: { + [SHY_ACCOUNT_137.uid]: SHY_ACCOUNT_137, + [SHY_ACCOUNT_1.uid]: SHY_ACCOUNT_1, + [ACCOUNT_INTERNAL_WXZ_137.uid]: ACCOUNT_INTERNAL_WXZ_137, + [ACCOUNT_Q_137.uid]: ACCOUNT_Q_137 + }, + tokens: {} + } +} + +// stub out the actual tx request & signature +// This is what would be the initial input from the external service +export const generateInboundRequest = async (): Promise => { + const txRequest = NATIVE_TRANSFER_TX_REQUEST + const request: Request = { + action: Action.SIGN_TRANSACTION, + nonce: 'random-nonce-111', + transactionRequest: txRequest, + resourceId: TREASURY_WALLET_X.uid + } + + const signatureMatt = await privateKeyToAccount(UNSAFE_PRIVATE_KEY_MATT).signMessage({ + message: hashRequest(request) + }) + // 0xe24d097cea880a40f8be2cf42f497b9fbda5f9e4a31b596827e051d78dce75c032fa7e5ee3046f7c6f116e5b98cb8d268fa9b9d222ff44719e2ec2a0d9159d0d1c + const approvalSigAAUser = await privateKeyToAccount(UNSAFE_PRIVATE_KEY_AAUSER).signMessage({ + message: hashRequest(request) + }) + // 0x48510e3b74799b8e8f4e01aba0d196e18f66d86a62ae91abf5b89be9391c15661c7d29ee4654a300ed6db977da512475ed5a39f70f677e23d1b2f53c1554d0dd1b + const approvalSigBBUser = await privateKeyToAccount(UNSAFE_PRIVATE_KEY_BBUSER).signMessage({ + message: hashRequest(request) + }) + // 0xcc645f43d8df80c4deeb2e60a8c0c15d58586d2c29ea7c85208cea81d1c47cbd787b1c8473dde70c3a7d49f573e491223107933257b2b99ecc4806b7cc16848d1c + + return { + authentication: { + sig: signatureMatt, + alg: Alg.ES256K, + pubKey: '0xd75D626a116D4a1959fE3bB938B2e7c116A05890' + }, + request, + approvals: [ + { + sig: approvalSigAAUser, + alg: Alg.ES256K, + pubKey: '0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06' + }, + { + sig: approvalSigBBUser, + alg: Alg.ES256K, + pubKey: '0xab88c8785D0C00082dE75D801Fcb1d5066a6311e' + } + ] + } +} +/** + * Sample API POST body for POST /evaluation that does the same thing as `generateInboundRequest + { + "authentication": { + "sig": "0xe24d097cea880a40f8be2cf42f497b9fbda5f9e4a31b596827e051d78dce75c032fa7e5ee3046f7c6f116e5b98cb8d268fa9b9d222ff44719e2ec2a0d9159d0d1c", + "alg": "ES256K", + "pubKey": "0xd75D626a116D4a1959fE3bB938B2e7c116A05890" + }, + "approvals": [ + { + "sig": "0x48510e3b74799b8e8f4e01aba0d196e18f66d86a62ae91abf5b89be9391c15661c7d29ee4654a300ed6db977da512475ed5a39f70f677e23d1b2f53c1554d0dd1b", + "alg": "ES256K", + "pubKey": "0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06" + }, + { + "sig": "0xcc645f43d8df80c4deeb2e60a8c0c15d58586d2c29ea7c85208cea81d1c47cbd787b1c8473dde70c3a7d49f573e491223107933257b2b99ecc4806b7cc16848d1c", + "alg": "ES256K", + "pubKey": "0xab88c8785D0C00082dE75D801Fcb1d5066a6311e" + } + ], + "request": { + "action": "signTransaction", + "transactionRequest": { + "from": "0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b", + "to": "0x031d8C0cA142921c459bCB28104c0FF37928F9eD", + "chainId": "137", + "data": "0xa9059cbb000000000000000000000000031d8c0ca142921c459bcb28104c0ff37928f9ed000000000000000000000000000000000000000000005ab7f55035d1e7b4fe6d", + "nonce": 192, + "type": "2" + }, + "resourceId": "eip155:eoa:0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b" + } +} + + */ diff --git a/packages/signature-verifier/src/lib/__test__/unit/jwt.spec.ts b/packages/signature-verifier/src/lib/__test__/unit/jwt.spec.ts new file mode 100644 index 000000000..69e895e86 --- /dev/null +++ b/packages/signature-verifier/src/lib/__test__/unit/jwt.spec.ts @@ -0,0 +1,52 @@ +import { Action, Request, hashRequest } from '@narval/authz-shared' +import { exportPKCS8, exportSPKI, generateKeyPair } from 'jose' +import { sign } from '../../signature/signRequest' +import { verify } from '../../signature/verifySignature' +import { SignatureInput, VerificationInput } from '../../types' +import { AAUser, AAUser_Credential_1 } from '../mock' + +describe('JWT Signing and Verification', () => { + it('should sign and verify a request successfully', async () => { + const request: Request = { + action: Action.CREATE_ORGANIZATION, + nonce: 'random-nonce-111', + organization: { + uid: AAUser.uid, + credential: AAUser_Credential_1 + } + } + + const algorithm = AAUser_Credential_1.alg + const kid = 'test-kid' + + const { publicKey, privateKey } = await generateKeyPair(algorithm, { crv: 'P-256' }) + + const privateKeyPEM = await exportPKCS8(privateKey) + const publicKeyPEM = await exportSPKI(publicKey) + + const hash = hashRequest(request) + + const signingInput: SignatureInput = { + request, + privateKey: privateKeyPEM, + algorithm, + kid + } + + const jwt = await sign(signingInput) + + console.log('Public Key PEM:', publicKeyPEM) + + const verificationInput: VerificationInput = { + rawToken: jwt, + publicKey: publicKeyPEM, + request, + algorithm, + kid + } + + const result = await verify(verificationInput) + + expect(result).toEqual({ requestHash: hash, iat: expect.any(Number), exp: expect.any(Number) }) + }) +}) diff --git a/packages/signature-verifier/src/lib/signature/signRequest.ts b/packages/signature-verifier/src/lib/signature/signRequest.ts new file mode 100644 index 000000000..2431c262e --- /dev/null +++ b/packages/signature-verifier/src/lib/signature/signRequest.ts @@ -0,0 +1,26 @@ +import { hashRequest } from '@narval/authz-shared' +import { SignJWT, importPKCS8 } from 'jose' +import { SignatureInput } from '../types' + +const DEF_EXP_TIME = '2h' + +/** + * Signs a request using the provided private key and algorithm. + * + * @param {SignatureInput} signingInput - The input required to sign a request. + * @returns {Promise} A promise that resolves with the signed JWT. + */ +export async function sign(signingInput: SignatureInput): Promise { + const { request, privateKey, algorithm, kid } = signingInput + + const requestHash = hashRequest(request) + const privateKeyObj = await importPKCS8(privateKey, algorithm) + + const jwt = await new SignJWT({ requestHash }) + .setProtectedHeader({ alg: algorithm, kid }) + .setIssuedAt() + .setExpirationTime(DEF_EXP_TIME) + .sign(privateKeyObj) + + return jwt +} diff --git a/packages/signature-verifier/src/lib/signature/verifySignature.ts b/packages/signature-verifier/src/lib/signature/verifySignature.ts new file mode 100644 index 000000000..060bc2bb7 --- /dev/null +++ b/packages/signature-verifier/src/lib/signature/verifySignature.ts @@ -0,0 +1,31 @@ +import { hashRequest } from '@narval/authz-shared' +import { JWTPayload, importSPKI, jwtVerify } from 'jose' +import { Payload, VerificationInput } from '../types' + +function isPayload(payload: JWTPayload): payload is Payload { + return ( + 'requestHash' in payload && + typeof payload.requestHash === 'string' && + 'iat' in payload && + typeof payload.iat === 'number' + ) +} +export async function verify(input: VerificationInput): Promise { + const { rawToken, request, algorithm, publicKey } = input + const publicKeyObj = await importSPKI(publicKey, algorithm) + + const { payload } = await jwtVerify(rawToken, publicKeyObj, { + algorithms: [algorithm] + }) + + if (!isPayload(payload)) { + throw new Error('Invalid payload') + } + + const requestHash = hashRequest(request) + if (payload.requestHash !== requestHash) { + throw new Error('Request hash mismatch') + } + + return payload +} diff --git a/packages/signature-verifier/src/lib/types/index.ts b/packages/signature-verifier/src/lib/types/index.ts new file mode 100644 index 000000000..8af702bfd --- /dev/null +++ b/packages/signature-verifier/src/lib/types/index.ts @@ -0,0 +1,67 @@ +import { Alg, Request } from '@narval/authz-shared' + +export type AlgorithmParameter = { + kty: 'EC' | 'RSA' + crv?: string +} + +/** + * Defines the header of our JWT. + * + * @param {Alg} alg - The algorithm used to sign the JWT. It contains ES256K which is not natively supported + * by the jsonwebtoken package + * @param {string} [kid] - The key ID to identify the signing key. + */ +type Header = { + alg: Alg // From the jsonwebtoken package, ensuring algorithm alignment + kid: string // Key ID to identify the signing key +} + +/** + * Defines the payload of our JWT. + * + * @param {string} requestHash - The hashed request. + * @param {string} [iss] - The issuer of the JWT. + * @param {number} [iat] - The time the JWT was issued. + * @param {number} [exp] - The time the JWT expires. + */ +export type Payload = { + requestHash: string + iat: number +} + +export type Jwt = { + header: Header + payload: Payload + signature: string +} + +/** + * Defines the input required to generate a JWT signature for a request. + * + * @param {string} privateKey - The private key to sign the JWT with. Private key will be identified by the kid in the header if this is not provided. + * @param {string} kid - The key ID to identify the signing key. + * @param {Alg} algorithm - The algorithm to use for signing. + * @param {Request} request - The content of the request to be signed. + */ +export type SignatureInput = { + privateKey: string + kid: string + algorithm: Alg + request: Request +} + +/** + * Defines the input required to verify a JWT. + * + * @param {string} jwt - The JWT to be verified. + * @param {Request} request - The content of the request to be verified. + * @param {string} publicKey - The public key that corresponds to the private key used for signing. + */ +export type VerificationInput = { + rawToken: string + request: Request + publicKey: string + algorithm: Alg + kid: string +} diff --git a/packages/signature-verifier/tsconfig.json b/packages/signature-verifier/tsconfig.json new file mode 100644 index 000000000..52c6fa8fe --- /dev/null +++ b/packages/signature-verifier/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true + } +} diff --git a/packages/signature-verifier/tsconfig.lib.json b/packages/signature-verifier/tsconfig.lib.json new file mode 100644 index 000000000..82378234a --- /dev/null +++ b/packages/signature-verifier/tsconfig.lib.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "lib": ["es2018"], + "target": "es2018", + "moduleResolution": "node" + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts"] +} diff --git a/packages/signature-verifier/tsconfig.spec.json b/packages/signature-verifier/tsconfig.spec.json new file mode 100644 index 000000000..26ef046ac --- /dev/null +++ b/packages/signature-verifier/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 6f7635bbd..0a5f1fd91 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -16,6 +16,7 @@ "@app/authz/*": ["apps/authz/src/*"], "@app/orchestration/*": ["apps/orchestration/src/*"], "@narval/authz-shared": ["packages/authz-shared/src/index.ts"], + "@narval/signature-verifier": ["packages/signature-verifier/src/index.ts"], "@narval/transaction-engine-module": ["packages/transaction-engine-module/src/index.ts"], "@narval/transaction-request-intent": ["packages/transaction-request-intent/src/index.ts"] }, From 9725d248317fc8a59602c06a657642f6fe0212ae Mon Sep 17 00:00:00 2001 From: Pierre Troger Date: Thu, 8 Feb 2024 01:23:00 -0400 Subject: [PATCH 2/3] removed unused packages --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index ad1305e84..c60d35cb5 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,6 @@ "@nestjs/swagger": "^7.2.0", "@open-policy-agent/opa-wasm": "^1.8.0", "@prisma/client": "^5.7.1", - "@types/jsonwebtoken": "^9.0.5", "axios": "^1.6.7", "bull": "^4.12.1", "caip": "^1.1.0", @@ -93,7 +92,6 @@ "date-fns": "^3.3.1", "handlebars": "^4.7.8", "jose": "^5.2.1", - "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "prism-react-renderer": "^2.3.1", "react": "18.2.0", From 8afd4a6c61dd1634ccc9fadc37bcab455d5adb55 Mon Sep 17 00:00:00 2001 From: Pierre Troger Date: Thu, 8 Feb 2024 01:23:49 -0400 Subject: [PATCH 3/3] really removed unused packages --- package-lock.json | 128 ---------------------------------------------- 1 file changed, 128 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1dbe474ae..240ebe73d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "@nestjs/swagger": "^7.2.0", "@open-policy-agent/opa-wasm": "^1.8.0", "@prisma/client": "^5.7.1", - "@types/jsonwebtoken": "^9.0.5", "axios": "^1.6.7", "bull": "^4.12.1", "caip": "^1.1.0", @@ -37,7 +36,6 @@ "date-fns": "^3.3.1", "handlebars": "^4.7.8", "jose": "^5.2.1", - "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "prism-react-renderer": "^2.3.1", "react": "18.2.0", @@ -9985,14 +9983,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", - "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", @@ -12106,11 +12096,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -14699,14 +14684,6 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -19499,57 +19476,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jsonwebtoken/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jsonwebtoken/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -19565,25 +19491,6 @@ "node": ">=4.0" } }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -20148,47 +20055,17 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", "dev": true }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -20200,11 +20077,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "devOptional": true }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",