From 644ea3a59df77f37ce237176e1305d971966e1d8 Mon Sep 17 00:00:00 2001 From: smallfawn <860562056@QQ.COM> Date: Thu, 27 Jun 2024 21:29:59 +0800 Subject: [PATCH] TEST --- .gitattributes | 2 - .github/workflows/decode.yml | 32 + input.js | 1 + output.js | 0 package-lock.json | 3283 +++++++++++++++++++++ package.json | 21 + src/main.js | 50 + src/plugin/awsc.js | 244 ++ src/plugin/common.js | 21 + src/plugin/eval.js | 52 + src/plugin/jjencode.js | 66 + src/plugin/obfuscator.js | 1109 +++++++ src/plugin/sojson.js | 657 +++++ src/plugin/sojsonv7.js | 914 ++++++ src/visitor/calculate-binary.js | 24 + src/visitor/calculate-rstring.js | 36 + src/visitor/delete-extra.js | 12 + src/visitor/delete-illegal-return.js | 10 + src/visitor/delete-unused-var.js | 35 + src/visitor/merge-object.js | 211 ++ src/visitor/parse-control-flow-storage.js | 196 ++ 21 files changed, 6974 insertions(+), 2 deletions(-) delete mode 100644 .gitattributes create mode 100644 .github/workflows/decode.yml create mode 100644 input.js create mode 100644 output.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/main.js create mode 100644 src/plugin/awsc.js create mode 100644 src/plugin/common.js create mode 100644 src/plugin/eval.js create mode 100644 src/plugin/jjencode.js create mode 100644 src/plugin/obfuscator.js create mode 100644 src/plugin/sojson.js create mode 100644 src/plugin/sojsonv7.js create mode 100644 src/visitor/calculate-binary.js create mode 100644 src/visitor/calculate-rstring.js create mode 100644 src/visitor/delete-extra.js create mode 100644 src/visitor/delete-illegal-return.js create mode 100644 src/visitor/delete-unused-var.js create mode 100644 src/visitor/merge-object.js create mode 100644 src/visitor/parse-control-flow-storage.js diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe077042..000000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/.github/workflows/decode.yml b/.github/workflows/decode.yml new file mode 100644 index 000000000..01d87eded --- /dev/null +++ b/.github/workflows/decode.yml @@ -0,0 +1,32 @@ +name: Decode JavaScript File + +on: + push: + branches: + - main +jobs: + decode: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: List files in root directory + run: ls -l + - name: Install dependencies and run decode + run: | + npm install + npm run decode -- -t obfuscator [-i input.js] [-o output.js] + - name: Configure Git author + run: | + git config --local user.email "action@github.com" + git config --local user.name "action" + - name: Save decoded output to repository + run: | + git status + git add output.js + git status + git commit -m "Add decoded output file" + git push + \ No newline at end of file diff --git a/input.js b/input.js new file mode 100644 index 000000000..cd8c53743 --- /dev/null +++ b/input.js @@ -0,0 +1 @@ +(function(_0x444058,_0x570471){function _0x339db3(_0x1d0c2f,_0x3b1f5a,_0x4874cc,_0x2145a8,_0x27afc4){return _0x5263(_0x27afc4-0x195,_0x3b1f5a);}function _0x56d139(_0x27325d,_0x183565,_0x4fee98,_0x4ebe7d,_0x1e9086){return _0x5263(_0x1e9086-0x368,_0x4fee98);}var _0x200cf6=_0x444058();function _0x5eaa44(_0x13fd33,_0x266fba,_0xdf817,_0x2f810d,_0x287e1a){return _0x5263(_0x13fd33-0x1d8,_0xdf817);}function _0x46004f(_0x1a7d2d,_0x4b6fc0,_0x40aa99,_0x48f6da,_0x1a9c65){return _0x5263(_0x4b6fc0-0x338,_0x1a9c65);}function _0x4bf04b(_0x5b4f4e,_0xd2f654,_0x5f381a,_0x4e29c8,_0x9db713){return _0x5263(_0x9db713-0xd7,_0x5f381a);}while(!![]){try{var _0x179890=-parseInt(_0x339db3(0x2d5,0x2d1,0x2cc,0x2d5,0x2d4))/(0x136c*-0x1+0x548*0x1+0x4b7*0x3)*(-parseInt(_0x56d139(0x4a3,0x49e,0x4aa,0x4a1,0x4a4))/(-0x11*-0x85+-0x1358+-0x1*-0xa85))+-parseInt(_0x339db3(0x2d8,0x2d0,0x2d4,0x2d5,0x2d5))/(0x2272+0x12f7+-0x3566)*(parseInt(_0x56d139(0x4a7,0x4ad,0x4aa,0x4a8,0x4aa))/(-0x1*0x1ebb+0x85*-0x21+-0x994*-0x5))+parseInt(_0x5eaa44(0x322,0x323,0x326,0x31c,0x31b))/(0x4c*0x67+-0x6*-0xc0+0x5*-0x703)+parseInt(_0x4bf04b(0x21f,0x218,0x218,0x224,0x21f))/(-0x1d4+-0x6ae*0x4+0x9f*0x2e)+-parseInt(_0x4bf04b(0x21a,0x224,0x220,0x218,0x21e))/(0x16d6+-0x1f0*-0x1+-0x18bf)+parseInt(_0x46004f(0x472,0x479,0x477,0x480,0x477))/(-0xfe5+0x3a8+-0x1*-0xc45)*(-parseInt(_0x56d139(0x4b0,0x4b3,0x4a5,0x4b3,0x4ac))/(-0x1*-0x21dc+-0x145+-0x56d*0x6))+parseInt(_0x4bf04b(0x21a,0x20d,0x213,0x20f,0x214))/(0x23e8+-0x2379+-0x65)*(-parseInt(_0x46004f(0x479,0x47e,0x481,0x477,0x480))/(0xc88*0x1+-0x224e+0x15d1));if(_0x179890===_0x570471)break;else _0x200cf6['push'](_0x200cf6['shift']());}catch(_0x2cf0ac){_0x200cf6['push'](_0x200cf6['shift']());}}}(_0x4f47,-0x466*0x494+0x999da*0x1+0x1511b5));function _0x4f47(){var _0x3b4ba0=['PbtJQ','1UboPxT','3hjknQS','24dkllqJ','889964CuSUOU','log','992808dMSJWQ','Hello','5687PqdMXP','4884243rTzFPz','5881650hdzsay','\x20Worl','4674680kJDtDQ','2632414JrYWaV','24950NsVBxV'];_0x4f47=function(){return _0x3b4ba0;};return _0x4f47();}function hi(){function _0x3d370d(_0x2101a2,_0x21af60,_0x26c689,_0x44e706,_0x4f9c6c){return _0x5263(_0x21af60- -0x3ba,_0x4f9c6c);}function _0x3df3dc(_0x5b0f06,_0x1ad90a,_0x1fab14,_0x3cecd9,_0x1e9d24){return _0x5263(_0x1e9d24- -0xd3,_0x1fab14);}function _0x5e4abf(_0x363beb,_0x36d681,_0x15bd4d,_0x2e3669,_0x24fb12){return _0x5263(_0x2e3669-0x19,_0x15bd4d);}var _0x3c3202={};function _0x144232(_0x432acb,_0x3a5371,_0x499003,_0x5bf0fe,_0x591a73){return _0x5263(_0x5bf0fe- -0x4d,_0x432acb);}_0x3c3202[_0x3df3dc(0x6e,0x70,0x64,0x6f,0x6b)]=_0xe3fb9f(-0x1f9,-0x1ff,-0x200,-0x1fc,-0x202)+_0xe3fb9f(-0x1f8,-0x1fb,-0x200,-0x1ff,-0x1ff)+'d!';function _0xe3fb9f(_0x4ef0bf,_0x5d2307,_0x5b6659,_0x526774,_0x4dc04e){return _0x5263(_0x5d2307- -0x344,_0x526774);}var _0xb13bfe=_0x3c3202;console[_0xe3fb9f(-0x207,-0x201,-0x207,-0x201,-0x208)](_0xb13bfe[_0x5e4abf(0x15b,0x150,0x153,0x157,0x15c)]);}function _0x5263(_0x49a732,_0x2f0df8){var _0x58f2ba=_0x4f47();return _0x5263=function(_0x498a53,_0x357ad3){_0x498a53=_0x498a53-(0x152*-0xa+-0x1f1b+-0x59*-0x83);var _0x511ecd=_0x58f2ba[_0x498a53];return _0x511ecd;},_0x5263(_0x49a732,_0x2f0df8);}hi(); \ No newline at end of file diff --git a/output.js b/output.js new file mode 100644 index 000000000..e69de29bb diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..06bd05d72 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3283 @@ +{ + "name": "decode-js", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "decode-js", + "dependencies": { + "@babel/generator": "^7.17.10", + "@babel/parser": "^7.17.10", + "@babel/traverse": "^7.17.10", + "@babel/types": "^7.17.10", + "eslint": "^8.23.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "isolated-vm": "^4.7.2", + "prettier": "^2.7.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "bin": { + "acorn": "bin/acorn" + }, + "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", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", + "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", + "dependencies": { + "@eslint/eslintrc": "^1.3.2", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@humanwhocodes/module-importer": "^1.0.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isolated-vm": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-4.7.2.tgz", + "integrity": "sha512-JVEs5gzWObzZK5+OlBplCdYSpokMcdhLSs/xWYYxmYWVfOOFF4oZJsYh7E/FmfX8e7gMioXMpMMeEyX1afuKrg==", + "hasInstallScript": true, + "dependencies": { + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/node-abi": { + "version": "3.56.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.56.0.tgz", + "integrity": "sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "requires": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + } + }, + "@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "requires": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + }, + "@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + } + }, + "@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==" + }, + "@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + } + }, + "@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "requires": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "requires": { + "type-fest": "^0.20.2" + } + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==" + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "requires": { + "fill-range": "^7.1.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "eslint": { + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", + "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", + "requires": { + "@eslint/eslintrc": "^1.3.2", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@humanwhocodes/module-importer": "^1.0.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "requires": {} + }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" + }, + "espree": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isolated-vm": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-4.7.2.tgz", + "integrity": "sha512-JVEs5gzWObzZK5+OlBplCdYSpokMcdhLSs/xWYYxmYWVfOOFF4oZJsYh7E/FmfX8e7gMioXMpMMeEyX1afuKrg==", + "requires": { + "prebuild-install": "^7.1.1" + } + }, + "js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node-abi": { + "version": "3.56.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.56.0.tgz", + "integrity": "sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==", + "requires": { + "semver": "^7.3.5" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..bc0f20880 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "decode-js", + "scripts": { + "decode": "node src/main.js", + "deob": "node src/main.js -t obfuscator", + "deso": "node src/main.js -t sojson", + "desov7": "node src/main.js -t sojsonv7", + "lint": "eslint --ext .js --fix src" + }, + "dependencies": { + "@babel/generator": "^7.17.10", + "@babel/parser": "^7.17.10", + "@babel/traverse": "^7.17.10", + "@babel/types": "^7.17.10", + "eslint": "^8.23.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "isolated-vm": "^4.7.2", + "prettier": "^2.7.1" + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 000000000..0c85154ba --- /dev/null +++ b/src/main.js @@ -0,0 +1,50 @@ +const fs = require('fs') +const PluginCommon = require('./plugin/common.js') +const PluginJjencode = require('./plugin/jjencode.js') +const PluginSojson = require('./plugin/sojson.js') +const PluginSojsonV7 = require('./plugin/sojsonv7.js') +const PluginObfuscator = require('./plugin/obfuscator.js') +const PluginAwsc = require('./plugin/awsc.js') + +// 读取参数 +let type = 'common' +let encodeFile = 'input.js' +let decodeFile = 'output.js' +for (let i = 2; i < process.argv.length; i += 2) { + if (process.argv[i] === '-t') { + type = process.argv[i + 1] + } + if (process.argv[i] === '-i') { + encodeFile = process.argv[i + 1] + } + if (process.argv[i] === '-o') { + decodeFile = process.argv[i + 1] + } +} +console.log(`类型: ${type}`) +console.log(`输入: ${encodeFile}`) +console.log(`输出: ${decodeFile}`) + +// 读取源代码 +const sourceCode = fs.readFileSync(encodeFile, { encoding: 'utf-8' }) + +// 净化源代码 +let code +if (type === 'sojson') { + code = PluginSojson(sourceCode) +} else if (type === 'sojsonv7') { + code = PluginSojsonV7(sourceCode) +} else if (type === 'obfuscator') { + code = PluginObfuscator(sourceCode) +} else if (type === 'awsc') { + code = PluginAwsc(sourceCode) +} else if (type === 'jjencode') { + code = PluginJjencode(sourceCode) +} else { + code = PluginCommon(sourceCode) +} + +// 输出代码 +if (code) { + fs.writeFile(decodeFile, code, () => {}) +} diff --git a/src/plugin/awsc.js b/src/plugin/awsc.js new file mode 100644 index 000000000..cbb951936 --- /dev/null +++ b/src/plugin/awsc.js @@ -0,0 +1,244 @@ +/** + * Reference: + * * [某宝登录bx-ua参数逆向思路(fireyejs 225算法)](https://zhuanlan.zhihu.com/p/626187669) + */ +const { parse } = require('@babel/parser') +const generator = require('@babel/generator').default +const traverse = require('@babel/traverse').default +const t = require('@babel/types') + +function RemoveVoid(path) { + if (path.node.operator === 'void') { + path.replaceWith(path.node.argument) + } +} + +function LintConditionalAssign(path) { + if (!t.isAssignmentExpression(path?.parent)) { + return + } + let { test, consequent, alternate } = path.node + let { operator, left } = path.parent + consequent = t.assignmentExpression(operator, left, consequent) + alternate = t.assignmentExpression(operator, left, alternate) + path.parentPath.replaceWith( + t.conditionalExpression(test, consequent, alternate) + ) +} + +function LintConditionalIf(ast) { + function conditional(path) { + let { test, consequent, alternate } = path.node + // console.log(generator(test, { minified: true }).code) + if (t.isSequenceExpression(path.parent)) { + if (!sequence(path.parentPath)) { + path.stop() + } + return + } + if (t.isLogicalExpression(path.parent)) { + if (!logical(path.parentPath)) { + path.stop() + } + return + } + if (!t.isExpressionStatement(path.parent)) { + console.error(`Unexpected parent type: ${path.parent.type}`) + path.stop() + return + } + consequent = t.expressionStatement(consequent) + alternate = t.expressionStatement(alternate) + let statement = t.ifStatement(test, consequent, alternate) + path.replaceWithMultiple(statement) + } + + function sequence(path) { + if (t.isLogicalExpression(path.parent)) { + return logical(path.parentPath) + } + let body = [] + for (const item of path.node.expressions) { + body.push(t.expressionStatement(item)) + } + let node = t.blockStatement(body, []) + let replace_path = path + if (t.isExpressionStatement(path.parent)) { + replace_path = path.parentPath + } else if (!t.isBlockStatement(path.parent)) { + console.error(`Unexpected parent type: ${path.parent.type}`) + return false + } + replace_path.replaceWith(node) + return true + } + + function logical(path) { + let { operator, left, right } = path.node + if (operator !== '&&') { + console.error(`Unexpected logical operator: ${operator}`) + return false + } + if (!t.isExpressionStatement(path.parent)) { + console.error(`Unexpected parent type: ${path.parent.type}`) + return false + } + let node = t.ifStatement(left, t.expressionStatement(right)) + path.parentPath.replaceWith(node) + return true + } + + traverse(ast, { + ConditionalExpression: { enter: conditional }, + }) +} + +function LintLogicalIf(path) { + let { operator, left, right } = path.node + if (operator !== '&&') { + // console.warn(`Unexpected logical operator: ${operator}`) + return + } + if (!t.isExpressionStatement(path.parent)) { + console.warn(`Unexpected parent type: ${path.parent.type}`) + return + } + let node = t.ifStatement(left, t.expressionStatement(right)) + path.parentPath.replaceWith(node) + return +} + +function LintIfStatement(path) { + let { test, consequent, alternate } = path.node + let changed = false + if (!t.isBlockStatement(consequent)) { + consequent = t.blockStatement([consequent]) + changed = true + } + if (alternate && !t.isBlockStatement(alternate)) { + alternate = t.blockStatement([alternate]) + changed = true + } + if (!changed) { + return + } + path.replaceWith(t.ifStatement(test, consequent, alternate)) +} + +function LintIfTest(path) { + let { test, consequent, alternate } = path.node + if (!t.isSequenceExpression(test)) { + return + } + if (!t.isBlockStatement(path.parent)) { + return + } + let body = test.expressions + let last = body.pop() + let before = t.expressionStatement(t.sequenceExpression(body)) + path.insertBefore(before) + path.replaceWith(t.ifStatement(last, consequent, alternate)) +} + +function LintSwitchCase(path) { + let { test, consequent } = path.node + if (consequent.length == 1 && t.isBlockStatement(consequent[0])) { + return + } + let block = t.blockStatement(consequent) + path.replaceWith(t.switchCase(test, [block])) +} + +function LintReturn(path) { + let { argument } = path.node + if (!t.isSequenceExpression(argument)) { + return + } + if (!t.isBlockStatement(path.parent)) { + return + } + let body = argument.expressions + let last = body.pop() + let before = t.expressionStatement(t.sequenceExpression(body)) + path.insertBefore(before) + path.replaceWith(t.returnStatement(last)) +} + +function LintSequence(path) { + let body = [] + for (const item of path.node.expressions) { + body.push(t.expressionStatement(item)) + } + let node = t.blockStatement(body, []) + let replace_path = path + if (t.isExpressionStatement(path.parent)) { + replace_path = path.parentPath + } else if (!t.isBlockStatement(path.parent)) { + console.warn(`Unexpected parent type: ${path.parent.type}`) + return + } + replace_path.replaceWith(node) + return +} + +function LintBlock(path) { + let { body } = path.node + if (!body.length) { + return + } + let changed = false + let arr = [] + for (const item of body) { + if (!t.isBlockStatement(item)) { + arr.push(item) + continue + } + changed = true + for (const sub of item.body) { + arr.push(sub) + } + } + if (!changed) { + return + } + path.replaceWith(t.blockStatement(arr)) +} + +module.exports = function (code) { + let ast = parse(code) + // Lint + traverse(ast, { + UnaryExpression: RemoveVoid, + }) + traverse(ast, { + ConditionalExpression: { exit: LintConditionalAssign }, + }) + LintConditionalIf(ast) + traverse(ast, { + LogicalExpression: { exit: LintLogicalIf }, + }) + traverse(ast, { + IfStatement: { exit: LintIfStatement }, + }) + traverse(ast, { + IfStatement: { enter: LintIfTest }, + }) + traverse(ast, { + SwitchCase: { enter: LintSwitchCase }, + }) + traverse(ast, { + ReturnStatement: { enter: LintReturn }, + }) + traverse(ast, { + SequenceExpression: { exit: LintSequence }, + }) + traverse(ast, { + BlockStatement: { exit: LintBlock }, + }) + + code = generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code + return code +} diff --git a/src/plugin/common.js b/src/plugin/common.js new file mode 100644 index 000000000..d48bf7208 --- /dev/null +++ b/src/plugin/common.js @@ -0,0 +1,21 @@ +const { parse } = require('@babel/parser') +const generator = require('@babel/generator').default +const traverse = require('@babel/traverse').default + +module.exports = function (code) { + let ast + try { + ast = parse(code, { errorRecovery: true }) + } catch (e) { + console.error(`Cannot parse code: ${e.reasonCode}`) + return null + } + const deleteExtra = require('../visitor/delete-extra') + traverse(ast, deleteExtra) + const calculateBinary = require('../visitor/calculate-binary') + traverse(ast, calculateBinary) + const calculateRString = require('../visitor/calculate-rstring') + traverse(ast, calculateRString) + code = generator(ast).code + return code +} diff --git a/src/plugin/eval.js b/src/plugin/eval.js new file mode 100644 index 000000000..142638fca --- /dev/null +++ b/src/plugin/eval.js @@ -0,0 +1,52 @@ +const { parse } = require('@babel/parser') +const generator = require('@babel/generator').default +const traverse = require('@babel/traverse').default +const t = require('@babel/types') + +function unpack(code) { + let ast = parse(code, { errorRecovery: true }) + let lines = ast.program.body + let data = null + for (let line of lines) { + if (t.isEmptyStatement(line)) { + continue + } + if (data) { + return null + } + if ( + t.isCallExpression(line?.expression) && + line.expression.callee?.name === 'eval' && + line.expression.arguments.length === 1 && + t.isCallExpression(line.expression.arguments[0]) + ) { + data = t.expressionStatement(line.expression.arguments[0]) + continue + } + return null + } + if (!data) { + return null + } + code = generator(data, { minified: true }).code + return eval(code) +} + +function pack(code) { + let ast1 = parse('(function(){}())') + let ast2 = parse(code) + traverse(ast1, { + FunctionExpression(path) { + let body = t.blockStatement(ast2.program.body) + path.replaceWith(t.functionExpression(null, [], body)) + path.stop() + }, + }) + code = generator(ast1, { minified: false }).code + return code +} + +module.exports = { + unpack, + pack, +} diff --git a/src/plugin/jjencode.js b/src/plugin/jjencode.js new file mode 100644 index 000000000..af14f8c45 --- /dev/null +++ b/src/plugin/jjencode.js @@ -0,0 +1,66 @@ +/** + * Check the format and decode if possible + * + * @param {string} code the encoded code + * @returns null or string + */ +function getCode(code) { + // split the code by semicolon + let blocks = [] + for (let line of code.split(';')) { + if (line.length && line !== '\n') { + blocks.push(line) + } + } + if (blocks.length !== 6) { + console.error('The number of code blocks is incorrect!') + return null + } + // try to get the global variable name + const line1 = blocks[0].split('=') + if (line1.length !== 2 || line1[1].indexOf('~[]') === -1) { + console.error('Cannot find variable name!') + return null + } + // extract the target code + const target = blocks[5] + const variable = line1[0] + const left = `${variable}.$(${variable}.$(${variable}.$$+"\\""+` + let i = 0 + let s = 0 + while (i < left.length && s < target.length) { + if (left[i] === target[s]) { + ++i + } + ++s + } + const right = '"\\"")())()' + let j = right.length - 1 + let e = target.length - 1 + while (j >= 0 && e >= 0) { + if (right[j] === target[e]) { + --j + } + --e + } + if (s >= e) { + console.error('Cannot find the target code!') + return null + } + const selected = target.substring(s, e) + blocks[5] = `${variable}.$(${variable}.$$+"\\""+${selected}+"\\"")()` + const result = eval(blocks.join(';')) + return result +} + +/** + * This encoding method originates from http://utf-8.jp/public/jjencode.html, + * and it does not change the original code (encoder, not obfuscation). + */ +module.exports = function (code) { + code = getCode(code) + if (!code) { + return null + } + return code +} diff --git a/src/plugin/obfuscator.js b/src/plugin/obfuscator.js new file mode 100644 index 000000000..1a73ad4a7 --- /dev/null +++ b/src/plugin/obfuscator.js @@ -0,0 +1,1109 @@ +/** + * 整合自下面两个项目: + * * cilame/v_jstools + * * Cqxstevexw/decodeObfuscator + */ +const { parse } = require('@babel/parser') +const generator = require('@babel/generator').default +const traverse = require('@babel/traverse').default +const t = require('@babel/types') +const ivm = require('isolated-vm') +const PluginEval = require('./eval.js') + +const isolate = new ivm.Isolate() +const globalContext = isolate.createContextSync() +function virtualGlobalEval(jsStr) { + return globalContext.evalSync(String(jsStr)) +} + +/** + * Extract the literal value of an object, and remove an object if all + * references to the object are replaced. + */ +function decodeObject(ast) { + function collectObject(path) { + const id = path.node.id + const init = path.node.init + if (!t.isIdentifier(id) || !t.isObjectExpression(init)) { + return + } + const obj_name = id.name + const bind = path.scope.getBinding(obj_name) + let valid = true + let count = 0 + let obj = {} + for (const item of init.properties) { + if (!t.isObjectProperty(item) || !t.isLiteral(item.value)) { + valid = false + break + } + if (!t.isIdentifier(item.key)) { + valid = false + break + } + ++count + obj[item.key.name] = item.value + } + if (!valid || !count) { + return + } + let safe = true + for (let ref of bind.referencePaths) { + const parent = ref.parentPath + if (ref.key !== 'object' || !parent.isMemberExpression()) { + safe = false + continue + } + const key = parent.node.property + if (!t.isIdentifier(key) || parent.node.computed) { + safe = false + continue + } + if (Object.prototype.hasOwnProperty.call(obj, key.name)) { + parent.replaceWith(obj[key.name]) + } else { + safe = false + } + } + bind.scope.crawl() + if (safe) { + path.remove() + console.log(`删除对象: ${obj_name}`) + } + } + traverse(ast, { + VariableDeclarator: collectObject, + }) + return ast +} + +/** + * Before version 2.19.0, the string-array is a single array. + * Hence, we have to find StringArrayRotateFunction instead. + * + * @param {t.File} ast The ast file + * @returns Object + */ +function stringArrayV2(ast) { + console.info('Try v2 mode...') + let obj = { + version: 2, + stringArrayName: null, + stringArrayCodes: [], + stringArrayCalls: [], + } + // Function to rotate string list ("func2") + function find_rotate_function(path) { + const callee = path.get('callee') + const args = path.node.arguments + if ( + !callee.isFunctionExpression() || + callee.node.params.length !== 2 || + args.length == 0 || + args.length > 2 || + !t.isIdentifier(args[0]) + ) { + return + } + const arr = callee.node.params[0].name + const cmpV = callee.node.params[1].name + // >= 2.10.0 + const fp1 = `(){try{if()break${arr}push(${arr}shift())}catch(){${arr}push(${arr}shift())}}` + // < 2.10.0 + const fp2 = `=function(){while(--){${arr}push(${arr}shift)}}${cmpV}` + const code = '' + callee.get('body') + if (!checkPattern(code, fp1) && !checkPattern(code, fp2)) { + return + } + obj.stringArrayName = args[0].name + // The string array can be found by its binding + const bind = path.scope.getBinding(obj.stringArrayName) + const def = t.variableDeclaration('var', [bind.path.node]) + obj.stringArrayCodes.push(generator(def, { minified: true }).code) + // The calls can be found by its references + for (let ref of bind.referencePaths) { + if (ref?.listKey === 'arguments') { + // This is the rotate function + continue + } + if (ref.findParent((path) => path.removed)) { + continue + } + // the key is 'object' + let up1 = ref.getFunctionParent() + if (up1.node.id) { + // 2.12.0 <= v < 2.15.4 + // The `stringArrayCallsWrapperName` is included in the definition + obj.stringArrayCalls.push(up1.node.id.name) + obj.stringArrayCodes.push(generator(up1.node, { minified: true }).code) + up1.remove() + continue + } + if (up1.key === 'init') { + // v < 2.12.0 + // The `stringArrayCallsWrapperName` is defined by VariableDeclarator + up1 = up1.parentPath + obj.stringArrayCalls.push(up1.node.id.name) + up1 = up1.parentPath + obj.stringArrayCodes.push(generator(up1.node, { minified: true }).code) + up1.remove() + continue + } + // 2.15.4 <= v < 2.19.0 + // The function includes another function with the same name + up1 = up1.parentPath + const wrapper = up1.node.left.name + let up2 = up1.getFunctionParent() + if (!up2 || up2.node?.id?.name !== wrapper) { + console.warn('Unexpected reference!') + continue + } + obj.stringArrayCalls.push(wrapper) + obj.stringArrayCodes.push(generator(up2.node, { minified: true }).code) + up2.remove() + } + // Remove the string array + bind.path.remove() + // Add the rotate function + const node = t.expressionStatement(path.node) + obj.stringArrayCodes.push(generator(node, { minified: true }).code) + path.stop() + if (path.parentPath.isUnaryExpression()) { + path.parentPath.remove() + } else { + path.remove() + } + } + traverse(ast, { CallExpression: find_rotate_function }) + if (obj.stringArrayCodes.length < 3 || !obj.stringArrayCalls.length) { + console.error('Essential code missing!') + obj.stringArrayName = null + } + return obj +} + +/** + * Find the string-array codes by matching string-array function + * (valid version >= 2.19.0) + * + * @param {t.File} ast The ast file + * @returns Object + */ +function stringArrayV3(ast) { + console.info('Try v3 mode...') + let ob_func_str = [] + let ob_dec_name = [] + let ob_string_func_name = null + // Normally, the string array func ("func1") follows the template below: + // function aaa() { + // const bbb = [...] + // aaa = function () { + // return bbb; + // }; + // return aaa(); + // } + // In some cases (lint), the assignment is merged into the ReturnStatement + // After finding the possible func1, this method will check all the binding + // references and put the child encode function into list. + function find_string_array_function(path) { + if (path.getFunctionParent()) { + return + } + if ( + !t.isIdentifier(path.node.id) || + path.node.params.length || + !t.isBlockStatement(path.node.body) + ) { + return + } + const body = path.node.body.body + if (body.length < 2 || body.length > 3) { + return + } + const name_func = path.node.id.name + let string_var = -1 + try { + if ( + body[0].declarations.length != 1 || + !(string_var = body[0].declarations[0].id.name) || + !t.isArrayExpression(body[0].declarations[0].init) + ) { + return + } + const nodes = [...body] + nodes.shift() + const code = generator(t.BlockStatement(nodes)).code + const fp = `${name_func}=function(){return${string_var}}${name_func}()` + if (!checkPattern(code, fp)) { + return + } + } catch { + return + } + const binding = path.scope.getBinding(name_func) + if (!binding.referencePaths) { + return + } + let paths = binding.referencePaths + let nodes = [] + // The sorting function maybe missing in some config + function find2(refer_path) { + if ( + refer_path.parentPath.isCallExpression() && + refer_path.listKey === 'arguments' && + refer_path.key === 0 + ) { + let rm_path = refer_path.parentPath + if (rm_path.parentPath.isExpressionStatement()) { + rm_path = rm_path.parentPath + } + nodes.push([rm_path.node, 'func2']) + rm_path.remove() + } + } + paths.map(find2) + function find3(refer_path) { + if (refer_path.findParent((path) => path.removed)) { + return + } + if ( + refer_path.parentPath.isCallExpression() && + refer_path.key === 'callee' + ) { + let rm_path = refer_path.parentPath.getFunctionParent() + if (name_func == rm_path.node.id.name) { + return + } + nodes.push([rm_path.node, 'func3']) + rm_path.remove() + } else { + console.error('Unexpected reference') + } + } + paths.map(find3) + if (!name_func) { + return + } + ob_string_func_name = name_func + ob_func_str.push(generator(path.node, { minified: true }).code) + nodes.map(function (item) { + let node = item[0] + if (item[1] == 'func3') { + ob_dec_name.push(node.id.name) + } + if (t.isCallExpression(node)) { + node = t.expressionStatement(node) + } + ob_func_str.push(generator(node, { minified: true }).code) + }) + path.stop() + path.remove() + } + traverse(ast, { FunctionDeclaration: find_string_array_function }) + return { + version: 3, + stringArrayName: ob_string_func_name, + stringArrayCodes: ob_func_str, + stringArrayCalls: ob_dec_name, + } +} + +function decodeGlobal(ast) { + let obj = stringArrayV3(ast) + if (!obj.stringArrayName) { + obj = stringArrayV2(ast) + if (!obj.stringArrayName) { + console.error('Cannot find string list!') + return false + } + } + console.log(`String List Name: ${obj.stringArrayName}`) + let ob_func_str = obj.stringArrayCodes + let ob_dec_name = obj.stringArrayCalls + try { + virtualGlobalEval(ob_func_str.join(';')) + } catch (e) { + // issue #31 + if (e.name === 'ReferenceError') { + let lost = e.message.split(' ')[0] + traverse(ast, { + Program(path) { + ob_dec_name.push(lost) + let loc = path.scope.getBinding(lost).path + let obj = t.variableDeclaration(loc.parent.kind, [loc.node]) + ob_func_str.unshift(generator(obj, { minified: true }).code) + loc.remove() + path.stop() + }, + }) + virtualGlobalEval(ob_func_str.join(';')) + } + } + + // 循环删除混淆函数 + let call_dict = {} + let exist_names = ob_dec_name + let collect_codes = [] + let collect_names = [] + function do_parse_value(path) { + let name = path.node.callee.name + if (path.node.callee && exist_names.indexOf(name) != -1) { + let old_call = path + '' + try { + // 运行成功则说明函数为直接调用并返回字符串 + let new_str = virtualGlobalEval(old_call) + console.log(`map: ${old_call} -> ${new_str}`) + call_dict[old_call] = new_str + } catch (e) { + // 运行失败则说明函数为其它混淆函数的子函数 + console.log(`sub: ${old_call}`) + } + } + } + function do_collect_remove(path) { + // 可以删除所有已收集混淆函数的定义 + // 因为根函数已被删除 即使保留也无法运行 + let node = path.node?.left + if (!node) { + node = path.node?.id + } + let name = node?.name + if (exist_names.indexOf(name) != -1) { + // console.log(`del: ${name}`) + if (path.parentPath.isCallExpression()) { + path.replaceWith(node) + } else { + path.remove() + } + } + } + function do_collect_func_dec(path) { + // function A (...) { return function B (...) } + do_collect_func(path, path) + } + function do_collect_func_var(path) { + // var A = function (...) { return function B (...) } + let func_path = path.get('init') + if (!func_path.isFunctionExpression()) { + return + } + do_collect_func(path, func_path) + } + function do_collect_func(root, path) { + if ( + path.node.body.body.length == 1 && + path.node.body.body[0].type == 'ReturnStatement' && + path.node.body.body[0].argument?.type == 'CallExpression' && + path.node.body.body[0].argument.callee.type == 'Identifier' && + // path.node.params.length == 5 && + root.node.id + ) { + let call_func = path.node.body.body[0].argument.callee.name + if (exist_names.indexOf(call_func) == -1) { + return + } + let name = root.node.id.name + let t = generator(root.node, { minified: true }).code + if (collect_names.indexOf(name) == -1) { + collect_codes.push(t) + collect_names.push(name) + } else { + console.log(`err: redef ${name}`) + } + } + } + function do_collect_var(path) { + // var A = B + let left, right + if (t.isVariableDeclarator(path.node)) { + left = path.node.id + right = path.node.init + } else { + left = path.node.left + right = path.node.right + } + if (right?.type == 'Identifier' && exist_names.indexOf(right.name) != -1) { + let name = left.name + let t = 'var ' + generator(path.node, { minified: true }).code + if (collect_names.indexOf(name) == -1) { + collect_codes.push(t) + collect_names.push(name) + } else { + console.warning(`redef ${name}`) + } + } + } + while (exist_names.length) { + // 查找已收集混淆函数的调用并建立替换关系 + traverse(ast, { CallExpression: do_parse_value }) + // 删除被使用过的定义 + traverse(ast, { FunctionDeclaration: do_collect_remove }) + traverse(ast, { VariableDeclarator: do_collect_remove }) + traverse(ast, { AssignmentExpression: do_collect_remove }) + // 收集所有调用已收集混淆函数的混淆函数 + collect_codes = [] + collect_names = [] + traverse(ast, { FunctionDeclaration: do_collect_func_dec }) + traverse(ast, { VariableDeclarator: do_collect_func_var }) + traverse(ast, { VariableDeclarator: do_collect_var }) + traverse(ast, { AssignmentExpression: do_collect_var }) + exist_names = collect_names + // 执行找到的函数 + virtualGlobalEval(collect_codes.join(';')) + } + // 替换混淆函数 + function do_replace(path) { + let old_call = path + '' + if (Object.prototype.hasOwnProperty.call(call_dict, old_call)) { + path.replaceWith(t.StringLiteral(call_dict[old_call])) + } + } + traverse(ast, { CallExpression: do_replace }) + return true +} + +function stringArrayLite(ast) { + const visitor = { + VariableDeclarator(path) { + const name = path.node.id.name + if (!path.get('init').isArrayExpression()) { + return + } + const elements = path.node.init.elements + for (const element of elements) { + if (!t.isLiteral(element)) { + return + } + } + const bind = path.scope.getBinding(name) + if (!bind.constant) { + return + } + for (const ref of bind.referencePaths) { + if ( + !ref.parentPath.isMemberExpression() || + ref.key !== 'object' || + ref.parentPath.key == 'left' || + !t.isNumericLiteral(ref.parent.property) + ) { + return + } + } + console.log(`Extract string array: ${name}`) + for (const ref of bind.referencePaths) { + const i = ref.parent.property.value + ref.parentPath.replaceWith(elements[i]) + } + bind.scope.crawl() + path.remove() + }, + } + traverse(ast, visitor) +} + +function calcBinary(path) { + let tps = ['StringLiteral', 'BooleanLiteral', 'NumericLiteral'] + let nod = path.node + function judge(e) { + return ( + tps.indexOf(e.type) != -1 || + (e.type == 'UnaryExpression' && tps.indexOf(e.argument.type) != -1) + ) + } + function make_rep(e) { + if (typeof e == 'number') { + return t.NumericLiteral(e) + } + if (typeof e == 'string') { + return t.StringLiteral(e) + } + if (typeof e == 'boolean') { + return t.BooleanLiteral(e) + } + throw Error('unknown type' + typeof e) + } + if (judge(nod.left) && judge(nod.right)) { + path.replaceWith(make_rep(eval(path + ''))) + } +} + +function decodeCodeBlock(ast) { + // 合并字面量 + traverse(ast, { BinaryExpression: { exit: calcBinary } }) + // 先合并分离的Object定义 + const mergeObject = require('../visitor/merge-object') + traverse(ast, mergeObject) + // 在变量定义完成后判断是否为代码块加密内容 + const parseControlFlowStorage = require('../visitor/parse-control-flow-storage') + traverse(ast, parseControlFlowStorage) + // 合并字面量(在解除区域混淆后会出现新的可合并分割) + traverse(ast, { BinaryExpression: { exit: calcBinary } }) + return ast +} + +function purifyBoolean(path) { + // 简化 ![] 和 !![] + const node0 = path.node + if (node0.operator !== '!') { + return + } + const node1 = node0.argument + if (t.isArrayExpression(node1) && node1.elements.length === 0) { + path.replaceWith(t.booleanLiteral(false)) + return + } + if (!t.isUnaryExpression(node1) || node1.operator !== '!') { + return + } + const node2 = node1.argument + if (t.isArrayExpression(node2) && node2.elements.length === 0) { + path.replaceWith(t.booleanLiteral(true)) + } +} + +function cleanIFCode(path) { + function clear(path, toggle) { + // 判定成立 + if (toggle) { + if (path.node.consequent.type == 'BlockStatement') { + path.replaceWithMultiple(path.node.consequent.body) + } else { + path.replaceWith(path.node.consequent) + } + return + } + // 判定不成立 + if (!path.node.alternate) { + path.remove() + return + } + if (path.node.alternate.type == 'BlockStatement') { + path.replaceWithMultiple(path.node.alternate.body) + } else { + path.replaceWith(path.node.alternate) + } + } + // 判断判定是否恒定 + const test = path.node.test + const types = ['StringLiteral', 'NumericLiteral', 'BooleanLiteral'] + if (test.type === 'BinaryExpression') { + if ( + types.indexOf(test.left.type) !== -1 && + types.indexOf(test.right.type) !== -1 + ) { + const left = JSON.stringify(test.left.value) + const right = JSON.stringify(test.right.value) + clear(path, eval(left + test.operator + right)) + } + } else if (types.indexOf(test.type) !== -1) { + clear(path, eval(JSON.stringify(test.value))) + } +} + +function cleanSwitchCode(path) { + // 扁平控制: + // 会使用一个恒为true的while语句包裹一个switch语句 + // switch语句的执行顺序又while语句上方的字符串决定 + // 首先碰断是否符合这种情况 + const node = path.node + let valid = false + if (t.isBooleanLiteral(node.test) && node.test.value) { + valid = true + } + if (t.isArrayExpression(node.test) && node.test.elements.length === 0) { + valid = true + } + if (!valid) { + return + } + if (!t.isBlockStatement(node.body)) { + return + } + const body = node.body.body + if ( + !t.isSwitchStatement(body[0]) || + !t.isMemberExpression(body[0].discriminant) || + !t.isBreakStatement(body[1]) + ) { + return + } + // switch语句的两个变量 + const swithStm = body[0] + const arrName = swithStm.discriminant.object.name + const argName = swithStm.discriminant.property.argument.name + // 在while上面的节点寻找这两个变量 + let arr = [] + let rm = [] + path.getAllPrevSiblings().forEach((pre_path) => { + if (!pre_path.isVariableDeclaration()) { + return + } + for (let i = 0; i < pre_path.node.declarations.length; ++i) { + const declaration = pre_path.get(`declarations.${i}`) + let { id, init } = declaration.node + if (arrName == id.name) { + if (t.isStringLiteral(init?.callee?.object)) { + arr = init.callee.object.value.split('|') + rm.push(declaration) + } + } + if (argName == id.name) { + if (t.isLiteral(init)) { + rm.push(declaration) + } + } + } + }) + if (rm.length !== 2) { + return + } + rm.forEach((pre_path) => { + pre_path.remove() + }) + console.log(`扁平化还原: ${arrName}[${argName}]`) + // 重建代码块 + const caseList = swithStm.cases + let resultBody = [] + arr.map((targetIdx) => { + // 从当前序号开始直到遇到continue + let valid = true + targetIdx = parseInt(targetIdx) + while (valid && targetIdx < caseList.length) { + const targetBody = caseList[targetIdx].consequent + const test = caseList[targetIdx].test + if (!t.isStringLiteral(test) || parseInt(test.value) !== targetIdx) { + console.log(`switch中出现乱序的序号: ${test.value}:${targetIdx}`) + } + for (let i = 0; i < targetBody.length; ++i) { + const s = targetBody[i] + if (t.isContinueStatement(s)) { + valid = false + break + } + if (t.isReturnStatement(s)) { + valid = false + resultBody.push(s) + break + } + if (t.isBreakStatement(s)) { + console.log(`switch中出现意外的break: ${arrName}[${argName}]`) + } else { + resultBody.push(s) + } + } + targetIdx++ + } + }) + // 替换整个while语句 + path.replaceInline(resultBody) +} + +function cleanDeadCode(ast) { + traverse(ast, { UnaryExpression: purifyBoolean }) + traverse(ast, { IfStatement: cleanIFCode }) + traverse(ast, { ConditionalExpression: cleanIFCode }) + traverse(ast, { WhileStatement: { exit: cleanSwitchCode } }) + return ast +} + +const splitVariableDeclarator = { + VariableDeclarator(path) { + const init = path.get('init') + if (!init.isAssignmentExpression()) { + return + } + path.parentPath.insertBefore(init.node) + init.replaceWith(init.node.left) + path.parentPath.scope.crawl() + }, +} + +function standardIfStatement(path) { + const consequent = path.get('consequent') + const alternate = path.get('alternate') + const test = path.get('test') + const evaluateTest = test.evaluateTruthy() + + if (!consequent.isBlockStatement()) { + consequent.replaceWith(t.BlockStatement([consequent.node])) + } + if (alternate.node !== null && !alternate.isBlockStatement()) { + alternate.replaceWith(t.BlockStatement([alternate.node])) + } + + if (consequent.node.body.length == 0) { + if (alternate.node == null) { + path.replaceWith(test.node) + } else { + consequent.replaceWith(alternate.node) + alternate.remove() + path.node.alternate = null + test.replaceWith(t.unaryExpression('!', test.node, true)) + } + } + + if (alternate.isBlockStatement() && alternate.node.body.length == 0) { + alternate.remove() + path.node.alternate = null + } + + if (evaluateTest === true) { + path.replaceWithMultiple(consequent.node.body) + } else if (evaluateTest === false) { + alternate.node === null + ? path.remove() + : path.replaceWithMultiple(alternate.node.body) + } +} + +function standardLoop(path) { + const node = path.node + if (!t.isBlockStatement(node.body)) { + node.body = t.BlockStatement([node.body]) + } +} + +function splitSequence(path) { + let { scope, parentPath, node } = path + let expressions = node.expressions + if (parentPath.isReturnStatement({ argument: node })) { + let lastExpression = expressions.pop() + for (let expression of expressions) { + parentPath.insertBefore(t.ExpressionStatement(expression)) + } + + path.replaceInline(lastExpression) + } else if (parentPath.isExpressionStatement({ expression: node })) { + let body = [] + expressions.forEach((express) => { + body.push(t.ExpressionStatement(express)) + }) + path.replaceInline(body) + } else { + return + } + + scope.crawl() +} + +function purifyCode(ast) { + // 标准化if语句 + traverse(ast, { IfStatement: standardIfStatement }) + // 标准化for语句 + traverse(ast, { ForStatement: standardLoop }) + // 标准化while语句 + traverse(ast, { WhileStatement: standardLoop }) + // 删除空语句 + traverse(ast, { + EmptyStatement: (path) => { + path.remove() + }, + }) + // 删除未使用的变量 + traverse(ast, splitVariableDeclarator) + const deleteUnusedVar = require('../visitor/delete-unused-var') + traverse(ast, deleteUnusedVar) + // 替换索引器 + function FormatMember(path) { + let curNode = path.node + if (!t.isStringLiteral(curNode.property)) { + return + } + if (curNode.computed === undefined || !curNode.computed === true) { + return + } + if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(curNode.property.value)) { + return + } + curNode.property = t.identifier(curNode.property.value) + curNode.computed = false + } + traverse(ast, { MemberExpression: FormatMember }) + + // 替换类和对象的计算方法和计算属性 + // ["method"](){} -> "method"(){} + function FormatComputed(path) { + let curNode = path.node + if (!t.isStringLiteral(curNode.key)) { + return + } + curNode.computed = false + } + // "method"(){} -> method(){} + function stringLiteralToIdentifier(path) { + let curNode = path.node + if (!t.isStringLiteral(curNode.key) || curNode.computed === true) { + return + } + if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(curNode.key.value)) { + return + } + curNode.key = t.identifier(curNode.key.value) + } + traverse(ast, { + 'Method|Property': (path) => { + FormatComputed(path) + stringLiteralToIdentifier(path) + }, + }) + + // 拆分语句 + traverse(ast, { SequenceExpression: splitSequence }) + return ast +} + +function checkPattern(code, pattern) { + let i = 0 + let j = 0 + while (i < code.length && j < pattern.length) { + if (code[i] == pattern[j]) { + ++j + } + ++i + } + return j == pattern.length +} + +const deleteSelfDefendingCode = { + VariableDeclarator(path) { + const { id, init } = path.node + const selfName = id.name + if (!t.isCallExpression(init)) { + return + } + if (!t.isIdentifier(init.callee)) { + return + } + const callName = init.callee.name + const args = init.arguments + if ( + args.length != 2 || + !t.isThisExpression(args[0]) || + !t.isFunctionExpression(args[1]) + ) { + return + } + const block = generator(args[1]).code + const patterns = [ + // @7920538 + `return${selfName}.toString().search().toString().constructor(${selfName}).search()`, + // @7135b09 + `const=function(){const=.constructor()return.test(${selfName})}return()`, + // #94 + `var=function(){var=.constructor()return.test(${selfName})}return()`, + ] + let valid = false + for (let pattern of patterns) { + valid |= checkPattern(block, pattern) + } + if (!valid) { + return + } + const refs = path.scope.bindings[selfName].referencePaths + for (let ref of refs) { + if (ref.key == 'callee') { + ref.parentPath.remove() + break + } + } + path.remove() + console.info(`Remove SelfDefendingFunc: ${selfName}`) + const scope = path.scope.getBinding(callName).scope + scope.crawl() + const bind = scope.bindings[callName] + if (bind.referenced) { + console.error(`Call func ${callName} unexpected ref!`) + } + bind.path.remove() + console.info(`Remove CallFunc: ${callName}`) + }, +} + +const deleteDebugProtectionCode = { + FunctionDeclaration(path) { + const { id, params, body } = path.node + if ( + !t.isIdentifier(id) || + params.length !== 1 || + !t.isIdentifier(params[0]) || + !t.isBlockStatement(body) || + body.body.length !== 2 || + !t.isFunctionDeclaration(body.body[0]) || + !t.isTryStatement(body.body[1]) + ) { + return + } + const debugName = id.name + const ret = params[0].name + const subNode = body.body[0] + if ( + !t.isIdentifier(subNode.id) || + subNode.params.length !== 1 || + !t.isIdentifier(subNode.params[0]) + ) { + return + } + const subName = subNode.id.name + const counter = subNode.params[0].name + const code = generator(body).code + const pattern = `function${subName}(${counter}){${counter}debugger${subName}(++${counter})}try{if(${ret})return${subName}${subName}(0)}catch(){}` + if (!checkPattern(code, pattern)) { + return + } + const scope1 = path.parentPath.scope + const refs = scope1.bindings[debugName].referencePaths + for (let ref of refs) { + if (ref.findParent((path) => path.removed)) { + continue + } + if (ref.key == 0) { + // DebugProtectionFunctionInterval @e8e92c6 + const rm = ref.getFunctionParent().parentPath + rm.remove() + continue + } + // ref.key == 'callee' + const up1 = ref.getFunctionParent() + const callName = up1.parent.callee.name + if (callName === 'setInterval') { + // DebugProtectionFunctionInterval @51523c0 + const rm = up1.parentPath + rm.remove() + continue + } + const up2 = up1.getFunctionParent()?.parentPath + if (up2) { + // DebugProtectionFunctionCall + const scope2 = up2.scope.getBinding(callName).scope + up2.remove() + scope1.crawl() + scope2.crawl() + const bind = scope2.bindings[callName] + bind.path.remove() + console.info(`Remove CallFunc: ${callName}`) + continue + } + // exceptions #95 + const rm = ref.parentPath + rm.remove() + } + path.remove() + console.info(`Remove DebugProtectionFunc: ${debugName}`) + }, +} + +const deleteConsoleOutputCode = { + VariableDeclarator(path) { + const { id, init } = path.node + const selfName = id.name + if (!t.isCallExpression(init)) { + return + } + if (!t.isIdentifier(init.callee)) { + return + } + const callName = init.callee.name + const args = init.arguments + if ( + args.length != 2 || + !t.isThisExpression(args[0]) || + !t.isFunctionExpression(args[1]) + ) { + return + } + const block = generator(args[1]).code + const pattern = `console=console=log,warn,info,error,for(){${callName}constructor.prototype.bind${callName}${callName}bind${callName}}` + if (!checkPattern(block, pattern)) { + return + } + const refs = path.scope.bindings[selfName].referencePaths + for (let ref of refs) { + if (ref.key == 'callee') { + ref.parentPath.remove() + break + } + } + path.remove() + console.info(`Remove ConsoleOutputFunc: ${selfName}`) + const scope = path.scope.getBinding(callName).scope + scope.crawl() + const bind = scope.bindings[callName] + if (bind.referenced) { + console.error(`Call func ${callName} unexpected ref!`) + } + bind.path.remove() + console.info(`Remove CallFunc: ${callName}`) + }, +} + +function unlockEnv(ast) { + //可能会误删一些代码,可屏蔽 + traverse(ast, deleteSelfDefendingCode) + traverse(ast, deleteDebugProtectionCode) + traverse(ast, deleteConsoleOutputCode) + return ast +} + +module.exports = function (code) { + let ret = PluginEval.unpack(code) + let global_eval = false + if (ret) { + global_eval = true + code = ret + } + let ast + try { + ast = parse(code, { errorRecovery: true }) + } catch (e) { + console.error(`Cannot parse code: ${e.reasonCode}`) + return null + } + // IllegalReturn + const deleteIllegalReturn = require('../visitor/delete-illegal-return') + traverse(ast, deleteIllegalReturn) + // 清理二进制显示内容 + traverse(ast, { + StringLiteral: ({ node }) => { + delete node.extra + }, + NumericLiteral: ({ node }) => { + delete node.extra + }, + }) + console.log('还原数值...') + if (!decodeObject(ast)) { + return null + } + console.log('处理全局加密...') + if (!decodeGlobal(ast)) { + return null + } + console.log('提高代码可读性...') + ast = purifyCode(ast) + console.log('处理代码块加密...') + stringArrayLite(ast) + ast = decodeCodeBlock(ast) + console.log('清理死代码...') + ast = cleanDeadCode(ast) + // 刷新代码 + ast = parse( + generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code, + { errorRecovery: true } + ) + console.log('提高代码可读性...') + ast = purifyCode(ast) + console.log('解除环境限制...') + ast = unlockEnv(ast) + console.log('净化完成') + code = generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code + if (global_eval) { + code = PluginEval.pack(code) + } + return code +} diff --git a/src/plugin/sojson.js b/src/plugin/sojson.js new file mode 100644 index 000000000..cf01508b2 --- /dev/null +++ b/src/plugin/sojson.js @@ -0,0 +1,657 @@ +/** + * 在 babel_asttool.js 的基础上修改而来 + */ +const { parse } = require('@babel/parser') +const generator = require('@babel/generator').default +const traverse = require('@babel/traverse').default +const t = require('@babel/types') +const ivm = require('isolated-vm') +const PluginEval = require('./eval.js') + +const isolate = new ivm.Isolate() +const globalContext = isolate.createContextSync() +function virtualGlobalEval(jsStr) { + return globalContext.evalSync(String(jsStr)) +} + +function decodeGlobal(ast) { + // 清理空语句 + let i = 0 + while (i < ast.program.body.length) { + if (t.isEmptyStatement(ast.program.body[i])) { + ast.program.body.splice(i, 1) + } else { + ++i + } + } + // 前3句非空语句分别为签名信息、预处理函数、解密函数。 + if (i < 3) { + console.log('Error: code too short') + return false + } + // 分离解密语句与内容语句 + let decrypt_code = ast.program.body.slice(0, 3) + if (!t.isVariableDeclaration(decrypt_code[0])) { + console.log('Error: line 1 is not variable declaration') + return false + } + let decrypt_fun = decrypt_code[2] + if (t.isExpressionStatement(decrypt_fun)) { + decrypt_fun = decrypt_code[1] + } + let decrypt_val + if (t.isVariableDeclaration(decrypt_fun)) { + decrypt_val = decrypt_fun.declarations[0].id.name + } else if (t.isFunctionDeclaration(decrypt_fun)) { + decrypt_val = decrypt_fun.id.name + } else { + console.log('Error: cannot find decrypt variable') + return false + } + console.log(`主加密变量: ${decrypt_val}`) + let content_code = ast.program.body.slice(3) + // 运行解密语句 + ast.program.body = decrypt_code + let { code } = generator(ast, { + compact: true, + }) + virtualGlobalEval(code) + // 遍历内容语句 + function funToStr(path) { + let node = path.node + if (!t.isIdentifier(node.callee, { name: decrypt_val })) { + return + } + let tmp = path.toString() + let value = virtualGlobalEval(tmp) + // console.log(`还原前:${tmp} 还原后:${value}`) + path.replaceWith(t.valueToNode(value)) + } + function memToStr(path) { + let node = path.node + if (!t.isIdentifier(node.object, { name: decrypt_val })) { + return + } + let tmp = path.toString() + let value = virtualGlobalEval(tmp) + // console.log(`还原前:${tmp} 还原后:${value}`) + path.replaceWith(t.valueToNode(value)) + } + ast.program.body = content_code + traverse(ast, { + CallExpression: funToStr, + MemberExpression: memToStr, + }) + return ast +} + +function purifyBoolean(path) { + // 简化 ![] 和 !![] + const node0 = path.node + if (node0.operator !== '!') { + return + } + const node1 = node0.argument + if (t.isArrayExpression(node1) && node1.elements.length === 0) { + path.replaceWith(t.booleanLiteral(false)) + return + } + if (!t.isUnaryExpression(node1) || node1.operator !== '!') { + return + } + const node2 = node1.argument + if (t.isArrayExpression(node2) && node2.elements.length === 0) { + path.replaceWith(t.booleanLiteral(true)) + } +} + +function cleanIFCode(path) { + function clear(path, toggle) { + // 判定成立 + if (toggle) { + if (path.node.consequent.type == 'BlockStatement') { + path.replaceWithMultiple(path.node.consequent.body) + } else { + path.replaceWith(path.node.consequent) + } + return + } + // 判定不成立 + if (!path.node.alternate) { + path.remove() + return + } + if (path.node.alternate.type == 'BlockStatement') { + path.replaceWithMultiple(path.node.alternate.body) + } else { + path.replaceWith(path.node.alternate) + } + } + // 判断判定是否恒定 + const test = path.node.test + const types = ['StringLiteral', 'NumericLiteral', 'BooleanLiteral'] + if (test.type === 'BinaryExpression') { + if ( + types.indexOf(test.left.type) !== -1 && + types.indexOf(test.right.type) !== -1 + ) { + const left = JSON.stringify(test.left.value) + const right = JSON.stringify(test.right.value) + clear(path, eval(left + test.operator + right)) + } + } else if (types.indexOf(test.type) !== -1) { + clear(path, eval(JSON.stringify(test.value))) + } +} + +function cleanSwitchCode(path) { + // 扁平控制: + // 会使用一个恒为true的while语句包裹一个switch语句 + // switch语句的执行顺序又while语句上方的字符串决定 + // 首先碰断是否符合这种情况 + const node = path.node + if (!(t.isBooleanLiteral(node.test) || t.isUnaryExpression(node.test))) { + return + } + if (!(node.test.prefix || node.test.value)) { + return + } + if (!t.isBlockStatement(node.body)) { + return + } + const body = node.body.body + if ( + !t.isSwitchStatement(body[0]) || + !t.isMemberExpression(body[0].discriminant) || + !t.isBreakStatement(body[1]) + ) { + return + } + // switch语句的两个变量 + const swithStm = body[0] + const arrName = swithStm.discriminant.object.name + const argName = swithStm.discriminant.property.argument.name + console.log(`扁平化还原: ${arrName}[${argName}]`) + // 在while上面的节点寻找这两个变量 + let arr = [] + path.getAllPrevSiblings().forEach((pre_path) => { + const { declarations } = pre_path.node + let { id, init } = declarations[0] + if (arrName == id.name) { + arr = init.callee.object.value.split('|') + pre_path.remove() + } + if (argName == id.name) { + pre_path.remove() + } + }) + // 重建代码块 + const caseList = swithStm.cases + let resultBody = [] + arr.map((targetIdx) => { + // 从当前序号开始直到遇到continue + let valid = true + targetIdx = parseInt(targetIdx) + while (valid && targetIdx < caseList.length) { + const targetBody = caseList[targetIdx].consequent + const test = caseList[targetIdx].test + if (!t.isStringLiteral(test) || parseInt(test.value) !== targetIdx) { + console.log(`switch中出现乱序的序号: ${test.value}:${targetIdx}`) + } + for (let i = 0; i < targetBody.length; ++i) { + const s = targetBody[i] + if (t.isContinueStatement(s)) { + valid = false + break + } + if (t.isReturnStatement(s)) { + valid = false + resultBody.push(s) + break + } + if (t.isBreakStatement(s)) { + console.log(`switch中出现意外的break: ${arrName}[${argName}]`) + } else { + resultBody.push(s) + } + } + targetIdx++ + } + }) + // 替换整个while语句 + path.replaceInline(resultBody) +} + +function cleanDeadCode(ast) { + traverse(ast, { UnaryExpression: purifyBoolean }) + traverse(ast, { IfStatement: cleanIFCode }) + traverse(ast, { ConditionalExpression: cleanIFCode }) + traverse(ast, { WhileStatement: { exit: cleanSwitchCode } }) + return ast +} + +function checkPattern(code, pattern) { + let i = 0 + let j = 0 + while (i < code.length && j < pattern.length) { + if (code[i] == pattern[j]) { + ++j + } + ++i + } + return j == pattern.length +} + +/** + * Two RegExp tests will be conducted here: + * * If '\n' exists (code formatted) + * * If '\u' or '\x' does not exist (literal formatted) + * + * An infinite call stack will appear if either of the test fails. + * (by replacing the 'e' with '\u0435') + */ +const deleteSelfDefendingCode = { + VariableDeclarator(path) { + const { id, init } = path.node + const selfName = id.name + if (!t.isCallExpression(init)) { + return + } + if (!t.isIdentifier(init.callee)) { + return + } + const callName = init.callee.name + const args = init.arguments + if ( + args.length != 2 || + !t.isThisExpression(args[0]) || + !t.isFunctionExpression(args[1]) + ) { + return + } + const block = generator(args[1]).code + const pattern = `RegExp()return.test(.toString())RegExp()return.test(.toString())\u0435\u0435` + if (!checkPattern(block, pattern)) { + return + } + const refs = path.scope.bindings[selfName].referencePaths + for (let ref of refs) { + if (ref.key == 'callee') { + ref.parentPath.remove() + break + } + } + path.remove() + console.info(`Remove SelfDefendingFunc: ${selfName}`) + const scope = path.scope.getBinding(callName).scope + scope.crawl() + const bind = scope.bindings[callName] + if (bind.referenced) { + console.error(`Call func ${callName} unexpected ref!`) + } + bind.path.remove() + console.info(`Remove CallFunc: ${callName}`) + }, +} + +/** + * A "debugger" will be inserted by: + * * v5: directly. + * * v6: calling Function constructor twice. + */ +const deleteDebugProtectionCode = { + FunctionDeclaration(path) { + const { id, params, body } = path.node + if ( + !t.isIdentifier(id) || + params.length !== 1 || + !t.isIdentifier(params[0]) || + !t.isBlockStatement(body) || + body.body.length !== 2 || + !t.isFunctionDeclaration(body.body[0]) || + !t.isTryStatement(body.body[1]) + ) { + return + } + const debugName = id.name + const ret = params[0].name + const subNode = body.body[0] + if ( + !t.isIdentifier(subNode.id) || + subNode.params.length !== 1 || + !t.isIdentifier(subNode.params[0]) + ) { + return + } + const subName = subNode.id.name + const counter = subNode.params[0].name + const code = generator(body).code + const pattern = `function${subName}(${counter}){${counter}debug${subName}(++${counter})}try{if(${ret})return${subName}${subName}(0)}catch(){}` + if (!checkPattern(code, pattern)) { + return + } + const scope1 = path.parentPath.scope + const refs = scope1.bindings[debugName].referencePaths + for (let ref of refs) { + if (ref.findParent((path) => path.removed)) { + continue + } + let parent = ref.getFunctionParent() + if (parent.key == 0) { + // DebugProtectionFunctionInterval + // window.setInterval(Function(), ...) + const rm = parent.parentPath + rm.remove() + continue + } + // DebugProtectionFunctionCall + const callName = parent.parent.callee.name + const up2 = parent.getFunctionParent().parentPath + const scope2 = up2.scope.getBinding(callName).scope + up2.remove() + scope1.crawl() + scope2.crawl() + const bind = scope2.bindings[callName] + bind.path.remove() + console.info(`Remove CallFunc: ${callName}`) + } + path.remove() + console.info(`Remove DebugProtectionFunc: ${debugName}`) + }, +} + +const deleteConsoleOutputCode = { + VariableDeclarator(path) { + const { id, init } = path.node + const selfName = id.name + if (!t.isCallExpression(init)) { + return + } + if (!t.isIdentifier(init.callee)) { + return + } + const callName = init.callee.name + const args = init.arguments + if ( + args.length != 2 || + !t.isThisExpression(args[0]) || + !t.isFunctionExpression(args[1]) + ) { + return + } + const body = args[1].body.body + if (body.length !== 3) { + return + } + if ( + !t.isVariableDeclaration(body[0]) || + !t.isVariableDeclaration(body[1]) || + !t.isIfStatement(body[2]) + ) { + return + } + const feature = [ + [], + ['window', 'process', 'require', 'global'], + [ + 'console', + 'log', + 'warn', + 'debug', + 'info', + 'error', + 'exception', + 'trace', + ], + ] + let valid = true + for (let i = 1; i < 3; ++i) { + const { code } = generator(body[i]) + feature[i].map((key) => { + if (code.indexOf(key) == -1) { + valid = false + } + }) + } + if (!valid) { + return + } + const refs = path.scope.bindings[selfName].referencePaths + for (let ref of refs) { + if (ref.key == 'callee') { + ref.parentPath.remove() + break + } + } + path.remove() + console.info(`Remove ConsoleOutputFunc: ${selfName}`) + const scope = path.scope.getBinding(callName).scope + scope.crawl() + const bind = scope.bindings[callName] + if (bind.referenced) { + console.error(`Call func ${callName} unexpected ref!`) + } + bind.path.remove() + console.info(`Remove CallFunc: ${callName}`) + }, +} + +const deleteVersionCheck = { + StringLiteral(path) { + const msg = '删除版本号,js会定期弹窗,还请支持我们的工作' + if (path.node.value !== msg) { + return + } + let fnPath = path.getFunctionParent().parentPath + if (!fnPath.isCallExpression()) { + return + } + fnPath.remove() + console.log('Remove VersionCheck') + }, +} + +function unlockEnv(ast) { + // 查找并删除`自卫模式`函数 + traverse(ast, deleteSelfDefendingCode) + // 查找并删除`禁止控制台调试`函数 + traverse(ast, deleteDebugProtectionCode) + // 清空`禁止控制台输出`函数 + traverse(ast, deleteConsoleOutputCode) + // 删除版本号检测 + traverse(ast, deleteVersionCheck) + return ast +} + +function purifyFunction(path) { + const node = path.node + if (!t.isIdentifier(node.left) || !t.isFunctionExpression(node.right)) { + return + } + const name = node.left.name + if (node.right.body.body.length !== 1) { + return + } + let retStmt = node.right.body.body[0] + if (!t.isReturnStatement(retStmt)) { + return + } + if (!t.isBinaryExpression(retStmt.argument, { operator: '+' })) { + return + } + try { + const fnPath = path.getFunctionParent() || path.scope.path + fnPath.traverse({ + CallExpression: function (_path) { + const _node = _path.node.callee + if (!t.isIdentifier(_node, { name: name })) { + return + } + let args = _path.node.arguments + _path.replaceWith(t.binaryExpression('+', args[0], args[1])) + }, + }) + path.remove() + console.log(`拼接类函数: ${name}`) + } catch { + let code = generator(path.node, { minified: true }).code + console.warn('Purify function failed: ' + code) + } +} + +function purifyCode(ast) { + // 净化拼接字符串的函数 + traverse(ast, { AssignmentExpression: purifyFunction }) + // 净化变量定义中的常量数值 + function purifyDecl(path) { + if (t.isNumericLiteral(path.node.init)) { + return + } + const name = path.node.id.name + const { code } = generator( + { + type: 'Program', + body: [path.node.init], + }, + { + compact: true, + } + ) + const valid = /^[-+*/%!<>&|~^ 0-9;]+$/.test(code) + if (!valid) { + return + } + if (/^[-][0-9]*$/.test(code)) { + return + } + const value = eval(code) + const node = t.valueToNode(value) + path.replaceWith(t.variableDeclarator(path.node.id, node)) + console.log(`替换 ${name}: ${code} -> ${value}`) + } + traverse(ast, { VariableDeclarator: purifyDecl }) + // 合并字符串 + let end = false + function combineString(path) { + const op = path.node.operator + if (op !== '+') { + return + } + const left = path.node.left + const right = path.node.right + if (!t.isStringLiteral(left) || !t.isStringLiteral(right)) { + return + } + end = false + path.replaceWith(t.StringLiteral(eval(path + ''))) + console.log(`合并字符串: ${path.node.value}`) + } + while (!end) { + end = true + traverse(ast, { BinaryExpression: combineString }) + } + // 替换索引器 + function FormatMember(path) { + // _0x19882c['removeCookie']['toString']() + // | + // | + // | + // v + // _0x19882c.removeCookie.toString() + let curNode = path.node + if (!t.isStringLiteral(curNode.property)) { + return + } + if (curNode.computed === undefined || !curNode.computed === true) { + return + } + if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(curNode.property.value)) { + return + } + curNode.property = t.identifier(curNode.property.value) + curNode.computed = false + } + traverse(ast, { MemberExpression: FormatMember }) + // 分割表达式 + function removeComma(path) { + // a = 1, b = ddd(), c = null; + // | + // | + // | + // v + // a = 1; + // b = ddd(); + // c = null; + let { expression } = path.node + if (!t.isSequenceExpression(expression)) { + return + } + let body = [] + expression.expressions.forEach((express) => { + body.push(t.expressionStatement(express)) + }) + path.replaceInline(body) + } + traverse(ast, { ExpressionStatement: removeComma }) + // 删除空语句 + traverse(ast, { + EmptyStatement: (path) => { + path.remove() + }, + }) + // 删除未使用的变量 + const deleteUnusedVar = require('../visitor/delete-unused-var') + traverse(ast, deleteUnusedVar) + return ast +} + +module.exports = function (code) { + let ret = PluginEval.unpack(code) + let global_eval = false + if (ret) { + global_eval = true + code = ret + } + let ast = parse(code) + // 清理二进制显示内容 + traverse(ast, { + StringLiteral: ({ node }) => { + delete node.extra + }, + }) + traverse(ast, { + NumericLiteral: ({ node }) => { + delete node.extra + }, + }) + console.log('处理全局加密...') + ast = decodeGlobal(ast) + if (!ast) { + return null + } + console.log('处理代码块加密...') + const parseControlFlowStorage = require('../visitor/parse-control-flow-storage') + traverse(ast, parseControlFlowStorage) + console.log('清理死代码...') + ast = cleanDeadCode(ast) + // 刷新代码 + ast = parse( + generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code + ) + console.log('提高代码可读性...') + ast = purifyCode(ast) + console.log('解除环境限制...') + ast = unlockEnv(ast) + console.log('净化完成') + code = generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code + if (global_eval) { + code = PluginEval.pack(code) + } + return code +} diff --git a/src/plugin/sojsonv7.js b/src/plugin/sojsonv7.js new file mode 100644 index 000000000..19d351bd4 --- /dev/null +++ b/src/plugin/sojsonv7.js @@ -0,0 +1,914 @@ +/** + * For jsjiami.com.v7 + */ +const { parse } = require('@babel/parser') +const generator = require('@babel/generator').default +const traverse = require('@babel/traverse').default +const t = require('@babel/types') +const ivm = require('isolated-vm') +const PluginEval = require('./eval.js') + +const isolate = new ivm.Isolate() +const globalContext = isolate.createContextSync() +function virtualGlobalEval(jsStr) { + return globalContext.evalSync(String(jsStr)) +} + +function decodeGlobal(ast) { + // 清理空语句 + let i = 0 + while (i < ast.program.body.length) { + if (t.isEmptyStatement(ast.program.body[i])) { + ast.program.body.splice(i, 1) + } else { + ++i + } + } + // line 1: version and string table + // line x: preprocessing function of string table + // line y: main encode function containing the var of string table + if (i < 3) { + console.log('Error: code too short') + return false + } + // split the first line + traverse(ast, { + Program(path) { + path.stop() + const l1 = path.get('body.0') + if (!l1.isVariableDeclaration()) { + return + } + const defs = l1.node.declarations + const kind = l1.node.kind + for (let i = defs.length - 1; i; --i) { + l1.insertAfter(t.VariableDeclaration(kind, [defs[i]])) + l1.get(`declarations.${i}`).remove() + } + l1.scope.crawl() + }, + }) + // find the main encode function + // [version, string-array, call, ...] + let decrypt_code = [] + for (let i = 0; i < 3; ++i) { + decrypt_code.push(t.EmptyStatement()) + } + const first_line = ast.program.body[0] + let var_version + if (t.isVariableDeclaration(first_line)) { + if (first_line.declarations.length) { + var_version = first_line.declarations[0].id.name + } + } else if (t.isCallExpression(first_line?.expression)) { + let call_func = first_line.expression.callee?.name + let i = ast.program.body.length + let find = false + while (--i) { + let part = ast.program.body[i] + if (!t.isFunctionDeclaration(part) || part?.id?.name !== call_func) { + continue + } + if (find) { + // remove duplicate definition + ast.program.body[i] = t.emptyStatement() + continue + } + find = true + let obj = part.body.body[0]?.expression?.left + if (!obj || !t.isMemberExpression(obj) || obj.object?.name !== 'global') { + break + } + var_version = obj.property?.value + decrypt_code.push(part) + ast.program.body[i] = t.emptyStatement() + continue + } + } + if (!var_version) { + console.error('Line 1 is not version variable!') + return false + } + console.info(`Version var: ${var_version}`) + decrypt_code[0] = first_line + ast.program.body.shift() + + // iterate and classify all refs of var_version + const refs = { + string_var: null, + string_path: null, + def: [], + } + traverse(ast, { + Identifier: (path) => { + const name = path.node.name + if (name !== var_version) { + return + } + const up1 = path.parentPath + if (up1.isVariableDeclarator()) { + refs.def.push(path) + } else if (up1.isArrayExpression()) { + let node_table = path.getFunctionParent() + while (node_table.getFunctionParent()) { + node_table = node_table.getFunctionParent() + } + let var_string_table = null + if (node_table.node.id) { + var_string_table = node_table.node.id.name + } else { + while (!node_table.isVariableDeclarator()) { + node_table = node_table.parentPath + } + var_string_table = node_table.node.id.name + } + let valid = true + up1.traverse({ + MemberExpression(path) { + valid = false + path.stop() + }, + }) + if (valid) { + refs.string_var = var_string_table + refs.string_path = node_table + } else { + console.info(`Drop string table: ${var_string_table}`) + } + } else if (up1.isAssignmentExpression() && path.key === 'left') { + // We don't need to execute this reference + // Instead, we can delete it directly + const up2 = up1.parentPath + up2.replaceWith(up2.node.left) + } else { + console.warn(`Unexpected ref var_version: ${up1}`) + } + }, + }) + // check if contains string table + let var_string_table = refs.string_var + if (!var_string_table) { + console.error('Cannot find string table') + return false + } + // check if contains rotate function and decrypt variable + let decrypt_val + let decrypt_path + let binds = refs.string_path.scope.getBinding(var_string_table) + function parse_main_call(path) { + decrypt_path = path + const node = path.node + const copy = t.functionDeclaration(node.id, node.params, node.body) + node.body = t.blockStatement([]) + return copy + } + // remove path of string table + if (refs.string_path.isVariableDeclarator()) { + decrypt_code[1] = t.variableDeclaration('var', [refs.string_path.node]) + } else { + decrypt_code[1] = refs.string_path.node + } + refs.string_path.remove() + // iterate refs + let cache = undefined + for (let bind of binds.referencePaths) { + if (bind.findParent((path) => path.removed)) { + continue + } + const parent = bind.parentPath + if (parent.isCallExpression() && bind.listKey === 'arguments') { + // This is the rotate function. + // If it's in a sequence expression, it can be handled together. + // Or, we should handle it after this iteration. + cache = parent + continue + } + if (parent.isSequenceExpression()) { + // rotate function + decrypt_code.push(t.expressionStatement(parent.node)) + const up2 = parent.parentPath + if (up2.isIfStatement()) { + // In the new version, rotate function will be enclosed by an + // empty IfStatement + up2.remove() + } else { + parent.remove() + } + continue + } + if (parent.isVariableDeclarator()) { + // main decrypt val + let top = parent.getFunctionParent() + while (top.getFunctionParent()) { + top = top.getFunctionParent() + } + decrypt_code[2] = parse_main_call(top) + decrypt_val = top.node.id.name + continue + } + if (parent.isCallExpression() && !parent.node.arguments.length) { + // main decrypt val + if (!t.isVariableDeclarator(parent.parentPath.node)) { + continue + } + let top = parent.getFunctionParent() + while (top.getFunctionParent()) { + top = top.getFunctionParent() + } + decrypt_code[2] = parse_main_call(top) + decrypt_val = top.node.id.name + continue + } + if (parent.isExpressionStatement()) { + parent.remove() + continue + } + console.warn(`Unexpected ref var_string_table: ${parent}`) + } + // If rotateFunction is detected but not handled, we should handle it now. + if (decrypt_code.length === 3 && cache) { + if (cache.parentPath.isExpressionStatement()) { + decrypt_code.push(cache.parent) + cache = cache.parentPath + } else { + decrypt_code.push(t.expressionStatement(cache.node)) + } + cache.remove() + } + decrypt_path.parentPath.scope.crawl() + if (!decrypt_val) { + console.error('Cannot find decrypt variable') + return + } + console.log(`Main call wrapper name: ${decrypt_val}`) + + // 运行解密语句 + let content_code = ast.program.body + ast.program.body = decrypt_code + let { code } = generator(ast, { + compact: true, + }) + virtualGlobalEval(code) + // 遍历内容语句 + ast.program.body = content_code + function funToStr(path) { + let tmp = path.toString() + let value = virtualGlobalEval(tmp) + // console.log(`还原前:${tmp} 还原后:${value}`) + path.replaceWith(t.valueToNode(value)) + } + function memToStr(path) { + let tmp = path.toString() + let value = virtualGlobalEval(tmp) + // console.log(`还原前:${tmp} 还原后:${value}`) + path.replaceWith(t.valueToNode(value)) + } + function dfs(stk, item) { + stk.push(item) + const cur_val = item.name + console.log(`Enter sub ${stk.length}:${cur_val}`) + let pfx = '' + for (let parent of stk) { + pfx += parent.code + ';' + } + virtualGlobalEval(pfx) + let scope = item.path.scope + if (item.path.isFunctionDeclaration()) { + scope = item.path.parentPath.scope + } + const refs = scope.bindings[cur_val].referencePaths + const refs_next = [] + for (let ref of refs) { + const parent = ref.parentPath + if (ref.key === 'init') { + // VariableDeclarator + refs_next.push({ + name: parent.node.id.name, + path: parent, + code: 'var ' + parent, + }) + } else if (ref.key === 'object') { + // MemberExpression + memToStr(parent) + } else if (ref.key === 'callee') { + // CallExpression + funToStr(parent) + } + } + for (let ref of refs_next) { + dfs(stk, ref) + } + scope.crawl() + item.path.remove() + scope.crawl() + console.log(`Exit sub ${stk.length}:${cur_val}`) + stk.pop() + } + const root = { + name: decrypt_val, + path: decrypt_path, + code: '', + } + dfs([], root) + return ast +} + +function purifyBoolean(path) { + // 简化 ![] 和 !![] + const node0 = path.node + if (node0.operator !== '!') { + return + } + const node1 = node0.argument + if (t.isArrayExpression(node1) && node1.elements.length === 0) { + path.replaceWith(t.booleanLiteral(false)) + return + } + if (!t.isUnaryExpression(node1) || node1.operator !== '!') { + return + } + const node2 = node1.argument + if (t.isArrayExpression(node2) && node2.elements.length === 0) { + path.replaceWith(t.booleanLiteral(true)) + } +} + +function cleanIFCode(path) { + function clear(path, toggle) { + // 判定成立 + if (toggle) { + if (path.node.consequent.type == 'BlockStatement') { + path.replaceWithMultiple(path.node.consequent.body) + } else { + path.replaceWith(path.node.consequent) + } + return + } + // 判定不成立 + if (!path.node.alternate) { + path.remove() + return + } + if (path.node.alternate.type == 'BlockStatement') { + path.replaceWithMultiple(path.node.alternate.body) + } else { + path.replaceWith(path.node.alternate) + } + } + // 判断判定是否恒定 + const test = path.node.test + const types = ['StringLiteral', 'NumericLiteral', 'BooleanLiteral'] + if (test.type === 'BinaryExpression') { + if ( + types.indexOf(test.left.type) !== -1 && + types.indexOf(test.right.type) !== -1 + ) { + const left = JSON.stringify(test.left.value) + const right = JSON.stringify(test.right.value) + clear(path, eval(left + test.operator + right)) + } + } else if (types.indexOf(test.type) !== -1) { + clear(path, eval(JSON.stringify(test.value))) + } +} + +function cleanSwitchCode1(path) { + // 扁平控制: + // 会使用一个恒为true的while语句包裹一个switch语句 + // switch语句的执行顺序又while语句上方的字符串决定 + // 首先碰断是否符合这种情况 + const node = path.node + if (!(t.isBooleanLiteral(node.test) || t.isUnaryExpression(node.test))) { + return + } + if (!(node.test.prefix || node.test.value)) { + return + } + if (!t.isBlockStatement(node.body)) { + return + } + const body = node.body.body + if ( + !t.isSwitchStatement(body[0]) || + !t.isMemberExpression(body[0].discriminant) || + !t.isBreakStatement(body[1]) + ) { + return + } + // switch语句的两个变量 + const swithStm = body[0] + const arrName = swithStm.discriminant.object.name + const argName = swithStm.discriminant.property.argument.name + console.log(`扁平化还原: ${arrName}[${argName}]`) + // 在while上面的节点寻找这两个变量 + let arr = [] + path.getAllPrevSiblings().forEach((pre_path) => { + const { declarations } = pre_path.node + let { id, init } = declarations[0] + if (arrName == id.name) { + arr = init.callee.object.value.split('|') + pre_path.remove() + } + if (argName == id.name) { + pre_path.remove() + } + }) + // 重建代码块 + const caseList = swithStm.cases + let resultBody = [] + arr.map((targetIdx) => { + // 从当前序号开始直到遇到continue + let valid = true + targetIdx = parseInt(targetIdx) + while (valid && targetIdx < caseList.length) { + const targetBody = caseList[targetIdx].consequent + const test = caseList[targetIdx].test + if (!t.isStringLiteral(test) || parseInt(test.value) !== targetIdx) { + console.log(`switch中出现乱序的序号: ${test.value}:${targetIdx}`) + } + for (let i = 0; i < targetBody.length; ++i) { + const s = targetBody[i] + if (t.isContinueStatement(s)) { + valid = false + break + } + if (t.isReturnStatement(s)) { + valid = false + resultBody.push(s) + break + } + if (t.isBreakStatement(s)) { + console.log(`switch中出现意外的break: ${arrName}[${argName}]`) + } else { + resultBody.push(s) + } + } + targetIdx++ + } + }) + // 替换整个while语句 + path.replaceInline(resultBody) +} + +function cleanSwitchCode2(path) { + // 扁平控制: + // 会使用一个空的for语句包裹一个switch语句 + // switch语句的执行顺序由for语句上方的字符串决定 + // 首先判断是否符合这种情况 + const node = path.node + if (node.init || node.test || node.update) { + return + } + if (!t.isBlockStatement(node.body)) { + return + } + const body = node.body.body + if ( + !t.isSwitchStatement(body[0]) || + !t.isMemberExpression(body[0].discriminant) || + !t.isBreakStatement(body[1]) + ) { + return + } + // switch语句的两个变量 + const swithStm = body[0] + const arrName = swithStm.discriminant.object.name + const argName = swithStm.discriminant.property.argument.name + // 在while上面的节点寻找这两个变量 + let arr = null + for (let pre_path of path.getAllPrevSiblings()) { + if (!pre_path.isVariableDeclaration()) { + continue + } + let test = '' + pre_path + try { + arr = eval(test + `;${arrName}`) + } catch { + // + } + } + if (!arr) { + return + } + console.log(`扁平化还原: ${arrName}[${argName}]`) + // 重建代码块 + const caseMap = {} + for (let item of swithStm.cases) { + caseMap[item.test.value] = item.consequent + } + let resultBody = [] + arr.map((targetIdx) => { + // 从当前序号开始直到遇到continue + let valid = true + while (valid && targetIdx < arr.length) { + const targetBody = caseMap[targetIdx] + for (let i = 0; i < targetBody.length; ++i) { + const s = targetBody[i] + if (t.isContinueStatement(s)) { + valid = false + break + } + if (t.isReturnStatement(s)) { + valid = false + resultBody.push(s) + break + } + if (t.isBreakStatement(s)) { + console.log(`switch中出现意外的break: ${arrName}[${argName}]`) + } else { + resultBody.push(s) + } + } + targetIdx++ + } + }) + // 替换整个while语句 + path.replaceInline(resultBody) +} + +function cleanDeadCode(ast) { + traverse(ast, { UnaryExpression: purifyBoolean }) + traverse(ast, { IfStatement: cleanIFCode }) + traverse(ast, { ConditionalExpression: cleanIFCode }) + traverse(ast, { WhileStatement: { exit: cleanSwitchCode1 } }) + traverse(ast, { ForStatement: { exit: cleanSwitchCode2 } }) + return ast +} + +function removeUniqueCall(path) { + let up1 = path.parentPath + let decorator = up1.node.callee.name + console.info(`Remove decorator: ${decorator}`) + let bind1 = up1.scope.getBinding(decorator) + bind1.path.remove() + if (up1.key === 'callee') { + up1.parentPath.remove() + } else if (up1.key === 'init') { + let up2 = up1.parentPath + let call = up2.node.id.name + console.info(`Remove call: ${call}`) + let bind2 = up2.scope.getBinding(call) + up2.remove() + for (let ref of bind2.referencePaths) { + if (ref.findParent((path) => path.removed)) { + continue + } + if (ref.key === 'callee') { + let rm = ref.parentPath + if (rm.key === 'expression') { + rm = rm.parentPath + } + rm.remove() + } else { + console.warn(`Unexpected ref key: ${ref.key}`) + } + } + } +} + +function unlockDebugger(path) { + const decl_path = path.getFunctionParent()?.getFunctionParent() + if (!decl_path) { + return + } + // Check if contains inf-loop + let valid = false + path.getFunctionParent().traverse({ + WhileStatement(path) { + if (t.isBooleanLiteral(path.node.test) && path.node.test) { + valid = true + } + }, + }) + if (!valid) { + return + } + const name = decl_path.node.id.name + const bind = decl_path.scope.getBinding(name) + console.info(`Debug test and inf-loop: ${name}`) + for (let ref of bind.referencePaths) { + if (ref.findParent((path) => path.removed)) { + continue + } + if (ref.listKey === 'arguments') { + // setInterval + let rm = ref.getFunctionParent().parentPath + if (rm.key === 'expression') { + rm = rm.parentPath + } + rm.remove() + } else if (ref.key === 'callee') { + // lint test for this method + let rm = ref.getFunctionParent() + removeUniqueCall(rm) + } else { + console.warn(`Unexpected ref key: ${ref.key}`) + } + } + decl_path.remove() + path.stop() +} + +function unlockConsole(path) { + if (!t.isArrayExpression(path.node.init)) { + return + } + let pattern = 'log|warn|debug|info|error|exception|table|trace' + let count = 0 + for (let ele of path.node.init.elements) { + if (~pattern.indexOf(ele.value)) { + ++count + continue + } + return + } + if (count < 5) { + return + } + let left1 = path.getSibling(0) + const code = generator(left1.node, { minified: true }).code + pattern = ['window', 'process', 'require', 'global'] + pattern.map((key) => { + if (code.indexOf(key) == -1) { + return + } + }) + let rm = path.getFunctionParent() + removeUniqueCall(rm) +} + +function unlockLint(path) { + if (path.findParent((up) => up.removed)) { + return + } + if (path.node.value !== '(((.+)+)+)+$') { + return + } + let rm = path.getFunctionParent() + removeUniqueCall(rm) +} + +function unlockDomainLock(path) { + const array_list = [ + '[7,116,5,101,3,117,0,100]', + '[5,110,0,100]', + '[7,110,0,108]', + '[7,101,0,104]', + ] + const checkArray = (node) => { + const trim = node.split(' ').join('') + for (let i = 0; i < 4; ++i) { + if (array_list[i] == trim) { + return i + 1 + } + } + return 0 + } + if (path.findParent((up) => up.removed)) { + return + } + let mask = 1 << checkArray('' + path) + if (mask == 1) { + return + } + let rm = path.getFunctionParent() + rm.traverse({ + ArrayExpression: function (item) { + mask = mask | (1 << checkArray('' + item)) + }, + }) + if (mask & 0b11110) { + console.info('Find domain lock') + removeUniqueCall(rm) + } +} + +function unlockEnv(ast) { + // 删除`禁止控制台调试`函数 + traverse(ast, { DebuggerStatement: unlockDebugger }) + // 删除`禁止控制台输出`函数 + traverse(ast, { VariableDeclarator: unlockConsole }) + // 删除`禁止换行`函数 + traverse(ast, { StringLiteral: unlockLint }) + // 删除`安全域名`函数 + traverse(ast, { ArrayExpression: unlockDomainLock }) +} + +/** + * If a function acts as follows: + * A = function (p1, p2) { return p1 + p2 } + * + * Convert its call to a binary expression: + * A(a, b) => a + b + */ +function purifyFunction(path) { + const left = path.get('left') + const right = path.get('right') + if (!left.isIdentifier() || !right.isFunctionExpression()) { + return + } + const name = left.node.name + const params = right.node.params + if (params.length !== 2) { + return + } + const name1 = params[0].name + const name2 = params[1].name + if (right.node.body.body.length !== 1) { + return + } + let retStmt = right.node.body.body[0] + if (!t.isReturnStatement(retStmt)) { + return + } + if (!t.isBinaryExpression(retStmt.argument, { operator: '+' })) { + return + } + if ( + retStmt.argument.left?.name !== name1 || + retStmt.argument.right?.name !== name2 + ) { + return + } + const fnPath = path.getFunctionParent() || path.scope.path + fnPath.traverse({ + CallExpression: function (_path) { + const _node = _path.node.callee + if (!t.isIdentifier(_node, { name: name })) { + return + } + let args = _path.node.arguments + _path.replaceWith(t.binaryExpression('+', args[0], args[1])) + }, + }) + path.remove() + console.log(`拼接类函数: ${name}`) +} + +function purifyCode(ast) { + // 净化拼接字符串的函数 + traverse(ast, { AssignmentExpression: purifyFunction }) + // 净化变量定义中的常量数值 + function purifyDecl(path) { + if (t.isNumericLiteral(path.node.init)) { + return + } + const name = path.node.id.name + const { code } = generator( + { + type: 'Program', + body: [path.node.init], + }, + { + compact: true, + } + ) + const valid = /^[-+*/%!<>&|~^ 0-9;]+$/.test(code) + if (!valid) { + return + } + if (/^[-][0-9]*$/.test(code)) { + return + } + const value = eval(code) + const node = t.valueToNode(value) + path.replaceWith(t.variableDeclarator(path.node.id, node)) + console.log(`替换 ${name}: ${code} -> ${value}`) + } + traverse(ast, { VariableDeclarator: purifyDecl }) + // 合并字符串 + let end = false + function combineString(path) { + const op = path.node.operator + if (op !== '+') { + return + } + const left = path.node.left + const right = path.node.right + if (!t.isStringLiteral(left) || !t.isStringLiteral(right)) { + return + } + end = false + path.replaceWith(t.StringLiteral(eval(path + ''))) + console.log(`合并字符串: ${path.node.value}`) + } + while (!end) { + end = true + traverse(ast, { BinaryExpression: combineString }) + } + // 替换索引器 + function FormatMember(path) { + // _0x19882c['removeCookie']['toString']() + // | + // | + // | + // v + // _0x19882c.removeCookie.toString() + let curNode = path.node + if (!t.isStringLiteral(curNode.property)) { + return + } + if (curNode.computed === undefined || !curNode.computed === true) { + return + } + if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(curNode.property.value)) { + return + } + curNode.property = t.identifier(curNode.property.value) + curNode.computed = false + } + traverse(ast, { MemberExpression: FormatMember }) + // 分割表达式 + function removeComma(path) { + // a = 1, b = ddd(), c = null; + // | + // | + // | + // v + // a = 1; + // b = ddd(); + // c = null; + if (!t.isExpressionStatement(path.parent)) { + return + } + let replace_path = path.parentPath + if (replace_path.listKey !== 'body') { + return + } + for (const item of path.node.expressions) { + replace_path.insertBefore(t.expressionStatement(item)) + } + replace_path.remove() + } + traverse(ast, { SequenceExpression: { exit: removeComma } }) + // 删除空语句 + traverse(ast, { + EmptyStatement: (path) => { + path.remove() + }, + }) + // 删除未使用的变量 + const deleteUnusedVar = require('../visitor/delete-unused-var') + traverse(ast, deleteUnusedVar) +} + +module.exports = function (code) { + let ret = PluginEval.unpack(code) + let global_eval = false + if (ret) { + global_eval = true + code = ret + } + let ast + try { + ast = parse(code, { errorRecovery: true }) + } catch (e) { + console.error(`Cannot parse code: ${e.reasonCode}`) + return null + } + // IllegalReturn + const deleteIllegalReturn = require('../visitor/delete-illegal-return') + traverse(ast, deleteIllegalReturn) + // 清理二进制显示内容 + traverse(ast, { + StringLiteral: ({ node }) => { + delete node.extra + }, + }) + traverse(ast, { + NumericLiteral: ({ node }) => { + delete node.extra + }, + }) + console.log('处理全局加密...') + ast = decodeGlobal(ast) + if (!ast) { + return null + } + console.log('处理代码块加密...') + const parseControlFlowStorage = require('../visitor/parse-control-flow-storage') + traverse(ast, parseControlFlowStorage) + console.log('清理死代码...') + ast = cleanDeadCode(ast) + // 刷新代码 + ast = parse( + generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code + ) + console.log('提高代码可读性...') + purifyCode(ast) + ast = parse(generator(ast, { comments: false }).code) + console.log('解除环境限制...') + unlockEnv(ast) + console.log('净化完成') + code = generator(ast, { + comments: false, + jsescOption: { minimal: true }, + }).code + if (global_eval) { + code = PluginEval.pack(code) + } + return code +} diff --git a/src/visitor/calculate-binary.js b/src/visitor/calculate-binary.js new file mode 100644 index 000000000..3b87d183b --- /dev/null +++ b/src/visitor/calculate-binary.js @@ -0,0 +1,24 @@ +const generator = require('@babel/generator').default +const t = require('@babel/types') + +/** + * Calculate BinaryExpression if left and right are both literals. + * Otherwise, the expression can't be simplified. + * + * For example, `typeof window` can be calculated but it's not constant. + */ +module.exports = { + BinaryExpression(path) { + const { left, right } = path.node + if (!t.isLiteral(left) || !t.isLiteral(right)) { + return + } + const code = generator(path.node).code + try { + const ret = eval(code) + path.replaceWithSourceString(ret) + } catch { + // + } + }, +} diff --git a/src/visitor/calculate-rstring.js b/src/visitor/calculate-rstring.js new file mode 100644 index 000000000..79a243b6e --- /dev/null +++ b/src/visitor/calculate-rstring.js @@ -0,0 +1,36 @@ +const generator = require('@babel/generator').default +const t = require('@babel/types') + +/** + * "sh".split("").reverse().join("") -> "hs" + */ +module.exports = { + StringLiteral(path) { + if (path.key !== 'object') { + return + } + let root = path + let count = 6 + while (root.parentPath && count) { + if ( + root.parentPath.isMemberExpression() || + root.parentPath.isCallExpression() + ) { + root = root.parentPath + --count + } else { + break + } + } + if (count) { + return + } + const code = generator(root.node).code + try { + const ret = eval(code) + root.replaceWith(t.stringLiteral(ret)) + } catch { + // + } + }, +} diff --git a/src/visitor/delete-extra.js b/src/visitor/delete-extra.js new file mode 100644 index 000000000..0ad246b22 --- /dev/null +++ b/src/visitor/delete-extra.js @@ -0,0 +1,12 @@ +/** + * 0x10 -> 16, "\u0058" -> "X" + * not ASCII-safe (disable jsescOption:minimal to keep ASCII-safe) + */ +module.exports = { + StringLiteral: ({ node }) => { + delete node.extra + }, + NumericLiteral: ({ node }) => { + delete node.extra + }, +} diff --git a/src/visitor/delete-illegal-return.js b/src/visitor/delete-illegal-return.js new file mode 100644 index 000000000..86f080ab5 --- /dev/null +++ b/src/visitor/delete-illegal-return.js @@ -0,0 +1,10 @@ +/** + * delete ReturnStatement in Program scope + */ +module.exports = { + ReturnStatement(path) { + if (!path.getFunctionParent()) { + path.remove() + } + }, +} diff --git a/src/visitor/delete-unused-var.js b/src/visitor/delete-unused-var.js new file mode 100644 index 000000000..87ae201b1 --- /dev/null +++ b/src/visitor/delete-unused-var.js @@ -0,0 +1,35 @@ +const t = require('@babel/types') + +/** + * Delete unused variables with the following exceptions: + * + * - ForOfStatement + * - ForInStatement + * + */ +module.exports = { + VariableDeclarator: (path) => { + const { node, scope } = path + const name = node.id.name + const binding = scope.getBinding(name) + if (!binding || binding.referenced || !binding.constant) { + return + } + const up1 = path.parentPath + const up2 = up1?.parentPath + if (t.isForOfStatement(up2)) { + return + } + if (t.isForInStatement(up2)) { + return + } + console.log(`Unused variable: ${name}`) + if (up1.node.declarations.length === 1) { + up1.remove() + up1.scope.crawl() + } else { + path.remove() + scope.crawl() + } + }, +} diff --git a/src/visitor/merge-object.js b/src/visitor/merge-object.js new file mode 100644 index 000000000..7ef9fba10 --- /dev/null +++ b/src/visitor/merge-object.js @@ -0,0 +1,211 @@ +const t = require('@babel/types') + +function mergeObject(path) { + const { id, init } = path.node + if (!t.isObjectExpression(init)) { + // 判断是否是定义对象 + return + } + let name = id.name + let scope = path.scope + let binding = scope.getBinding(name) + const start = path.node.end + let end = -1 + let violation = null + if (!binding.constant) { + // Find the first constantViolation after this declaration + for (let item of binding.constantViolations) { + if (item.node.start <= start) { + continue + } + if (item.isVariableDeclarator()) { + end = item.node.start + violation = item + break + } + if (item.isAssignmentExpression()) { + end = item.node.start + violation = item + break + } + return + } + } + // 添加已有的key + let keys = {} + let properties = init.properties + for (let prop of properties) { + let key = null + if (t.isStringLiteral(prop.key)) { + key = prop.key.value + } + if (t.isIdentifier(prop.key)) { + key = prop.key.name + } + if (key) { + keys[key] = true + } + } + // 遍历作用域检测是否含有局部混淆特征并合并成员 + let merges = [] + const container = path.parentPath.parentPath + let cur = 0 + let valid = true + // Check references in sequence + while (cur < binding.references) { + const ref = binding.referencePaths[cur] + // Ignore the references before this declaration + if (ref.node.start <= start) { + ++cur + continue + } + // Ignore the references after the first constantViolation + if (end >= 0 && ref.node.end >= end) { + break + } + if (ref.key !== 'object' || !ref.parentPath.isMemberExpression()) { + break + } + const me = ref.parentPath + if (me.key !== 'left' || !me.parentPath.isAssignmentExpression()) { + break + } + const ae = me.parentPath + let bk = ae + let stop = false + while (bk.parentPath !== container) { + if ( + bk.parentPath.isSequenceExpression() || + bk.parentPath.isVariableDeclarator() || + bk.parentPath.isVariableDeclaration() || + bk.parentPath.isExpressionStatement() + ) { + bk = bk.parentPath + continue + } + stop = true + break + } + if (stop) { + break + } + const property = me.node.property + let key = null + if (t.isStringLiteral(property)) { + key = property.value + } + if (t.isIdentifier(property)) { + key = property.name + } + if (!key) { + valid = false + break + } + // 不允许出现重定义 + if (Object.prototype.hasOwnProperty.call(keys, key)) { + valid = false + break + } + // 添加到列表 + properties.push(t.ObjectProperty(t.valueToNode(key), ae.node.right)) + keys[key] = true + merges.push(ae) + ++cur + } + if (!merges.length || !valid) { + return + } + // Remove code + console.log(`尝试性合并: ${name}`) + for (let ref of merges) { + const left = ref.node.left + if (ref.parentPath.isSequenceExpression() && ref.container.length === 1) { + ref = ref.parentPath + } + if ( + ref.parentPath.isVariableDeclarator() || + ref.parentPath.isAssignmentExpression() + ) { + ref.replaceWith(left) + } else { + ref.remove() + } + } + // Check the remaining references + const ref1 = binding.referencePaths[cur++] + if (!ref1) { + scope.crawl() + return + } + const ref2 = binding.referencePaths[cur] + // Don't replace the declarator if there exists more than one reference + if (ref2 && ref2.node.end < end) { + scope.crawl() + return + } + // Check if the only reference is an assignment + let key = ref1.key + let up1 = ref1.parentPath + if (up1.isSequenceExpression() && ref1.container.length === 1) { + key = up1.key + up1 = up1.parentPath + } + if (!up1.isVariableDeclarator() || key !== 'init') { + scope.crawl() + return + } + // Move the definition to its reference + up1.node.init = path.node.init + // Delete the original definition + if (violation?.isAssignmentExpression()) { + path.node.init = undefined + } else { + path.remove() + } + scope.crawl() +} + +/** + * Collect the properties of one object and move it back to the declaration. + * + * One example made by ObjectExpressionKeysTransformer: + * + * ```javascript + * var _0xb28de8 = {}; + * _0xb28de8["abcd"] = function(_0x22293f, _0x5a165e) { + * return _0x22293f == _0x5a165e; + * }; + * _0xb28de8.dbca = function(_0xfbac1e, _0x23462f, _0x556555) { + * return _0xfbac1e(_0x23462f, _0x556555); + * }; + * _0xb28de8.aaa = function(_0x57e640) { + * return _0x57e640(); + * }; + * _0xb28de8["bbb"] = "eee"; + * var _0x15e145 = _0xb28de8; + * ``` + * + * The result: + * + * ```javascript + * var _0x15e145 = { + * "abcd": function (_0x22293f, _0x5a165e) { + * return _0x22293f == _0x5a165e; + * }, + * "dbca": function (_0xfbac1e, _0x23462f, _0x556555) { + * return _0xfbac1e(_0x23462f, _0x556555); + * }, + * "aaa": function (_0x57e640) { + * return _0x57e640(); + * }, + * "bbb": "eee" + * }; + * ``` + * + * Note: + * - Constant objects in the original code can be splitted + * - AssignmentExpression can be moved to ReturnStatement + */ +module.exports = { + VariableDeclarator: mergeObject, +} diff --git a/src/visitor/parse-control-flow-storage.js b/src/visitor/parse-control-flow-storage.js new file mode 100644 index 000000000..71eaf61d8 --- /dev/null +++ b/src/visitor/parse-control-flow-storage.js @@ -0,0 +1,196 @@ +const generator = require('@babel/generator').default +const t = require('@babel/types') + +function parseObject(path) { + let node = path.node + // 变量必须定义为Object类型才可能是代码块加密内容 + if (!t.isObjectExpression(node.init)) { + return + } + let objPropertiesList = node.init.properties + if (objPropertiesList.length == 0) { + return + } + // 遍历Object 判断每个元素是否符合格式 + let objName = node.id.name + let objKeys = {} + // 有时会有重复的定义 + let replCount = 0 + objPropertiesList.map(function (prop) { + if (!t.isObjectProperty(prop)) { + return + } + let key + if (t.isIdentifier(prop.key)) { + key = prop.key.name + } else { + key = prop.key.value + } + if (t.isFunctionExpression(prop.value)) { + // 符合要求的函数必须有且仅有一条return语句 + if (prop.value.body.body.length !== 1) { + return + } + let retStmt = prop.value.body.body[0] + if (!t.isReturnStatement(retStmt)) { + return + } + // 检测是否是3种格式之一 + let repfunc = null + if (t.isBinaryExpression(retStmt.argument)) { + // 二元运算类型 + repfunc = function (_path, args) { + _path.replaceWith( + t.binaryExpression(retStmt.argument.operator, args[0], args[1]) + ) + } + } else if (t.isLogicalExpression(retStmt.argument)) { + // 逻辑判断类型 + repfunc = function (_path, args) { + _path.replaceWith( + t.logicalExpression(retStmt.argument.operator, args[0], args[1]) + ) + } + } else if (t.isCallExpression(retStmt.argument)) { + // 函数调用类型 调用的函数必须是传入的第一个参数 + if (!t.isIdentifier(retStmt.argument.callee)) { + return + } + if (retStmt.argument.callee.name !== prop.value.params[0]?.name) { + return + } + repfunc = function (_path, args) { + _path.replaceWith(t.callExpression(args[0], args.slice(1))) + } + } + if (repfunc) { + objKeys[key] = repfunc + ++replCount + } + } else if (t.isStringLiteral(prop.value)) { + let retStmt = prop.value.value + objKeys[key] = function (_path) { + _path.replaceWith(t.stringLiteral(retStmt)) + } + ++replCount + } else if (t.isMemberExpression(prop.value)) { + let retStmt = prop.value + objKeys[key] = function (_path) { + _path.replaceWith(retStmt) + } + ++replCount + } + }) + // 如果Object内的元素不全符合要求 很有可能是普通的字符串类型 不需要替换 + if (!replCount) { + return + } + if (objPropertiesList.length !== replCount) { + console.log( + `不完整替换: ${objName} ${replCount}/${objPropertiesList.length}` + ) + return + } + // 遍历作用域进行替换 分为函数调用和字符串调用 + console.log(`处理代码块: ${objName}`) + let objUsed = {} + function getReplaceFunc(_node) { + // 这里开始所有的调用应该都在列表中 + let key = null + if (t.isStringLiteral(_node.property)) { + key = _node.property.value + } else if (t.isIdentifier(_node.property)) { + key = _node.property.name + } else { + // Maybe the code was obfuscated more than once + const code = generator(_node.property, { minified: true }).code + console.log(`意外的调用: ${objName}[${code}]`) + return null + } + if (!Object.prototype.hasOwnProperty.call(objKeys, key)) { + // 这里应该是在死代码中 因为key不存在 + return null + } + objUsed[key] = true + return objKeys[key] + } + let bind = path.scope.getBinding(objName)?.referencePaths + let usedCount = 0 + // Replace reversely to handle nested cases correctly + for (let i = bind.length - 1; i >= 0; --i) { + let ref = bind[i] + let up1 = ref.parentPath + if (up1.isMemberExpression() && ref.key === 'object') { + if (up1.key === 'left' && t.isAssignmentExpression(up1.parent)) { + continue + } + let func = getReplaceFunc(up1.node) + if (!func) { + continue + } + ++usedCount + let up2 = up1.parentPath + if (up1.key === 'callee') { + func(up2, up2.node.arguments) + } else { + func(up1) + } + } + } + // 如果没有全部使用 就先不删除 + if (usedCount !== bind.length) { + console.log(`不完整使用: ${objName} ${usedCount}/${bind.length}`) + } else { + path.remove() + } +} + +/** + * Parse control flow object + * + * Several kinds of expressions are collected, transformed, and merged into + * the controlFlowStorage object by method FunctionControlFlowTransformer: + * + * - BinaryExpression + * - CallExpression + * - LogicalExpression + * - Literal + * + * ```javascript + * var _0xb28de8 = { + * "abcd": function(_0x22293f, _0x5a165e) { + * return _0x22293f == _0x5a165e; + * }, + * "dbca": function(_0xfbac1e, _0x23462f, _0x556555) { + * return _0xfbac1e(_0x23462f, _0x556555); + * }, + * "aaa": function(_0x57e640) { + * return _0x57e640(); + * }, + * "bbb": "eee", + * "ccc": A[x][y][...] + * }; + * ``` + * + * This visitor can parse such objects and undo the transformation. + * + * ```javascript + * // From + * var aa = _0xb28de8["abcd"](123, 456); + * var bb = _0xb28de8["dbca"](bcd, 11, 22); + * var cc = _0xb28de8["aaa"](dcb); + * var dd = _0xb28de8["bbb"]; + * var ee = _0xb28de8["ccc"]; + * // To + * var aa = 123 == 456; + * var bb = bcd(11, 22); + * var cc = dcb(); + * var dd = "eee"; + * var ee = A[x][y][...]; + * ``` + */ +module.exports = { + VariableDeclarator: { + exit: parseObject, + }, +}