From 297d65ce03fbd979e96729b28a1e0fd7967c1cbd Mon Sep 17 00:00:00 2001 From: Franck R Date: Wed, 16 Feb 2022 12:11:54 +1100 Subject: [PATCH] Reduce Buffer usage in ENR module (#522) --- .mocharc.json | 2 +- CHANGELOG.md | 3 +- package-lock.json | 889 ++++++++++++++++++++++-- package.json | 6 +- src/index.ts | 2 + src/lib/discovery/dns.spec.ts | 5 +- src/lib/discovery/enrtree.ts | 10 +- src/lib/discovery/index.spec.ts | 5 +- src/lib/enr/create.ts | 6 +- src/lib/enr/enr.spec.ts | 61 +- src/lib/enr/enr.ts | 143 ++-- src/lib/enr/keypair/index.ts | 4 +- src/lib/enr/keypair/secp256k1.ts | 15 +- src/lib/enr/keypair/types.ts | 20 +- src/lib/enr/multiaddrs_codec.spec.ts | 34 + src/lib/enr/multiaddrs_codec.ts | 50 ++ src/lib/enr/v4.ts | 32 +- src/{test_utils => lib}/utf8.ts | 42 ++ src/lib/utils.ts | 46 ++ src/lib/waku.spec.ts | 5 +- src/lib/waku_message/index.node.spec.ts | 2 +- src/test_utils/index.ts | 1 - src/test_utils/nim_waku.ts | 1 - 23 files changed, 1129 insertions(+), 255 deletions(-) create mode 100644 src/lib/enr/multiaddrs_codec.spec.ts create mode 100644 src/lib/enr/multiaddrs_codec.ts rename src/{test_utils => lib}/utf8.ts (54%) diff --git a/.mocharc.json b/.mocharc.json index 7ecdac5352..dece11d531 100644 --- a/.mocharc.json +++ b/.mocharc.json @@ -1,6 +1,6 @@ { "extension": ["ts"], "spec": "src/**/*.spec.ts", - "require": ["ts-node/register", "isomorphic-fetch"], + "require": ["ts-node/register", "isomorphic-fetch", "jsdom-global/register"], "exit": true } diff --git a/CHANGELOG.md b/CHANGELOG.md index 5619066348..fdc3efd30a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -- axios dependency in favour of fetch. +- `axios` dependency in favour of fetch. +- `base64url` and `bigint-buffer` dependencies. ## [0.16.0] - 2022-01-31 diff --git a/package-lock.json b/package-lock.json index 47afafe448..37d2d5c45a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,6 @@ "license": "MIT OR Apache-2.0", "dependencies": { "@chainsafe/libp2p-noise": "^5.0.0", - "base64url": "^3.0.1", - "bigint-buffer": "^1.1.5", "debug": "^4.3.1", "dns-query": "^0.8.0", "ecies-geth": "^1.5.2", @@ -59,6 +57,8 @@ "fast-check": "^2.14.0", "gh-pages": "^3.2.3", "isomorphic-fetch": "^3.0.0", + "jsdom": "^19.0.0", + "jsdom-global": "^3.0.2", "karma": "^6.3.12", "karma-chrome-launcher": "^3.1.0", "karma-env-preprocessor": "^0.1.1", @@ -1343,6 +1343,15 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -1915,6 +1924,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -1959,6 +1974,37 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -2320,14 +2366,6 @@ "node": "^4.5.0 || >= 5.9" } }, - "node_modules/base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -2336,18 +2374,6 @@ "tweetnacl": "^0.14.3" } }, - "node_modules/bigint-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", - "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", - "hasInstallScript": true, - "dependencies": { - "bindings": "^1.3.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/bignumber.js": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", @@ -2365,14 +2391,6 @@ "node": ">=8" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bl": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz", @@ -2502,6 +2520,12 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "node_modules/browser-resolve": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", @@ -3553,6 +3577,30 @@ "node": ">=12" } }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -3570,6 +3618,20 @@ "node": ">=0.10" } }, + "node_modules/data-urls": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.1.tgz", + "integrity": "sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/dataloader": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", @@ -3632,6 +3694,12 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, "node_modules/deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -3876,6 +3944,18 @@ "url": "https://bevry.me/fund" } }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -4201,6 +4281,98 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.6.0.tgz", @@ -4875,11 +5047,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "node_modules/filename-reserved-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", @@ -5655,6 +5822,18 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -5675,6 +5854,20 @@ "node": ">=8.0.0" } }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -6145,6 +6338,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6660,6 +6859,119 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" }, + "node_modules/jsdom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", + "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.5.0", + "acorn-globals": "^6.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.1", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0", + "ws": "^8.2.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=", + "dev": true, + "peerDependencies": { + "jsdom": ">=10.0.0" + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsdom/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -8138,6 +8450,12 @@ "node": ">=8" } }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -8777,6 +9095,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -9762,6 +10086,18 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -10324,6 +10660,12 @@ "node": ">=8" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/tail": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz", @@ -10598,6 +10940,18 @@ "node": ">=0.8" } }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/trim-repeated": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", @@ -11160,6 +11514,27 @@ "integrity": "sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA==", "dev": true }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", @@ -11182,6 +11557,15 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/webpack": { "version": "5.69.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.0.tgz", @@ -11330,12 +11714,46 @@ "acorn": "^8" } }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", "dev": true }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", + "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/wherearewe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wherearewe/-/wherearewe-1.0.0.tgz", @@ -11509,6 +11927,15 @@ "node": ">=8" } }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/xml2js": { "version": "0.1.14", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.1.14.tgz", @@ -11520,6 +11947,12 @@ "node": "*" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/xsalsa20": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.1.0.tgz", @@ -12746,6 +13179,12 @@ "@stablelib/wipe": "^1.0.1" } }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -13229,6 +13668,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -13261,6 +13706,30 @@ "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + } + } + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -13528,11 +13997,6 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -13541,14 +14005,6 @@ "tweetnacl": "^0.14.3" } }, - "bigint-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", - "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", - "requires": { - "bindings": "^1.3.0" - } - }, "bignumber.js": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", @@ -13560,14 +14016,6 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, "bl": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz", @@ -13681,6 +14129,12 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "browser-resolve": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", @@ -14519,6 +14973,29 @@ } } }, + "cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -14533,6 +15010,17 @@ "assert-plus": "^1.0.0" } }, + "data-urls": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.1.tgz", + "integrity": "sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0" + } + }, "dataloader": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", @@ -14577,6 +15065,12 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -14772,6 +15266,15 @@ "integrity": "sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==", "dev": true }, + "domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "requires": { + "webidl-conversions": "^7.0.0" + } + }, "dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -15036,6 +15539,73 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, "eslint": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.6.0.tgz", @@ -15548,11 +16118,6 @@ "flat-cache": "^3.0.4" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "filename-reserved-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", @@ -16110,6 +16675,15 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -16127,6 +16701,17 @@ "requires-port": "^1.0.0" } }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -16463,6 +17048,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -16878,6 +17469,85 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" }, + "jsdom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", + "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.5.0", + "acorn-globals": "^6.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.1", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0", + "ws": "^8.2.3", + "xml-name-validator": "^4.0.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "requires": {} + } + } + }, + "jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=", + "dev": true, + "requires": {} + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -18077,6 +18747,12 @@ "path-key": "^3.0.0" } }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -18553,6 +19229,12 @@ "lines-and-columns": "^1.1.6" } }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -19295,6 +19977,15 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -19740,6 +20431,12 @@ "has-flag": "^4.0.0" } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "tail": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/tail/-/tail-2.2.4.tgz", @@ -19937,6 +20634,15 @@ "punycode": "^2.1.1" } }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, "trim-repeated": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", @@ -20369,6 +21075,24 @@ "integrity": "sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA==", "dev": true }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "dev": true, + "requires": { + "xml-name-validator": "^4.0.0" + } + }, "watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", @@ -20388,6 +21112,12 @@ "defaults": "^1.0.3" } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, "webpack": { "version": "5.69.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.0.tgz", @@ -20488,12 +21218,37 @@ "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + } + }, "whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", "dev": true }, + "whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true + }, + "whatwg-url": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", + "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", + "dev": true, + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + }, "wherearewe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wherearewe/-/wherearewe-1.0.0.tgz", @@ -20622,6 +21377,12 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true + }, "xml2js": { "version": "0.1.14", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.1.14.tgz", @@ -20630,6 +21391,12 @@ "sax": ">=0.1.1" } }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "xsalsa20": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.1.0.tgz", diff --git a/package.json b/package.json index 4bcb0b502c..4aa103ce38 100644 --- a/package.json +++ b/package.json @@ -51,15 +51,13 @@ "doc:cname": "echo 'js-waku.wakuconnect.dev' > build/docs/CNAME", "doc:examples": "mkdir -p build/docs/examples", "deploy": "node ci/deploy.js", - "reset-hard": "git clean -dfx && git reset --hard && npm i && npm run build && for d in examples/*; do (cd $d; npm i); done" + "reset-hard": "git clean -dfx && git reset --hard && npm i && npm run build && for d in examples/*/; do (cd $d; npm i); done" }, "engines": { "node": ">=16" }, "dependencies": { "@chainsafe/libp2p-noise": "^5.0.0", - "base64url": "^3.0.1", - "bigint-buffer": "^1.1.5", "debug": "^4.3.1", "dns-query": "^0.8.0", "ecies-geth": "^1.5.2", @@ -107,6 +105,8 @@ "fast-check": "^2.14.0", "gh-pages": "^3.2.3", "isomorphic-fetch": "^3.0.0", + "jsdom": "^19.0.0", + "jsdom-global": "^3.0.2", "karma": "^6.3.12", "karma-chrome-launcher": "^3.1.0", "karma-env-preprocessor": "^0.1.1", diff --git a/src/index.ts b/src/index.ts index 8624fd92fb..e583056328 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,8 @@ export * as discovery from "./lib/discovery"; export * as enr from "./lib/enr"; +export * as utf8 from "./lib/utf8"; + export * as utils from "./lib/utils"; export * as waku from "./lib/waku"; diff --git a/src/lib/discovery/dns.spec.ts b/src/lib/discovery/dns.spec.ts index e642135daf..04222791c2 100644 --- a/src/lib/discovery/dns.spec.ts +++ b/src/lib/discovery/dns.spec.ts @@ -183,10 +183,7 @@ describe("DNS Node Discovery [live data]", function () { const maxQuantity = 3; before(function () { - if ( - process.env.CI || - (typeof window !== "undefined" && window?.__env__?.CI) - ) { + if (process.env.CI || window?.__env__?.CI) { this.skip(); } }); diff --git a/src/lib/discovery/enrtree.ts b/src/lib/discovery/enrtree.ts index f7308b621f..01acb45e51 100644 --- a/src/lib/discovery/enrtree.ts +++ b/src/lib/discovery/enrtree.ts @@ -1,11 +1,10 @@ import assert from "assert"; -import base64url from "base64url"; import * as base32 from "hi-base32"; import { ecdsaVerify } from "secp256k1"; import { ENR } from "../enr"; -import { keccak256Buf } from "../utils"; +import { base64ToBytes, keccak256Buf } from "../utils"; export type ENRRootValues = { eRoot: string; @@ -43,15 +42,12 @@ export class ENRTree { // (Trailing recovery bit must be trimmed to pass `ecdsaVerify` method) const signedComponent = root.split(" sig")[0]; const signedComponentBuffer = Buffer.from(signedComponent); - const signatureBuffer = base64url - .toBuffer(rootValues.signature) - .slice(0, 64); - const keyBuffer = Buffer.from(decodedPublicKey); + const signatureBuffer = base64ToBytes(rootValues.signature).slice(0, 64); const isVerified = ecdsaVerify( signatureBuffer, keccak256Buf(signedComponentBuffer), - keyBuffer + new Uint8Array(decodedPublicKey) ); assert(isVerified, "Unable to verify ENRTree root signature"); diff --git a/src/lib/discovery/index.spec.ts b/src/lib/discovery/index.spec.ts index 63862250ff..b9108ca99b 100644 --- a/src/lib/discovery/index.spec.ts +++ b/src/lib/discovery/index.spec.ts @@ -45,10 +45,7 @@ describe("Discovery", () => { describe("Discovery [live data]", function () { before(function () { - if ( - process.env.CI || - (typeof window !== "undefined" && window?.__env__?.CI) - ) { + if (process.env.CI || window?.__env__?.CI) { this.skip(); } }); diff --git a/src/lib/enr/create.ts b/src/lib/enr/create.ts index b7c4c6bdae..cf9b8936bc 100644 --- a/src/lib/enr/create.ts +++ b/src/lib/enr/create.ts @@ -2,9 +2,9 @@ import { bytesToHex } from "../utils"; import { NodeId } from "./types"; -export function createNodeId(buffer: Buffer): NodeId { - if (buffer.length !== 32) { +export function createNodeId(bytes: Uint8Array): NodeId { + if (bytes.length !== 32) { throw new Error("NodeId must be 32 bytes in length"); } - return bytesToHex(buffer); + return bytesToHex(bytes); } diff --git a/src/lib/enr/enr.spec.ts b/src/lib/enr/enr.spec.ts index 4251ee1ecd..00e493a9a4 100644 --- a/src/lib/enr/enr.spec.ts +++ b/src/lib/enr/enr.spec.ts @@ -28,8 +28,8 @@ describe("ENR", function () { "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss" ), ]; - const txt = enr.encodeTxt(keypair.privateKey); - expect(txt.slice(0, 4)).to.be.equal("enr:"); + const txt = await enr.encodeTxt(keypair.privateKey); + const enr2 = ENR.decodeTxt(txt); expect(bytesToHex(enr2.signature as Buffer)).to.be.equal( bytesToHex(enr.signature as Buffer) @@ -87,17 +87,21 @@ describe("ENR", function () { expect(enr.ip).to.not.be.undefined; expect(enr.ip).to.be.equal("134.209.139.210"); expect(enr.publicKey).to.not.be.undefined; - expect(enr.peerId.toB58String()).to.be.equal( + expect(enr.peerId?.toB58String()).to.be.equal( "16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ" ); }); - it("should throw error - no id", () => { + it("should throw error - no id", async () => { try { - const txt = Buffer.from( - "656e723a2d435972595a62404b574342526c4179357a7a61445a584a42476b636e68344d486342465a6e75584e467264764a6a5830346a527a6a7a", - "hex" - ).toString(); + const peerId = await PeerId.create({ keyType: "secp256k1" }); + const enr = ENR.createFromPeerId(peerId); + const keypair = createKeypairFromPeerId(peerId); + enr.setLocationMultiaddr(new Multiaddr("/ip4/18.223.219.100/udp/9000")); + + enr.set("id", new Uint8Array([0])); + const txt = await enr.encodeTxt(keypair.privateKey); + ENR.decodeTxt(txt); assert.fail("Expect error here"); } catch (err: unknown) { @@ -170,37 +174,6 @@ describe("ENR", function () { }); }); - describe("Fuzzing testcases", () => { - it("should throw error in invalid signature", () => { - const buf = Buffer.from( - "656e723a2d4b7634514147774f54385374716d7749354c486149796d494f346f6f464b664e6b456a576130663150384f73456c67426832496a622d4772445f2d623957346b6350466377796e354845516d526371584e716470566f3168656f42683246306447356c64484f494141414141414141414143455a58526f4d704141414141414141414141505f5f5f5f5f5f5f5f5f5f676d6c6b676e5930676d6c7768424c663232534a6332566a634449314e6d73786f514a78436e4536765f7832656b67595f756f45317274777a76477934306d7139654436365866485042576749494e315a48437f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f434436410d0a", - "hex" - ).toString(); - try { - ENR.decodeTxt(buf); - } catch (err: unknown) { - const e = err as Error; - expect(e.message).to.equal( - "Decoded ENR invalid signature: must be a byte array" - ); - } - }); - it("should throw error in invalid sequence number", () => { - const buf = Buffer.from( - "656e723a2d495334514b6b33ff583945717841337838334162436979416e537550444d764b353264433530486d31584744643574457951684d3356634a4c2d5062446b44673541507a5f706f76763022d48dcf992d5379716b306e616e636f4e572d656e7263713042676d6c6b676e5930676d6c77684838414141474a6332566a634449314e6d73786f514d31453579557370397638516a397476335a575843766146427672504e647a384b5049314e68576651577a494e315a4843434239410a", - "hex" - ).toString(); - try { - ENR.decodeTxt(buf); - } catch (err: unknown) { - const e = err as Error; - expect(e.message).to.equal( - "Decoded ENR invalid sequence number: must be a byte array" - ); - } - }); - }); - describe("Static tests", () => { let privateKey: Buffer; let record: ENR; @@ -212,9 +185,10 @@ describe("ENR", function () { "hex" ); record = ENR.createV4(v4.publicKey(privateKey)); - record.set("ip", Buffer.from("7f000001", "hex")); - record.set("udp", Buffer.from((30303).toString(16), "hex")); + record.setLocationMultiaddr(new Multiaddr("/ip4/127.0.0.1/udp/30303")); record.seq = seq; + // To set signature + record.encode(privateKey); }); it("should properly compute the node id", () => { @@ -228,7 +202,7 @@ describe("ENR", function () { expect(decoded).to.deep.equal(record); }); - it("should encode/decode to text encoding", () => { + it("should encode/decode to text encoding", async () => { // spec enr https://eips.ethereum.org/EIPS/eip-778 const testTxt = "enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8"; @@ -236,7 +210,8 @@ describe("ENR", function () { expect(decoded.udp).to.be.equal(30303); expect(decoded.ip).to.be.equal("127.0.0.1"); expect(decoded).to.deep.equal(record); - expect(record.encodeTxt(privateKey)).to.equal(testTxt); + const recordTxt = await record.encodeTxt(privateKey); + expect(recordTxt).to.equal(testTxt); }); }); diff --git a/src/lib/enr/enr.ts b/src/lib/enr/enr.ts index 6f18377de9..16781d6e2e 100644 --- a/src/lib/enr/enr.ts +++ b/src/lib/enr/enr.ts @@ -1,5 +1,3 @@ -import base64url from "base64url"; -import { toBigIntBE } from "bigint-buffer"; import { Multiaddr, protocols } from "multiaddr"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: No types available @@ -8,12 +6,10 @@ import PeerId from "peer-id"; import * as RLP from "rlp"; import { encode as varintEncode } from "varint"; -import { - ERR_INVALID_ID, - ERR_NO_SIGNATURE, - MAX_RECORD_SIZE, - MULTIADDR_LENGTH_SIZE, -} from "./constants"; +import { bytesToUtf8, utf8ToBytes } from "../utf8"; +import { base64ToBytes, bytesToBase64, bytesToHex } from "../utils"; + +import { ERR_INVALID_ID, ERR_NO_SIGNATURE, MAX_RECORD_SIZE } from "./constants"; import { createKeypair, createKeypairFromPeerId, @@ -21,28 +17,32 @@ import { IKeypair, KeypairType, } from "./keypair"; +import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec"; import { ENRKey, ENRValue, NodeId, SequenceNumber } from "./types"; import * as v4 from "./v4"; export class ENR extends Map { public static readonly RECORD_PREFIX = "enr:"; public seq: SequenceNumber; - public signature: Buffer | null; + public signature: Uint8Array | null; constructor( kvs: Record = {}, seq: SequenceNumber = 1n, - signature: Buffer | null = null + signature: Uint8Array | null = null ) { super(Object.entries(kvs)); this.seq = seq; this.signature = signature; } - static createV4(publicKey: Buffer, kvs: Record = {}): ENR { + static createV4( + publicKey: Uint8Array, + kvs: Record = {} + ): ENR { return new ENR({ ...kvs, - id: Buffer.from("v4"), + id: utf8ToBytes("v4"), secp256k1: publicKey, }); } @@ -78,9 +78,13 @@ export class ENR extends Map { } const obj: Record = {}; for (let i = 0; i < kvs.length; i += 2) { - obj[kvs[i].toString()] = Buffer.from(kvs[i + 1]); + obj[kvs[i].toString()] = new Uint8Array(kvs[i + 1]); } - const enr = new ENR(obj, toBigIntBE(seq), signature); + const enr = new ENR( + obj, + BigInt("0x" + bytesToHex(seq)), + new Uint8Array(signature) + ); if (!enr.verify(RLP.encode([seq, ...kvs]), signature)) { throw new Error("Unable to verify ENR signature"); @@ -88,7 +92,7 @@ export class ENR extends Map { return enr; } - static decode(encoded: Buffer): ENR { + static decode(encoded: Uint8Array): ENR { const decoded = RLP.decode(encoded) as unknown as Buffer[]; return ENR.decodeFromValues(decoded); } @@ -99,7 +103,7 @@ export class ENR extends Map { `"string encoded ENR must start with '${this.RECORD_PREFIX}'` ); } - return ENR.decode(base64url.toBuffer(encoded.slice(4))); + return ENR.decode(base64ToBytes(encoded.slice(4))); } set(k: ENRKey, v: ENRValue): this { @@ -109,9 +113,9 @@ export class ENR extends Map { } get id(): string { - const id = this.get("id") as Buffer; + const id = this.get("id"); if (!id) throw new Error("id not found."); - return id.toString("utf8"); + return bytesToUtf8(id); } get keypairType(): KeypairType { @@ -123,27 +127,31 @@ export class ENR extends Map { } } - get publicKey(): Buffer { + get publicKey(): Uint8Array | undefined { switch (this.id) { case "v4": - return this.get("secp256k1") as Buffer; + return this.get("secp256k1"); default: throw new Error(ERR_INVALID_ID); } } - get keypair(): IKeypair { - return createKeypair(this.keypairType, undefined, this.publicKey); + get keypair(): IKeypair | undefined { + if (this.publicKey) { + const publicKey = this.publicKey; + return createKeypair(this.keypairType, undefined, publicKey); + } + return; } - get peerId(): PeerId { - return createPeerIdFromKeypair(this.keypair); + get peerId(): PeerId | undefined { + return this.keypair ? createPeerIdFromKeypair(this.keypair) : undefined; } - get nodeId(): NodeId { + get nodeId(): NodeId | undefined { switch (this.id) { case "v4": - return v4.nodeId(this.publicKey); + return this.publicKey ? v4.nodeId(this.publicKey) : undefined; default: throw new Error(ERR_INVALID_ID); } @@ -266,32 +274,9 @@ export class ENR extends Map { get multiaddrs(): Multiaddr[] | undefined { const raw = this.get("multiaddrs"); - if (raw) { - const multiaddrs = []; + if (raw) return decodeMultiaddrs(raw); - try { - let index = 0; - - while (index < raw.length) { - const sizeBytes = raw.slice(index, index + 2); - const size = Buffer.from(sizeBytes).readUInt16BE(0); - - const multiaddrBytes = raw.slice( - index + MULTIADDR_LENGTH_SIZE, - index + size + MULTIADDR_LENGTH_SIZE - ); - const multiaddr = new Multiaddr(multiaddrBytes); - - multiaddrs.push(multiaddr); - index += size + MULTIADDR_LENGTH_SIZE; - } - } catch (e) { - throw new Error("Invalid value in multiaddrs field"); - } - return multiaddrs; - } else { - return undefined; - } + return; } /** @@ -303,37 +288,14 @@ export class ENR extends Map { * * If the peer information only contains information that can be represented with the ENR pre-defined keys * (ip, tcp, etc) then the usage of [[setLocationMultiaddr]] should be preferred. - * - * The multiaddresses stored in this field must to be location multiaddresses, ie, peer id less. + * The multiaddresses stored in this field must be location multiaddresses, + * ie, without a peer id. */ set multiaddrs(multiaddrs: Multiaddr[] | undefined) { if (multiaddrs === undefined) { this.delete("multiaddrs"); } else { - let multiaddrsBuf = Buffer.from([]); - - multiaddrs.forEach((multiaddr) => { - if (multiaddr.getPeerId()) - throw new Error("`multiaddr` field MUST not contain peer id"); - - const bytes = multiaddr.bytes; - - let buf = Buffer.alloc(2); - - // Prepend the size of the next entry - const written = buf.writeUInt16BE(bytes.length, 0); - - if (written !== MULTIADDR_LENGTH_SIZE) { - throw new Error( - `Internal error: unsigned 16-bit integer was not written in ${MULTIADDR_LENGTH_SIZE} bytes` - ); - } - - buf = Buffer.concat([buf, bytes]); - - multiaddrsBuf = Buffer.concat([multiaddrsBuf, buf]); - }); - + const multiaddrsBuf = encodeMultiaddrs(multiaddrs); this.set("multiaddrs", multiaddrsBuf); } } @@ -427,9 +389,13 @@ export class ENR extends Map { getFullMultiaddr( protocol: "udp" | "udp4" | "udp6" | "tcp" | "tcp4" | "tcp6" ): Multiaddr | undefined { - const locationMultiaddr = this.getLocationMultiaddr(protocol); - if (locationMultiaddr) { - return locationMultiaddr.encapsulate(`/p2p/${this.peerId.toB58String()}`); + if (this.peerId) { + const locationMultiaddr = this.getLocationMultiaddr(protocol); + if (locationMultiaddr) { + return locationMultiaddr.encapsulate( + `/p2p/${this.peerId.toB58String()}` + ); + } } return; } @@ -438,15 +404,16 @@ export class ENR extends Map { * Returns the full multiaddrs from the `multiaddrs` ENR field. */ getFullMultiaddrs(): Multiaddr[] { - if (this.multiaddrs) { + if (this.peerId && this.multiaddrs) { + const peerId = this.peerId; return this.multiaddrs.map((ma) => { - return ma.encapsulate(`/p2p/${this.peerId.toB58String()}`); + return ma.encapsulate(`/p2p/${peerId.toB58String()}`); }); } return []; } - verify(data: Buffer, signature: Buffer): boolean { + verify(data: Uint8Array, signature: Uint8Array): boolean { if (!this.get("id") || this.id !== "v4") { throw new Error(ERR_INVALID_ID); } @@ -456,7 +423,7 @@ export class ENR extends Map { return v4.verify(this.publicKey, data, signature); } - sign(data: Buffer, privateKey: Buffer): Buffer { + sign(data: Uint8Array, privateKey: Uint8Array): Uint8Array { switch (this.id) { case "v4": this.signature = v4.sign(privateKey, data); @@ -467,7 +434,7 @@ export class ENR extends Map { return this.signature; } - encodeToValues(privateKey?: Buffer): (ENRKey | ENRValue | number)[] { + encodeToValues(privateKey?: Uint8Array): (ENRKey | ENRValue | number)[] { // sort keys and flatten into [k, v, k, v, ...] const content: Array = Array.from(this.keys()) .sort((a, b) => a.localeCompare(b)) @@ -485,7 +452,7 @@ export class ENR extends Map { return content; } - encode(privateKey?: Buffer): Buffer { + encode(privateKey?: Uint8Array): Uint8Array { const encoded = RLP.encode(this.encodeToValues(privateKey)); if (encoded.length >= MAX_RECORD_SIZE) { throw new Error("ENR must be less than 300 bytes"); @@ -493,7 +460,7 @@ export class ENR extends Map { return encoded; } - encodeTxt(privateKey?: Buffer): string { - return ENR.RECORD_PREFIX + base64url.encode(this.encode(privateKey)); + async encodeTxt(privateKey?: Uint8Array): Promise { + return ENR.RECORD_PREFIX + (await bytesToBase64(this.encode(privateKey))); } } diff --git a/src/lib/enr/keypair/index.ts b/src/lib/enr/keypair/index.ts index d50e0ab296..c4ed54ff0b 100644 --- a/src/lib/enr/keypair/index.ts +++ b/src/lib/enr/keypair/index.ts @@ -22,8 +22,8 @@ export async function generateKeypair(type: KeypairType): Promise { export function createKeypair( type: KeypairType, - privateKey?: Buffer, - publicKey?: Buffer + privateKey?: Uint8Array, + publicKey?: Uint8Array ): IKeypair { switch (type) { case KeypairType.secp256k1: diff --git a/src/lib/enr/keypair/secp256k1.ts b/src/lib/enr/keypair/secp256k1.ts index 024ddaaf7d..b7a3d5e75c 100644 --- a/src/lib/enr/keypair/secp256k1.ts +++ b/src/lib/enr/keypair/secp256k1.ts @@ -1,25 +1,26 @@ -import { Buffer } from "buffer"; import crypto from "crypto"; import * as secp256k1 from "secp256k1"; import { AbstractKeypair, IKeypair, IKeypairClass, KeypairType } from "./types"; -export function secp256k1PublicKeyToCompressed(publicKey: Uint8Array): Buffer { +export function secp256k1PublicKeyToCompressed( + publicKey: Uint8Array +): Uint8Array { if (publicKey.length === 64) { publicKey = Buffer.concat([Buffer.from([4]), publicKey]); } return Buffer.from(secp256k1.publicKeyConvert(publicKey, true)); } -export function secp256k1PublicKeyToFull(publicKey: Uint8Array): Buffer { +export function secp256k1PublicKeyToFull(publicKey: Uint8Array): Uint8Array { if (publicKey.length === 64) { return Buffer.concat([Buffer.from([4]), publicKey]); } return Buffer.from(secp256k1.publicKeyConvert(publicKey, false)); } -export function secp256k1PublicKeyToRaw(publicKey: Uint8Array): Buffer { +export function secp256k1PublicKeyToRaw(publicKey: Uint8Array): Uint8Array { return Buffer.from(secp256k1.publicKeyConvert(publicKey, false).slice(1)); } @@ -29,7 +30,7 @@ export const Secp256k1Keypair: IKeypairClass = class Secp256k1Keypair { readonly type: KeypairType; - constructor(privateKey?: Buffer, publicKey?: Buffer) { + constructor(privateKey?: Uint8Array, publicKey?: Uint8Array) { let pub = publicKey; if (pub) { pub = secp256k1PublicKeyToCompressed(pub); @@ -58,12 +59,12 @@ export const Secp256k1Keypair: IKeypairClass = class Secp256k1Keypair return true; } - sign(msg: Buffer): Buffer { + sign(msg: Uint8Array): Uint8Array { const { signature, recid } = secp256k1.ecdsaSign(msg, this.privateKey); return Buffer.concat([signature, Buffer.from([recid])]); } - verify(msg: Buffer, sig: Buffer): boolean { + verify(msg: Uint8Array, sig: Uint8Array): boolean { return secp256k1.ecdsaVerify(sig, msg, this.publicKey); } }; diff --git a/src/lib/enr/keypair/types.ts b/src/lib/enr/keypair/types.ts index 4444371f06..657d751749 100644 --- a/src/lib/enr/keypair/types.ts +++ b/src/lib/enr/keypair/types.ts @@ -6,25 +6,25 @@ export enum KeypairType { export interface IKeypair { type: KeypairType; - privateKey: Buffer; - publicKey: Buffer; + privateKey: Uint8Array; + publicKey: Uint8Array; privateKeyVerify(): boolean; publicKeyVerify(): boolean; - sign(msg: Buffer): Buffer; - verify(msg: Buffer, sig: Buffer): boolean; + sign(msg: Uint8Array): Uint8Array; + verify(msg: Uint8Array, sig: Uint8Array): boolean; hasPrivateKey(): boolean; } export interface IKeypairClass { - new (privateKey?: Buffer, publicKey?: Buffer): IKeypair; + new (privateKey?: Uint8Array, publicKey?: Uint8Array): IKeypair; generate(): Promise; } export abstract class AbstractKeypair { - _privateKey?: Buffer; - readonly _publicKey?: Buffer; + _privateKey?: Uint8Array; + readonly _publicKey?: Uint8Array; - constructor(privateKey?: Buffer, publicKey?: Buffer) { + constructor(privateKey?: Uint8Array, publicKey?: Uint8Array) { if ((this._privateKey = privateKey) && !this.privateKeyVerify()) { throw new Error("Invalid private key"); } @@ -33,14 +33,14 @@ export abstract class AbstractKeypair { } } - get privateKey(): Buffer { + get privateKey(): Uint8Array { if (!this._privateKey) { throw new Error(); } return this._privateKey; } - get publicKey(): Buffer { + get publicKey(): Uint8Array { if (!this._publicKey) { throw new Error(); } diff --git a/src/lib/enr/multiaddrs_codec.spec.ts b/src/lib/enr/multiaddrs_codec.spec.ts new file mode 100644 index 0000000000..443047122b --- /dev/null +++ b/src/lib/enr/multiaddrs_codec.spec.ts @@ -0,0 +1,34 @@ +import { expect } from "chai"; +import { Multiaddr } from "multiaddr"; + +import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec"; + +describe("ENR multiaddrs codec", function () { + it("Sample", async () => { + const multiaddrs = [ + new Multiaddr( + "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss" + ), + new Multiaddr( + "/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss" + ), + new Multiaddr( + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss" + ), + ]; + + const bytes = encodeMultiaddrs(multiaddrs); + const result = decodeMultiaddrs(bytes); + + const multiaddrsAsStr = result.map((ma) => ma.toString()); + expect(multiaddrsAsStr).to.include( + "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss" + ); + expect(multiaddrsAsStr).to.include( + "/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss" + ); + expect(multiaddrsAsStr).to.include( + "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss" + ); + }); +}); diff --git a/src/lib/enr/multiaddrs_codec.ts b/src/lib/enr/multiaddrs_codec.ts new file mode 100644 index 0000000000..c4e44a7047 --- /dev/null +++ b/src/lib/enr/multiaddrs_codec.ts @@ -0,0 +1,50 @@ +import { Multiaddr } from "multiaddr"; + +import { MULTIADDR_LENGTH_SIZE } from "./constants"; + +export function decodeMultiaddrs(bytes: Uint8Array): Multiaddr[] { + const multiaddrs = []; + + let index = 0; + + while (index < bytes.length) { + const sizeDataView = new DataView( + bytes.buffer, + index, + MULTIADDR_LENGTH_SIZE + ); + const size = sizeDataView.getUint16(0); + index += MULTIADDR_LENGTH_SIZE; + + const multiaddrBytes = bytes.slice(index, index + size); + index += size; + + const multiaddr = new Multiaddr(multiaddrBytes); + multiaddrs.push(multiaddr); + } + return multiaddrs; +} + +export function encodeMultiaddrs(multiaddrs: Multiaddr[]): Uint8Array { + const totalLength = multiaddrs.reduce( + (acc, ma) => acc + MULTIADDR_LENGTH_SIZE + ma.bytes.length, + 0 + ); + const bytes = new Uint8Array(totalLength); + const dataView = new DataView(bytes.buffer); + + let index = 0; + multiaddrs.forEach((multiaddr) => { + if (multiaddr.getPeerId()) + throw new Error("`multiaddr` field MUST not contain peer id"); + + // Prepend the size of the next entry + dataView.setUint16(index, multiaddr.bytes.length); + index += MULTIADDR_LENGTH_SIZE; + + bytes.set(multiaddr.bytes, index); + index += multiaddr.bytes.length; + }); + + return bytes; +} diff --git a/src/lib/enr/v4.ts b/src/lib/enr/v4.ts index 54193035b7..5a8d74794f 100644 --- a/src/lib/enr/v4.ts +++ b/src/lib/enr/v4.ts @@ -6,24 +6,28 @@ import * as secp256k1 from "secp256k1"; import { createNodeId } from "./create"; import { NodeId } from "./types"; -export function hash(input: Uint8Array): Buffer { - return Buffer.from(keccak256.arrayBuffer(input)); +export function hash(input: Uint8Array): Uint8Array { + return new Uint8Array(keccak256.arrayBuffer(input)); } -export async function createPrivateKey(): Promise { - return Buffer.from(await randomBytes(32)); +export async function createPrivateKey(): Promise { + return new Uint8Array(await randomBytes(32)); } -export function publicKey(privKey: Uint8Array): Buffer { - return Buffer.from(secp256k1.publicKeyCreate(privKey)); +export function publicKey(privKey: Uint8Array): Uint8Array { + return new Uint8Array(secp256k1.publicKeyCreate(privKey)); } -export function sign(privKey: Uint8Array, msg: Uint8Array): Buffer { +export function sign(privKey: Uint8Array, msg: Uint8Array): Uint8Array { const { signature } = secp256k1.ecdsaSign(hash(msg), privKey); - return Buffer.from(signature); + return new Uint8Array(signature); } -export function verify(pubKey: Buffer, msg: Buffer, sig: Buffer): boolean { +export function verify( + pubKey: Uint8Array, + msg: Uint8Array, + sig: Uint8Array +): boolean { // Remove the recovery id if present (byte #65) return secp256k1.ecdsaVerify(sig.slice(0, 64), hash(msg), pubKey); } @@ -37,11 +41,11 @@ export function nodeId(pubKey: Uint8Array): NodeId { export class ENRKeyPair { public constructor( public readonly nodeId: NodeId, - public readonly privateKey: Buffer, - public readonly publicKey: Buffer + public readonly privateKey: Uint8Array, + public readonly publicKey: Uint8Array ) {} - public static async create(privateKey?: Buffer): Promise { + public static async create(privateKey?: Uint8Array): Promise { if (privateKey) { if (!secp256k1.privateKeyVerify(privateKey)) { throw new Error("Invalid private key"); @@ -54,11 +58,11 @@ export class ENRKeyPair { return new ENRKeyPair(_nodeId, _privateKey, _publicKey); } - public sign(msg: Buffer): Buffer { + public sign(msg: Uint8Array): Uint8Array { return sign(this.privateKey, msg); } - public verify(msg: Buffer, sig: Buffer): boolean { + public verify(msg: Uint8Array, sig: Uint8Array): boolean { return verify(this.publicKey, msg, sig); } } diff --git a/src/test_utils/utf8.ts b/src/lib/utf8.ts similarity index 54% rename from src/test_utils/utf8.ts rename to src/lib/utf8.ts index a70b7b8417..cd8a61c689 100644 --- a/src/test_utils/utf8.ts +++ b/src/lib/utf8.ts @@ -1,3 +1,6 @@ +/** + * Decode bytes to utf-8 string. + */ // Thanks https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330 export function bytesToUtf8(bytes: Uint8Array): string { let i = 0, @@ -41,3 +44,42 @@ export function bytesToUtf8(bytes: Uint8Array): string { } return s; } + +/** + * Encode utf-8 string to byte array + */ +// Thanks https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330 +export function utf8ToBytes(s: string): Uint8Array { + let i = 0; + const bytes = new Uint8Array(s.length * 4); + for (let ci = 0; ci != s.length; ci++) { + let c = s.charCodeAt(ci); + if (c < 128) { + bytes[i++] = c; + continue; + } + if (c < 2048) { + bytes[i++] = (c >> 6) | 192; + } else { + if (c > 0xd7ff && c < 0xdc00) { + if (++ci >= s.length) + throw new Error("UTF-8 encode: incomplete surrogate pair"); + const c2 = s.charCodeAt(ci); + if (c2 < 0xdc00 || c2 > 0xdfff) + throw new Error( + "UTF-8 encode: second surrogate character 0x" + + c2.toString(16) + + " at index " + + ci + + " out of range" + ); + c = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff); + bytes[i++] = (c >> 18) | 240; + bytes[i++] = ((c >> 12) & 63) | 128; + } else bytes[i++] = (c >> 12) | 224; + bytes[i++] = ((c >> 6) & 63) | 128; + } + bytes[i++] = (c & 63) | 128; + } + return bytes.subarray(0, i); +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b3674060f4..7b165817ac 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -81,3 +81,49 @@ export function equalByteArrays( export function keccak256Buf(message: Message): Buffer { return Buffer.from(keccak256.arrayBuffer(message)); } + +/** + * Convert base64 string to byte array. + */ +export function base64ToBytes(base64: string): Uint8Array { + const e = new Map(); + + const len = base64.length; + const res = []; + const A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + for (let i = 0; i < 64; i++) { + e.set(A.charAt(i), i); + } + e.set("+", 62); + e.set("/", 63); + + let b = 0, + l = 0, + a; + for (let i = 0; i < len; i++) { + const c = e.get(base64.charAt(i)); + if (c === undefined) + throw new Error(`Invalid base64 character ${base64.charAt(i)}`); + b = (b << 6) + c; + l += 6; + while (l >= 8) { + ((a = (b >>> (l -= 8)) & 0xff) || i < len - 2) && res.push(a); + } + } + return new Uint8Array(res); +} + +/** + * Convert byte array to base64 string. + */ +export async function bytesToBase64(bytes: Uint8Array): Promise { + const base64url: string = await new Promise((r) => { + const reader = new window.FileReader(); + reader.onload = (): void => r(reader.result as string); + reader.readAsDataURL(new Blob([bytes])); + }); + const base64 = base64url.split(",", 2)[1]; + // We want URL and Filename Safe base64: https://datatracker.ietf.org/doc/html/rfc4648#section-5 + // Without trailing padding + return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); +} diff --git a/src/lib/waku.spec.ts b/src/lib/waku.spec.ts index 03a57d6eb6..77e9c21915 100644 --- a/src/lib/waku.spec.ts +++ b/src/lib/waku.spec.ts @@ -19,10 +19,7 @@ describe("Waku Dial", function () { }); before(function () { - if ( - process.env.CI || - (typeof window !== "undefined" && window?.__env__?.CI) - ) { + if (process.env.CI || window?.__env__?.CI) { this.skip(); } }); diff --git a/src/lib/waku_message/index.node.spec.ts b/src/lib/waku_message/index.node.spec.ts index ec3e1cae37..5e0cda3f8f 100644 --- a/src/lib/waku_message/index.node.spec.ts +++ b/src/lib/waku_message/index.node.spec.ts @@ -2,13 +2,13 @@ import { expect } from "chai"; import debug from "debug"; import { - bytesToUtf8, makeLogFileName, NimWaku, NOISE_KEY_1, WakuRelayMessage, } from "../../test_utils"; import { delay } from "../../test_utils/delay"; +import { bytesToUtf8 } from "../utf8"; import { hexToBytes } from "../utils"; import { Protocols, Waku } from "../waku"; diff --git a/src/test_utils/index.ts b/src/test_utils/index.ts index 1a5bf83131..a01035af71 100644 --- a/src/test_utils/index.ts +++ b/src/test_utils/index.ts @@ -9,4 +9,3 @@ export * from "./async_fs"; export * from "./constants"; export * from "./log_file"; export * from "./nim_waku"; -export * from "./utf8"; diff --git a/src/test_utils/nim_waku.ts b/src/test_utils/nim_waku.ts index a0b90ae7b8..d93fe14ea7 100644 --- a/src/test_utils/nim_waku.ts +++ b/src/test_utils/nim_waku.ts @@ -335,7 +335,6 @@ export class NimWaku { return { peerId: this.peerId, multiaddrWithId: this.multiaddrWithId }; } const res = await this.info(); - console.log(res); this.multiaddrWithId = res.listenAddresses .map((ma) => multiaddr(ma)) .find((ma) => ma.protoNames().includes("ws"));