diff --git a/modules/express/src/typedRoutes/api/common/decrypt.ts b/modules/express/src/typedRoutes/api/common/decrypt.ts index d7ad264169..67e6267559 100644 --- a/modules/express/src/typedRoutes/api/common/decrypt.ts +++ b/modules/express/src/typedRoutes/api/common/decrypt.ts @@ -8,13 +8,16 @@ export const DecryptRequestBody = { }; /** - * Decrypt + * Decrypt messages + * + * Decrypt a ciphertext generated by encrypt route with provided password * * @operationId express.decrypt - * @tag express + * @tag Express + * @public */ export const PostDecrypt = httpRoute({ - path: '/api/v[12]/decrypt', + path: '/api/v2/decrypt', method: 'POST', request: httpRequest({ body: DecryptRequestBody, diff --git a/modules/express/src/typedRoutes/api/common/encrypt.ts b/modules/express/src/typedRoutes/api/common/encrypt.ts index 0a8d46daea..4aac4d18b9 100644 --- a/modules/express/src/typedRoutes/api/common/encrypt.ts +++ b/modules/express/src/typedRoutes/api/common/encrypt.ts @@ -9,13 +9,16 @@ export const EncryptRequestBody = { }; /** - * Encrypt + * Encrypt messages + * + * Symmetrically encrypt an arbitrary message with provided password * * @operationId express.encrypt - * @tag express + * @tag Express + * @public */ export const PostEncrypt = httpRoute({ - path: '/api/v[12]/encrypt', + path: '/api/v2/encrypt', method: 'POST', request: httpRequest({ body: EncryptRequestBody, diff --git a/modules/express/src/typedRoutes/api/express_entry.ts b/modules/express/src/typedRoutes/api/express_entry.ts new file mode 100644 index 0000000000..e5e23f90ec --- /dev/null +++ b/modules/express/src/typedRoutes/api/express_entry.ts @@ -0,0 +1,356 @@ +import * as t from 'io-ts'; +import { apiSpec } from '@api-ts/io-ts-http'; +import * as express from 'express'; + +/* import { GetPing } from './common/ping'; +import { GetPingExpress } from './common/pingExpress'; +import { PostLogin } from './common/login'; */ +import { PostDecrypt } from './common/decrypt'; +import { PostEncrypt } from './common/encrypt'; +/* import { PostVerifyAddress } from './common/verifyAddress'; */ +/* import { PostV1CalculateMinerFeeInfo } from './v1/calculateMinerFeeInfo'; +import { PostV2CalculateMinerFeeInfo } from './v2/calculateMinerFeeInfo'; */ +/* import { PostAcceptShare } from './v1/acceptShare'; +import { PostSimpleCreate } from './v1/simpleCreate'; */ +/* import { PutPendingApproval } from './v1/pendingApproval'; */ +/* import { PostSignTransaction } from './v1/signTransaction'; */ +/* import { PostKeychainLocal } from './v2/keychainLocal'; +import { GetLightningState } from './v2/lightningState'; +import { PostKeychainChangePassword } from './v2/keychainChangePassword'; +import { PostLightningInitWallet } from './v2/lightningInitWallet'; +import { PostUnlockLightningWallet } from './v2/unlockWallet'; */ +/* import { PostVerifyCoinAddress } from './v2/verifyAddress'; */ +/* import { PostDeriveLocalKeyChain } from './v1/deriveLocalKeyChain'; +import { PostCreateLocalKeyChain } from './v1/createLocalKeyChain'; */ +/* import { PutConstructPendingApprovalTx } from './v1/constructPendingApprovalTx'; */ +/* import { PutConsolidateUnspents } from './v1/consolidateUnspents'; */ +/* import { PostCreateAddress } from './v2/createAddress'; */ +/* import { PutFanoutUnspents } from './v1/fanoutUnspents'; */ +/* import { PostOfcSignPayload } from './v2/ofcSignPayload'; */ +/* import { PostWalletRecoverToken } from './v2/walletRecoverToken'; */ +import { PostGenerateWallet } from './v2/generateWallet'; +/* import { PostSignerMacaroon } from './v2/signerMacaroon'; */ +/* import { PostCoinSignTx } from './v2/coinSignTx'; */ +/* import { PostWalletSignTx } from './v2/walletSignTx'; */ +/* import { PostWalletTxSignTSS } from './v2/walletTxSignTSS'; */ +/* import { PostShareWallet } from './v2/shareWallet'; */ +/* import { PutExpressWalletUpdate } from './v2/expressWalletUpdate'; */ +/* import { PostFanoutUnspents } from './v2/fanoutUnspents'; */ +/* import { PostSendMany } from './v2/sendmany'; */ +/* import { PostConsolidateUnspents } from './v2/consolidateunspents'; */ +/* import { PostPrebuildAndSignTransaction } from './v2/prebuildAndSignTransaction'; */ +/* import { PostCoinSign } from './v2/coinSign'; */ +/* import { PostSendCoins } from './v2/sendCoins'; */ +/* import { PostGenerateShareTSS } from './v2/generateShareTSS'; */ +/* import { PostOfcExtSignPayload } from './v2/ofcExtSignPayload'; */ +/* import { PostLightningWalletPayment } from './v2/lightningPayment'; */ +/* import { PostLightningWalletWithdraw } from './v2/lightningWithdraw'; */ +/* import { PutV2PendingApproval } from './v2/pendingApproval'; */ +/* import { PostConsolidateAccount } from './v2/consolidateAccount'; */ +/* import { PostCanonicalAddress } from './v2/canonicalAddress'; */ +/* import { PostWalletEnableTokens } from './v2/walletEnableTokens'; */ +/* import { PostWalletSweep } from './v2/walletSweep'; */ +/* import { PostWalletAccelerateTx } from './v2/walletAccelerateTx'; */ +/* import { PostIsWalletAddress } from './v2/isWalletAddress'; */ +/* import { GetAccountResources } from './v2/accountResources'; +import { GetResourceDelegations } from './v2/resourceDelegations'; */ + +// Too large types can cause the following error +// +// > error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed. +// +// Workarounds: (1) export heavy httpRoute handlers as `HttpRoute<'post'>` (etc.) in their modules so apiSpec +// inference stays small; (2) only construct expressApi with a single key and add it to the type union at the end. + +/* export const ExpressPingApiSpec = apiSpec({ + 'express.ping': { + get: GetPing, + }, +}); */ + +/* export const ExpressPingExpressApiSpec = apiSpec({ + 'express.pingExpress': { + get: GetPingExpress, + }, +}); */ + +/* export const ExpressLoginApiSpec = apiSpec({ + 'express.login': { + post: PostLogin, + }, +}); */ + +export const ExpressDecryptApiSpec = apiSpec({ + 'express.decrypt': { + post: PostDecrypt, + }, +}); + +export const ExpressEncryptApiSpec = apiSpec({ + 'express.encrypt': { + post: PostEncrypt, + }, +}); + +/* export const ExpressVerifyAddressApiSpec = apiSpec({ + 'express.verifyaddress': { + post: PostVerifyAddress, + }, +}); */ + +/* export const ExpressVerifyCoinAddressApiSpec = apiSpec({ + 'express.verifycoinaddress': { + post: PostVerifyCoinAddress, + }, +}); */ + +/* export const ExpressCalculateMinerFeeInfoApiSpec = apiSpec({ + 'express.v1.calculateminerfeeinfo': { + post: PostV1CalculateMinerFeeInfo, + }, + 'express.calculateminerfeeinfo': { + post: PostV2CalculateMinerFeeInfo, + }, +}); */ + +/* export const ExpressV1WalletAcceptShareApiSpec = apiSpec({ + 'express.v1.wallet.acceptShare': { + post: PostAcceptShare, + }, +}); */ + +/* export const ExpressV1WalletSimpleCreateApiSpec = apiSpec({ + 'express.v1.wallet.simplecreate': { + post: PostSimpleCreate, + }, +}); */ + +/* export const ExpressPendingApprovalsApiSpec = apiSpec({ + 'express.v1.pendingapprovals': { + put: PutPendingApproval, + }, + 'express.pendingapprovals': { + put: PutV2PendingApproval, + }, +}); */ + +/* export const ExpressWalletSignTransactionApiSpec = apiSpec({ + 'express.v1.wallet.signTransaction': { + post: PostSignTransaction, + }, + 'express.v2.wallet.prebuildandsigntransaction': { + post: PostPrebuildAndSignTransaction, + }, +}); */ + +/* export const ExpressV1KeychainDeriveApiSpec = apiSpec({ + 'express.v1.keychain.derive': { + post: PostDeriveLocalKeyChain, + }, +}); */ + +/* export const ExpressV1KeychainLocalApiSpec = apiSpec({ + 'express.v1.keychain.local': { + post: PostCreateLocalKeyChain, + }, +}); */ + +/* export const ExpressV1PendingApprovalConstructTxApiSpec = apiSpec({ + 'express.v1.pendingapproval.constructTx': { + put: PutConstructPendingApprovalTx, + }, +}); */ + +/* export const ExpressWalletConsolidateUnspentsApiSpec = apiSpec({ + 'express.v1.wallet.consolidateunspents': { + put: PutConsolidateUnspents, + }, + 'express.wallet.consolidateunspents': { + post: PostConsolidateUnspents, + }, +}); */ + +/* export const ExpressV2WalletConsolidateAccountApiSpec = apiSpec({ + 'express.wallet.consolidateaccount': { + post: PostConsolidateAccount, + }, +}); */ + +/* export const ExpressWalletFanoutUnspentsApiSpec = apiSpec({ + 'express.v1.wallet.fanoutunspents': { + put: PutFanoutUnspents, + }, + 'express.wallet.fanoutunspents': { + post: PostFanoutUnspents, + }, +}); */ + +/* export const ExpressV2WalletCreateAddressApiSpec = apiSpec({ + 'express.v2.wallet.createAddress': { + post: PostCreateAddress, + }, +}); */ + +/* export const ExpressV2WalletIsWalletAddressApiSpec = apiSpec({ + 'express.v2.wallet.isWalletAddress': { + post: PostIsWalletAddress, + }, +}); */ + +/* export const ExpressV2WalletSendManyApiSpec = apiSpec({ + 'express.wallet.sendmany': { + post: PostSendMany, + }, +}); */ + +/* export const ExpressV2WalletSendCoinsApiSpec = apiSpec({ + 'express.wallet.sendcoins': { + post: PostSendCoins, + }, +}); */ + +/* export const ExpressKeychainLocalApiSpec = apiSpec({ + 'express.keychain.local': { + post: PostKeychainLocal, + }, +}); */ + +/* export const ExpressKeychainChangePasswordApiSpec = apiSpec({ + 'express.keychain.changePassword': { + post: PostKeychainChangePassword, + }, +}); */ + +/* export const ExpressLightningWalletPaymentApiSpec = apiSpec({ + 'express.lightningpayinvoice': { + post: PostLightningWalletPayment, + }, +}); */ + +/* export const ExpressLightningGetStateApiSpec = apiSpec({ + 'express.lightning.getState': { + get: GetLightningState, + }, +}); */ + +/* export const ExpressLightningInitWalletApiSpec = apiSpec({ + 'express.lightning.initWallet': { + post: PostLightningInitWallet, + }, +}); */ + +/* export const ExpressLightningUnlockWalletApiSpec = apiSpec({ + 'express.lightning.unlockWallet': { + post: PostUnlockLightningWallet, + }, +}); */ + +/* export const ExpressLightningWalletWithdrawApiSpec = apiSpec({ + 'express.lightningwithdrawonchain': { + post: PostLightningWalletWithdraw, + }, +}); */ + +/* export const ExpressOfcSignPayloadApiSpec = apiSpec({ + 'express.ofc.signPayload': { + post: PostOfcSignPayload, + }, +}); */ + +/* export const ExpressWalletRecoverTokenApiSpec = apiSpec({ + 'express.wallet.recovertoken': { + post: PostWalletRecoverToken, + }, +}); */ + +/* export const ExpressWalletEnableTokensApiSpec = apiSpec({ + 'express.v2.wallet.enableTokens': { + post: PostWalletEnableTokens, + }, +}); */ + +/* export const ExpressCoinSigningApiSpec = apiSpec({ + 'express.signtx': { + post: PostCoinSignTx, + }, +}); */ + +/* export const ExpressExternalSigningApiSpec = apiSpec({ + 'express.v2.coin.sign': { + post: PostCoinSign, + }, + 'express.v2.tssshare.generate': { + post: PostGenerateShareTSS, + }, + 'express.v2.ofc.extSignPayload': { + post: PostOfcExtSignPayload, + }, +}); */ + +/* export const ExpressWalletSigningApiSpec = apiSpec({ + 'express.wallet.signtx': { + post: PostWalletSignTx, + }, + 'express.wallet.signtxtss': { + post: PostWalletTxSignTSS, + }, +}); */ + +export const ExpressWalletManagementApiSpec = apiSpec({ + 'express.wallet.generate': { + post: PostGenerateWallet, + }, +}); + +/* export const ExpressV2CanonicalAddressApiSpec = apiSpec({ + 'express.canonicaladdress': { + post: PostCanonicalAddress, + }, +}); */ + +/* export const ExpressV2WalletSweepApiSpec = apiSpec({ + 'express.wallet.sweep': { + post: PostWalletSweep, + }, +}); */ + +/* export const ExpressV2WalletAccelerateTxApiSpec = apiSpec({ + 'express.wallet.acceleratetx': { + post: PostWalletAccelerateTx, + }, +}); */ + +/* export const ExpressV2WalletAccountResourcesApiSpec = apiSpec({ + 'express.v2.wallet.getaccountresources': { + post: GetAccountResources, + }, +}); */ + +/* export const ExpressV2WalletResourceDelegationsApiSpec = apiSpec({ + 'express.v2.wallet.resourcedelegations': { + get: GetResourceDelegations, + }, +}); */ + +export type ExpressApi = typeof ExpressDecryptApiSpec & + typeof ExpressEncryptApiSpec & + typeof ExpressWalletManagementApiSpec; + +export const ExpressApi: ExpressApi = { + ...ExpressDecryptApiSpec, + ...ExpressEncryptApiSpec, + ...ExpressWalletManagementApiSpec, +}; + +type ExtractDecoded = T extends t.Type ? O : never; +type FlattenDecoded = T extends Record + ? (T extends { body: infer B } ? B : any) & + (T extends { query: infer Q } ? Q : any) & + (T extends { params: infer P } ? P : any) + : T; +export type ExpressApiRouteRequest< + ApiName extends keyof ExpressApi, + Method extends keyof ExpressApi[ApiName] +> = ExpressApi[ApiName][Method] extends { request: infer R } + ? express.Request & { decoded: FlattenDecoded> } + : never; diff --git a/modules/express/src/typedRoutes/api/v2/generateWallet.ts b/modules/express/src/typedRoutes/api/v2/generateWallet.ts index 0493aa4cd6..dbc6081956 100644 --- a/modules/express/src/typedRoutes/api/v2/generateWallet.ts +++ b/modules/express/src/typedRoutes/api/v2/generateWallet.ts @@ -97,7 +97,7 @@ export const GenerateWalletV2Query = { }; /** - * Generate Wallet + * Generate wallet * * Generate a new wallet for a coin. If you want a wallet to hold tokens, generate a wallet for the native coin of the blockchain (e.g. generate an ETH wallet to hold ERC20 tokens). * @@ -119,6 +119,7 @@ export const GenerateWalletV2Query = { * * @operationId express.wallet.generate * @tag Express + * @public */ export const PostGenerateWallet = httpRoute({ path: '/api/v2/{coin}/wallet/generate', diff --git a/modules/passkey-crypto/.mocharc.yml b/modules/passkey-crypto/.mocharc.yml new file mode 100644 index 0000000000..b18501b155 --- /dev/null +++ b/modules/passkey-crypto/.mocharc.yml @@ -0,0 +1,8 @@ +require: 'tsx' +timeout: '20000' +reporter: 'min' +reporter-option: + - 'cdn=true' + - 'json=false' +exit: true +spec: ['test/unit/**/*.ts'] diff --git a/modules/passkey-crypto/package.json b/modules/passkey-crypto/package.json new file mode 100644 index 0000000000..134653ecbc --- /dev/null +++ b/modules/passkey-crypto/package.json @@ -0,0 +1,42 @@ +{ + "name": "@bitgo/passkey-crypto", + "version": "1.0.0", + "description": "Pure cryptographic primitives for BitGo passkey (WebAuthn PRF) key derivation", + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn tsc --build --incremental --verbose .", + "fmt": "prettier --write .", + "check-fmt": "prettier --check '**/*.{ts,js,json}'", + "clean": "rm -r ./dist", + "lint": "eslint --quiet .", + "prepare": "npm run build", + "test": "npm run unit-test", + "unit-test": "mocha 'test/unit/**/*.ts'" + }, + "author": "BitGo SDK Team ", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/BitGo/BitGoJS.git", + "directory": "modules/passkey-crypto" + }, + "lint-staged": { + "*.{js,ts}": [ + "yarn prettier --write", + "yarn eslint --fix" + ] + }, + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "mocha": "^10.0.0", + "ts-node": "^10.0.0", + "typescript": "~5.4.5" + } +} diff --git a/modules/passkey-crypto/src/deriveEnterpriseSalt.ts b/modules/passkey-crypto/src/deriveEnterpriseSalt.ts new file mode 100644 index 0000000000..311b133d5a --- /dev/null +++ b/modules/passkey-crypto/src/deriveEnterpriseSalt.ts @@ -0,0 +1,15 @@ +import { createHmac } from 'crypto'; + +/** + * Derives an enterprise-scoped salt to prevent cross-enterprise key reuse. + * + * Computes HMAC-SHA256(baseSalt, enterpriseId) as a hex string. + * The baseSalt must always come from the server — never generate it client-side. + * + * @param baseSalt - Server-provided base salt + * @param enterpriseId - Enterprise identifier + * @returns Hex-encoded HMAC-SHA256 digest + */ +export function deriveEnterpriseSalt(baseSalt: string, enterpriseId: string): string { + return createHmac('sha256', baseSalt).update(enterpriseId).digest('hex'); +} diff --git a/modules/passkey-crypto/src/derivePassword.ts b/modules/passkey-crypto/src/derivePassword.ts new file mode 100644 index 0000000000..6865811af5 --- /dev/null +++ b/modules/passkey-crypto/src/derivePassword.ts @@ -0,0 +1,12 @@ +/** + * Derives a wallet passphrase from a WebAuthn PRF result. + * + * The PRF output (ArrayBuffer) is hex-encoded and used directly as the + * walletPassphrase for SJCL-based encryption (bitgo.encrypt). + * + * @param prfResult - Raw PRF output from WebAuthn credential assertion + * @returns Lowercase hex string to use as walletPassphrase + */ +export function derivePassword(prfResult: ArrayBuffer): string { + return Buffer.from(prfResult).toString('hex'); +} diff --git a/modules/passkey-crypto/src/index.ts b/modules/passkey-crypto/src/index.ts new file mode 100644 index 0000000000..f8a6c23cc8 --- /dev/null +++ b/modules/passkey-crypto/src/index.ts @@ -0,0 +1,2 @@ +export { derivePassword } from './derivePassword'; +export { deriveEnterpriseSalt } from './deriveEnterpriseSalt'; diff --git a/modules/passkey-crypto/test/unit/deriveEnterpriseSalt.test.ts b/modules/passkey-crypto/test/unit/deriveEnterpriseSalt.test.ts new file mode 100644 index 0000000000..362961545f --- /dev/null +++ b/modules/passkey-crypto/test/unit/deriveEnterpriseSalt.test.ts @@ -0,0 +1,39 @@ +import * as assert from 'assert'; +import { createHmac } from 'crypto'; +import { deriveEnterpriseSalt } from '../../src'; + +describe('deriveEnterpriseSalt', function () { + const BASE_SALT = 'server-provided-base-salt'; + const ENTERPRISE_ID = 'ent-abc123'; + + it('returns a hex string', function () { + const result = deriveEnterpriseSalt(BASE_SALT, ENTERPRISE_ID); + assert.match(result, /^[0-9a-f]+$/); + }); + + it('returns a 64-character string (SHA-256 = 32 bytes = 64 hex chars)', function () { + const result = deriveEnterpriseSalt(BASE_SALT, ENTERPRISE_ID); + assert.strictEqual(result.length, 64); + }); + + it('matches a known HMAC-SHA256 test vector', function () { + const expected = createHmac('sha256', BASE_SALT).update(ENTERPRISE_ID).digest('hex'); + assert.strictEqual(deriveEnterpriseSalt(BASE_SALT, ENTERPRISE_ID), expected); + }); + + it('is deterministic — same inputs produce same output', function () { + assert.strictEqual(deriveEnterpriseSalt(BASE_SALT, ENTERPRISE_ID), deriveEnterpriseSalt(BASE_SALT, ENTERPRISE_ID)); + }); + + it('produces different output for different enterprise IDs', function () { + const a = deriveEnterpriseSalt(BASE_SALT, 'ent-aaa'); + const b = deriveEnterpriseSalt(BASE_SALT, 'ent-bbb'); + assert.notStrictEqual(a, b); + }); + + it('produces different output for different base salts', function () { + const a = deriveEnterpriseSalt('salt-one', ENTERPRISE_ID); + const b = deriveEnterpriseSalt('salt-two', ENTERPRISE_ID); + assert.notStrictEqual(a, b); + }); +}); diff --git a/modules/passkey-crypto/test/unit/derivePassword.test.ts b/modules/passkey-crypto/test/unit/derivePassword.test.ts new file mode 100644 index 0000000000..90815b4f87 --- /dev/null +++ b/modules/passkey-crypto/test/unit/derivePassword.test.ts @@ -0,0 +1,30 @@ +import * as assert from 'assert'; +import { derivePassword } from '../../src'; + +describe('derivePassword', function () { + it('converts an ArrayBuffer of zeros to a hex string of zeros', function () { + const input = new ArrayBuffer(4); + assert.strictEqual(derivePassword(input), '00000000'); + }); + + it('converts known bytes to expected hex', function () { + const input = new Uint8Array([0xde, 0xad, 0xbe, 0xef]).buffer; + assert.strictEqual(derivePassword(input), 'deadbeef'); + }); + + it('returns a lowercase hex string', function () { + const input = new Uint8Array([0xab, 0xcd]).buffer; + const result = derivePassword(input); + assert.strictEqual(result, result.toLowerCase()); + }); + + it('returns a string of length 2x the input byte length', function () { + const input = new ArrayBuffer(32); + assert.strictEqual(derivePassword(input).length, 64); + }); + + it('produces the same output for the same input (deterministic)', function () { + const input = new Uint8Array([1, 2, 3, 4, 5]).buffer; + assert.strictEqual(derivePassword(input), derivePassword(input)); + }); +}); diff --git a/modules/passkey-crypto/tsconfig.json b/modules/passkey-crypto/tsconfig.json new file mode 100644 index 0000000000..6c98fcc52c --- /dev/null +++ b/modules/passkey-crypto/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./", + "strictPropertyInitialization": false, + "esModuleInterop": true, + "typeRoots": ["../../types", "./node_modules/@types", "../../node_modules/@types"] + }, + "include": ["src/**/*", "test/**/*"], + "exclude": ["node_modules"] +} diff --git a/yarn.lock b/yarn.lock index 8e451bc1ca..9b2014e9d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1521,6 +1521,13 @@ resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.33.1.tgz" integrity sha512-UnLHDY6KMmC+UXf3Ufyh+onE19xzEXjT4VZ504Acmk4PXxqyvG4cCPprlKUFnGUX7f0z8Or9MAOHXBx41uHBcg== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@csstools/postcss-cascade-layers@^1.1.1": version "1.1.1" resolved "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz" @@ -3182,7 +3189,7 @@ "@jridgewell/sourcemap-codec" "^1.5.0" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== @@ -3195,11 +3202,19 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" -"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": version "0.3.30" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz" @@ -5842,6 +5857,26 @@ resolved "https://registry.npmjs.org/@tronweb3/google-protobuf/-/google-protobuf-3.21.4.tgz" integrity sha512-joxgV4esCdyZ921AprMIG1T7HjkypquhbJ5qJti/priCBJhRE1z9GOxIEMvayxSVSRbMGIoJNE0Knrg3vpwM1w== +"@tsconfig/node10@^1.0.7": + version "1.0.12" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz#be57ceac1e4692b41be9de6be8c32a106636dba4" + integrity sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@tufjs/canonical-json@1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz" @@ -6290,6 +6325,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz" integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== +"@types/node@^18.0.0": + version "18.19.130" + resolved "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz#da4c6324793a79defb7a62cba3947ec5add00d59" + integrity sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg== + dependencies: + undici-types "~5.26.4" + "@types/node@^18.0.4": version "18.19.123" resolved "https://registry.npmjs.org/@types/node/-/node-18.19.123.tgz" @@ -7024,6 +7066,13 @@ acorn-walk@^8.0.0, acorn-walk@^8.0.2: dependencies: acorn "^8.11.0" +acorn-walk@^8.1.1: + version "8.3.5" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz#8a6b8ca8fc5b34685af15dabb44118663c296496" + integrity sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw== + dependencies: + acorn "^8.11.0" + acorn@7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz" @@ -7044,6 +7093,11 @@ acorn@^8.0.4, acorn@^8.1.0, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.15.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== +acorn@^8.4.1: + version "8.16.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" + integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz" @@ -7245,6 +7299,11 @@ are-we-there-yet@^3.0.0: delegates "^1.0.0" readable-stream "^3.6.0" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" @@ -9494,6 +9553,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-env@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz" @@ -14817,6 +14881,11 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + make-fetch-happen@15.0.2, make-fetch-happen@^15.0.0, make-fetch-happen@^15.0.2: version "15.0.2" resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.2.tgz" @@ -15354,7 +15423,7 @@ mocha@10.6.0: yargs-parser "^20.2.9" yargs-unparser "^2.0.0" -mocha@^10.2.0: +mocha@^10.0.0, mocha@^10.2.0: version "10.8.2" resolved "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz" integrity sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== @@ -20124,6 +20193,25 @@ ts-loader@^9.1.2: semver "^7.3.4" source-map "^0.7.4" +ts-node@^10.0.0: + version "10.9.2" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + ts-results@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/ts-results/-/ts-results-3.3.0.tgz" @@ -20421,6 +20509,11 @@ typescript@^4.2.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@~5.4.5: + version "5.4.5" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + "ua-parser-js@>0.7.30 <0.8.0", ua-parser-js@^0.7.30, ua-parser-js@^1.0.35: version "0.7.41" resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz#9f6dee58c389e8afababa62a4a2dc22edb69a452" @@ -20723,6 +20816,11 @@ uuid@^8.3.2: resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + v8-compile-cache@^2.0.3: version "2.4.0" resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz" @@ -21544,6 +21642,11 @@ yeoman-generator@^5.6.1: sort-keys "^4.2.0" text-table "^0.2.0" +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"