From 51671da5da9124fc7dbad652ee7ba2141a953c27 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 18 Mar 2020 23:59:25 +0100 Subject: [PATCH 01/12] chore: web-ext update --- package.json | 2 +- yarn.lock | 821 +++++++++++++++++++++++++++------------------------ 2 files changed, 428 insertions(+), 395 deletions(-) diff --git a/package.json b/package.json index b1dad5fa1..2a66fd4b1 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "terser": "4.4.2", "terser-webpack-plugin": "2.2.2", "transform-loader": "0.2.4", - "web-ext": "3.2.1", + "web-ext": "4.1.0", "webpack": "4.41.2", "webpack-bundle-analyzer": "3.6.0", "webpack-cli": "3.3.10", diff --git a/yarn.lock b/yarn.lock index e6517ad3c..c2453911e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -623,10 +623,10 @@ "@babel/helper-create-regexp-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/polyfill@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.6.0.tgz#6d89203f8b6cd323e8d946e47774ea35dc0619cc" - integrity sha512-q5BZJI0n/B10VaQQvln1IlDK3BTBJFbADx7tv+oXDPIDZuTo37H5Adb9jhlXm/fEN4Y7/64qD9mnrJJG7rmaTw== +"@babel/polyfill@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.7.0.tgz#e1066e251e17606ec7908b05617f9b7f8180d8f3" + integrity sha512-/TS23MVvo34dFmf8mwCisCbWGrfhbiWZSwBo6HkADTBhUa2Q/jWltyY/tpofz/b6/RIhqaqQcquptCirqIhOaQ== dependencies: core-js "^2.6.5" regenerator-runtime "^0.13.2" @@ -696,10 +696,10 @@ core-js "^2.6.5" regenerator-runtime "^0.13.2" -"@babel/runtime@7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd" - integrity sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg== +"@babel/runtime@7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.7.tgz#194769ca8d6d7790ec23605af9ee3e42a0aa79cf" + integrity sha512-uCnC2JEVAu8AKB5do1WRIsvrdJ0flYx/A/9f/6chdacnEZ7LmavjdsDXr5ksYBegxtuTPR5Va9/+13QF/kFkCA== dependencies: regenerator-runtime "^0.13.2" @@ -1520,6 +1520,11 @@ acorn-jsx@^5.0.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== +acorn-jsx@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== + acorn-node@^1.3.0: version "1.7.0" resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.7.0.tgz#aac6a559d27af6176b076ab6fb13c5974c213e3b" @@ -1560,6 +1565,11 @@ acorn@^7.0.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== +acorn@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" + integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== + adbkit-logcat@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/adbkit-logcat/-/adbkit-logcat-1.1.0.tgz#01d7f9b0cef9093a30bcb3b007efff301508962f" @@ -1585,48 +1595,47 @@ adbkit@2.11.1: node-forge "^0.7.1" split "~0.3.3" -addons-linter@1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/addons-linter/-/addons-linter-1.14.0.tgz#611f8d9e8c4cc84646ebd0b61c016f758225bf13" - integrity sha512-Of7A53J2ltaIZzD8RPH1hVxOR+DmLDuHBtwfhXJw8JTXwzpDIvOKn/i6XDtPgfFlj5wIWxpUGV+tFb/kE/K9gg== +addons-linter@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/addons-linter/-/addons-linter-1.20.0.tgz#e748d4c1f67ef82be39450864e9a13d6ad3e7b29" + integrity sha512-EIyJnIkvXhBKgOzVFR873uGa4ny07odIl8i8qWxHAuVJWM/ZQtLouAbndA+cVRDbD66sK6HsO1oWN6WkdCr/uA== dependencies: ajv "6.10.2" ajv-merge-patch "4.1.0" - chalk "2.4.2" + chalk "3.0.0" cheerio "1.0.0-rc.3" columnify "1.5.4" common-tags "1.8.0" - deepmerge "4.0.0" - dispensary "0.40.0" + deepmerge "4.2.2" + dispensary "0.49.0" es6-promisify "6.0.2" eslint "5.16.0" eslint-plugin-no-unsafe-innerhtml "1.0.16" eslint-visitor-keys "1.1.0" - espree "6.1.1" + espree "6.1.2" esprima "4.0.1" first-chunk-stream "3.0.0" fluent-syntax "0.13.0" - glob "7.1.4" + glob "7.1.6" is-mergeable-object "1.1.1" jed "1.1.1" - mdn-browser-compat-data "0.0.94" + mdn-browser-compat-data "1.0.3" os-locale "4.0.0" - pino "5.13.3" - po2json "0.4.5" - postcss "7.0.18" + pino "5.15.0" + postcss "7.0.26" probe-image-size "5.0.0" regenerator-runtime "0.13.3" relaxed-json "1.0.3" - semver "6.3.0" - source-map-support "0.5.13" + semver "7.1.1" + source-map-support "0.5.16" strip-bom-stream "4.0.0" tosource "1.0.0" upath "1.2.0" - whatwg-url "7.0.0" - yargs "14.0.0" + whatwg-url "8.0.0" + yargs "15.1.0" yauzl "2.10.0" optionalDependencies: - fsevents "2.0.7" + fsevents "2.1.2" adm-zip@~0.4.x: version "0.4.13" @@ -1687,16 +1696,6 @@ ajv@^4.7.0: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.1.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - ajv@^6.1.0, ajv@^6.5.5, ajv@^6.9.1: version "6.10.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593" @@ -1776,10 +1775,13 @@ ansi-styles@^4.0.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -ansi-styles@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" - integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg= +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" any-observable@^0.3.0: version "0.3.0" @@ -2074,11 +2076,6 @@ async-iterator-to-stream@^1.1.0: dependencies: readable-stream "^3.0.5" -async-limiter@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -2135,7 +2132,7 @@ aws-sign2@~0.7.0: resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= -aws4@^1.6.0, aws4@^1.8.0: +aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== @@ -2178,23 +2175,6 @@ babel-plugin-syntax-async-generators@6.13.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" integrity sha1-a8lj67FuzLrmuStZbrfzXDQqi5o= -babel-polyfill@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422" - integrity sha1-LUUCHfh+JqN0ttTRqcZZZNF/JCI= - dependencies: - babel-runtime "^6.9.1" - core-js "^2.4.0" - regenerator-runtime "^0.9.5" - -babel-runtime@^6.9.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -2490,6 +2470,20 @@ boxen@^3.0.0: type-fest "^0.3.0" widest-line "^2.0.0" +boxen@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" + integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^3.0.0" + cli-boxes "^2.2.0" + string-width "^4.1.0" + term-size "^2.1.0" + type-fest "^0.8.1" + widest-line "^3.1.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2996,6 +2990,14 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4. escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@3.0.0, chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -3007,15 +3009,6 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" - integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8= - dependencies: - ansi-styles "~1.0.0" - has-color "~0.1.0" - strip-ansi "~0.1.0" - chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3099,10 +3092,10 @@ chrome-dgram@3.0.4: inherits "^2.0.1" run-series "^1.1.2" -chrome-launcher@0.11.2: - version "0.11.2" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.11.2.tgz#c9a248dbccd3a08565553acf61adff879bcc982c" - integrity sha512-jx0kJDCXdB2ARcDMwNCtrf04oY1Up4rOmVu+fqJ5MTPOOIG8EhRcEU9NZfXZc6dMw9FU8o1r21PNp8V2M0zQ+g== +chrome-launcher@0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.12.0.tgz#08db81ef0f7b283c331df2c350e780c38bd0ce3a" + integrity sha512-rBUP4tvWToiileDi3UR0SbWKoUoDCYTRmVND2sdoBL1xANBgVz8V9h1yQluj3MEQaBJg0fRw7hW82uOPrJus7A== dependencies: "@types/node" "*" is-wsl "^2.1.0" @@ -3342,7 +3335,7 @@ columnify@1.5.4: strip-ansi "^3.0.0" wcwidth "^1.0.0" -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.5, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -3450,6 +3443,18 @@ configstore@^4.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" +configstore@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -3543,7 +3548,12 @@ core-js-compat@^3.4.7: browserslist "^4.8.0" semver "^6.3.0" -core-js@^2.4.0, core-js@^2.6.5: +core-js@3.6.4: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647" + integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw== + +core-js@^2.6.5: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== @@ -3693,6 +3703,11 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -3971,12 +3986,19 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -deepcopy@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/deepcopy/-/deepcopy-0.6.3.tgz#634780f2f8656ab771af8fa8431ed1ccee55c7b0" - integrity sha1-Y0eA8vhlardxr4+oQx7RzO5Vx7A= +deepcopy@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/deepcopy/-/deepcopy-2.0.0.tgz#2acb9b7645f9f54d815eee991455e790e72e2252" + integrity sha512-d5ZK7pJw7F3k6M5vqDjGiiUS9xliIyWkdzBjnPhnSeRGjkYOGZMCFkdKVwV/WiHOe0NwzB8q+iDo7afvSf0arA== + dependencies: + type-detect "^4.0.8" + +deepmerge@4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -deepmerge@4.0.0, deepmerge@^4.0.0: +deepmerge@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.0.0.tgz#3e3110ca29205f120d7cb064960a39c3d2087c09" integrity sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww== @@ -4141,18 +4163,18 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -dispensary@0.40.0: - version "0.40.0" - resolved "https://registry.yarnpkg.com/dispensary/-/dispensary-0.40.0.tgz#dedc4a4e4aebae7afcb6ae91f03e292ba107fe67" - integrity sha512-ttKDQvGBf+ygQ4rXuLBLErp3kMJIS+Gfmy+nJ6N/EfV8/RQdjd9SORpc729YK5SYAI+IuBo88S2xGUjKjU2jYw== +dispensary@0.49.0: + version "0.49.0" + resolved "https://registry.yarnpkg.com/dispensary/-/dispensary-0.49.0.tgz#0ea2c62f1d7353b6e9a27f5dac08b0bad586b74f" + integrity sha512-szH0vDORmGWEfwQgIqrhmrMpSGU2yXL3z7oe0NGx4sCbmnJdXXr5SQvRccPNCPrRuRPn2zPIITvwD9Lf+pcOew== dependencies: async "~3.1.0" natural-compare-lite "~1.4.0" - pino "~5.13.0" + pino "~5.15.0" request "~2.88.0" sha.js "~2.4.4" source-map-support "~0.5.4" - yargs "~14.0.0" + yargs "~15.1.0" dlv@^1.1.3: version "1.1.3" @@ -4252,6 +4274,13 @@ dot-prop@^4.1.0: dependencies: is-obj "^1.0.0" +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + download-cli@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/download-cli/-/download-cli-1.1.1.tgz#0aada6dc1abf9fd2f3d20281dfbdadea9f64ec3e" @@ -4412,13 +4441,6 @@ encoding-down@~5.0.0: level-errors "^2.0.0" xtend "^4.0.1" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= - dependencies: - iconv-lite "~0.4.13" - end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" @@ -4564,11 +4586,6 @@ es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14: es6-symbol "~3.1.1" next-tick "^1.0.0" -es6-error@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.0.tgz#f094c7041f662599bb12720da059d6b9c7ff0f40" - integrity sha1-8JTHBB9mJZm7EnINoFnWucf/D0A= - es6-error@4.1.1, es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" @@ -4605,18 +4622,6 @@ es6-promise@^2.0.1: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-2.3.0.tgz#96edb9f2fdb01995822b263dd8aadab6748181bc" integrity sha1-lu258v2wGZWCKyY92KratnSBgbw= -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - es6-promisify@6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.2.tgz#525c23725b8510f5f1f2feb5a1fbad93a93e29b4" @@ -4930,13 +4935,13 @@ eslint@~6.4.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@6.1.1, espree@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" - integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== +espree@6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d" + integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA== dependencies: - acorn "^7.0.0" - acorn-jsx "^5.0.2" + acorn "^7.1.0" + acorn-jsx "^5.1.0" eslint-visitor-keys "^1.1.0" espree@^3.4.0: @@ -4956,6 +4961,15 @@ espree@^5.0.1: acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== + dependencies: + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" + esprima@4.0.1, esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -5222,7 +5236,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3.0.2, extend@^3.0.0, extend@~3.0.1, extend@~3.0.2: +extend@3.0.2, extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -5267,11 +5281,6 @@ fakefile@0.0.9: dependencies: fs-extra "0.26.5" -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= - fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -5527,10 +5536,10 @@ firefox-addons-add-update-version@1.0.1: unzip-stream "^0.3.0" yargs "^10.0.3" -firefox-profile@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/firefox-profile/-/firefox-profile-1.2.0.tgz#2068227924e714a2b10ec5fba8392e19b5788509" - integrity sha512-TTEFfPOkyaz4EWx/5ZDQC1mJAe3a+JgVcchpIfD4Tvx1UspwlTJRJxOYA35x/z2iJcxaF6aW2rdh6oj6qwgd2g== +firefox-profile@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/firefox-profile/-/firefox-profile-1.3.0.tgz#36c74c30d67e898a2ef0fb7983f975e44f1312b2" + integrity sha512-3d7JPnFC3GrwGW8wonAqy2E4YCI7A8MO7yVDkqS09uQ3tLvMLCY3Ytt4ntvVXvyzjVMRmrLW9W/CubnnzrdLCA== dependencies: adm-zip "~0.4.x" archiver "~2.1.0" @@ -5672,7 +5681,7 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.1, form-data@~2.3.2: +form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== @@ -5797,10 +5806,10 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" - integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== +fsevents@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== fsevents@^1.2.7: version "1.2.9" @@ -6005,20 +6014,13 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gettext-parser@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/gettext-parser/-/gettext-parser-1.1.0.tgz#2c5a6638d893934b9b55037d0ad82cb7004b2679" - integrity sha1-LFpmONiTk0ubVQN9CtgstwBLJnk= - dependencies: - encoding "^0.1.11" - -git-rev-sync@1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/git-rev-sync/-/git-rev-sync-1.12.0.tgz#4468406c7e6c3ba4cf4587999e1adb28d9d1af55" - integrity sha1-RGhAbH5sO6TPRYeZnhrbKNnRr1U= +git-rev-sync@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/git-rev-sync/-/git-rev-sync-2.0.0.tgz#82fb77d9281efe7e7947569380dda4d1c19f4cb3" + integrity sha512-vnHFv2eocTmt/wHqZm3ksxtVshK4vptT0cEoumk6hAYRFx3do6Qo7xHBTBCv29+r3ZZCQOQ1i328MUCsYF7AUw== dependencies: escape-string-regexp "1.0.5" - graceful-fs "4.1.11" + graceful-fs "4.1.15" shelljs "0.7.7" glob-parent@^3.1.0: @@ -6048,10 +6050,10 @@ glob@7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.4, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6071,6 +6073,18 @@ glob@^6.0.1: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global-dirs@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -6078,6 +6092,13 @@ global-dirs@^0.1.0: dependencies: ini "^1.3.4" +global-dirs@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201" + integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A== + dependencies: + ini "^1.3.5" + global-modules@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -6178,10 +6199,10 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@4.1.11: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= +graceful-fs@4.1.15: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== graceful-fs@^4.1.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.2.0" @@ -6249,14 +6270,6 @@ har-schema@^2.0.0: resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0= - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - har-validator@~5.1.0: version "5.1.3" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" @@ -6279,11 +6292,6 @@ has-binary2@~1.0.2: dependencies: isarray "2.0.1" -has-color@~0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8= - has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" @@ -6294,6 +6302,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" @@ -6558,7 +6571,7 @@ hyperx@^2.5.0: dependencies: hyperscript-attribute-to-property "^1.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -6607,10 +6620,10 @@ immediate@^3.2.3, immediate@~3.2.3: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= -import-fresh@3.1.0, import-fresh@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" - integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== +import-fresh@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -6623,6 +6636,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -7763,6 +7784,14 @@ is-installed-globally@^0.1.0: global-dirs "^0.1.0" is-path-inside "^1.0.0" +is-installed-globally@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.1.tgz#679afef819347a72584617fd19497f010b8ed35f" + integrity sha512-oiEcGoQbGc+3/iijAijrK2qFpkNoNjsHOm/5V5iaeydyrS/hnwaRCEgH5cpW0P3T1lSjV5piB7S5b5lEugNLhg== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -7835,6 +7864,11 @@ is-npm@^3.0.0: resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-3.0.0.tgz#ec9147bfb629c43f494cf67936a961edec7e8053" integrity sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA== +is-npm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" + integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -7847,6 +7881,11 @@ is-obj@^1.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" @@ -7866,6 +7905,11 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + is-plain-obj@^1.0.0, is-plain-obj@^1.1, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -8279,11 +8323,6 @@ json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -8369,12 +8408,12 @@ jsonpointer@^4.0.0: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= -jsonwebtoken@8.2.1: - version "8.2.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.2.1.tgz#333ee39aa8f238f32fa41693e7a2fb7e42f82b31" - integrity sha512-l8rUBr0fqYYwPc8/ZGrue7GiW7vWdZtZqelxo4Sd5lMvuEeCK8/wS54sEo6tJhdZ6hqfutsj6COgC0d1XdbHGw== +jsonwebtoken@8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== dependencies: - jws "^3.1.4" + jws "^3.2.2" lodash.includes "^4.3.0" lodash.isboolean "^3.0.3" lodash.isinteger "^4.0.4" @@ -8383,7 +8422,7 @@ jsonwebtoken@8.2.1: lodash.isstring "^4.0.1" lodash.once "^4.0.0" ms "^2.1.1" - xtend "^4.0.1" + semver "^5.6.0" jsprim@^1.2.2: version "1.4.1" @@ -8449,7 +8488,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@^3.1.4: +jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -9646,10 +9685,10 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -mdn-browser-compat-data@0.0.94: - version "0.0.94" - resolved "https://registry.yarnpkg.com/mdn-browser-compat-data/-/mdn-browser-compat-data-0.0.94.tgz#eaa1653761ce95881ea1858a8c0ce6066d85f94b" - integrity sha512-O3zJqbmehz0Hn3wpk62taA0+jNF7yn6BDWqQ9Wh2bEoO9Rx1BYiTmNX565eNVbW0ixfQkY6Sp9FvY/rr79Qmyg== +mdn-browser-compat-data@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mdn-browser-compat-data/-/mdn-browser-compat-data-1.0.3.tgz#62f248a6fc457c01b6243425af0b45fdf11054bf" + integrity sha512-5n7c20IVrUiuOPSuhbkd5xoJPSzEEGsoMrmrdEtPHIw6gRPzonydcsguAmqGfSBd4d2DRoDQg533sijLUpeJLg== dependencies: extend "3.0.2" @@ -9875,7 +9914,7 @@ mime-types@2.1.25: dependencies: mime-db "1.42.0" -mime-types@^2.1.12, mime-types@^2.1.21, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@^2.1.21, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.24" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== @@ -10364,15 +10403,6 @@ mv@~2: ncp "~2.0.0" rimraf "~2.4.0" -mz@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.5.0.tgz#2859025df03d46b57bb317174b196477ce64cec1" - integrity sha1-KFkCXfA9RrV7sxcXSxlkd85kzsE= - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - mz@2.7.0, mz@^2.6.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -10740,14 +10770,6 @@ nodeify@^1.0.1: is-promise "~1.0.0" promise "~1.3.0" -nomnom@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" - integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc= - dependencies: - chalk "~0.4.0" - underscore "~1.6.0" - nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -10884,11 +10906,6 @@ nyc@14.1.1: yargs "^13.2.2" yargs-parser "^13.0.0" -oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -11048,12 +11065,12 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" - integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== +open@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/open/-/open-7.0.0.tgz#7e52999b14eb73f90f0f0807fe93897c4ae73ec9" + integrity sha512-K6EKzYqnwQzk+/dzJAQSBORub3xlBTxMz+ntpZpH/LyCa1o6KjXhuN+2npAaI9jaSmU3R1Q8NWf4KUWcyytGsQ== dependencies: - is-wsl "^1.1.0" + is-wsl "^2.1.0" opencollective-postinstall@^2.0.0, opencollective-postinstall@^2.0.2: version "2.0.2" @@ -11727,21 +11744,21 @@ pino-pretty@^3.2.1: readable-stream "^3.3.0" split2 "^3.1.1" -pino-std-serializers@^2.3.0: +pino-std-serializers@^2.3.0, pino-std-serializers@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-2.4.2.tgz#cb5e3e58c358b26f88969d7e619ae54bdfcc1ae1" integrity sha512-WaL504dO8eGs+vrK+j4BuQQq6GLKeCCcHaMB2ItygzVURcL1CycwNEUHTD/lHFHs/NL5qAz2UKrjYWXKSf4aMQ== -pino@5.13.3: - version "5.13.3" - resolved "https://registry.yarnpkg.com/pino/-/pino-5.13.3.tgz#26cd6f69b4bd03d6408af28eddcd9313687f143d" - integrity sha512-FL12DKlPwBlbhztlUz6kseR03PRR8nD+wvLdN/Sji9UiBYYfSjX+k8ocU7/NwW55JdFRONTn3iACoelXnMFVVQ== +pino@5.15.0, pino@~5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-5.15.0.tgz#6703164ce74dd4786d44887cd33268e13fd463d8" + integrity sha512-7+FXMTA3H3sNP5+2miY2K9JKnAAW5GKuhHfNWsukFCsPprGQY3ctqpwbV74wAHW3Nl93cEEQ1G82MgOLM8P7TQ== dependencies: - fast-redact "^1.4.4" + fast-redact "^2.0.0" fast-safe-stringify "^2.0.7" - flatstr "^1.0.9" - pino-std-serializers "^2.3.0" - quick-format-unescaped "^3.0.2" + flatstr "^1.0.12" + pino-std-serializers "^2.4.2" + quick-format-unescaped "^3.0.3" sonic-boom "^0.7.5" pino@^5.13.2: @@ -11756,18 +11773,6 @@ pino@^5.13.2: quick-format-unescaped "^3.0.2" sonic-boom "^0.7.5" -pino@~5.13.0: - version "5.13.4" - resolved "https://registry.yarnpkg.com/pino/-/pino-5.13.4.tgz#52935caaab8d47048deffa315336e8da30d8b96d" - integrity sha512-heeg8m8FZY8Nl3nuuD+msJUmhamqoGl7JXoTExh9YpGajzz6LYbVByUqrjbf4sCEMYFsqdcqnTJWiSY660DraQ== - dependencies: - fast-redact "^2.0.0" - fast-safe-stringify "^2.0.7" - flatstr "^1.0.9" - pino-std-serializers "^2.3.0" - quick-format-unescaped "^3.0.2" - sonic-boom "^0.7.5" - pkg-conf@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-3.1.0.tgz#d9f9c75ea1bae0e77938cde045b276dac7cc69ae" @@ -11818,23 +11823,15 @@ pluralize@^1.2.1: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" integrity sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU= -po2json@0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/po2json/-/po2json-0.4.5.tgz#47bb2952da32d58a1be2f256a598eebc0b745118" - integrity sha1-R7spUtoy1Yob4vJWpZjuvAt0URg= - dependencies: - gettext-parser "1.1.0" - nomnom "1.8.1" - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -postcss@7.0.18: - version "7.0.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.18.tgz#4b9cda95ae6c069c67a4d933029eddd4838ac233" - integrity sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g== +postcss@7.0.26: + version "7.0.26" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" + integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -12277,7 +12274,7 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -12299,7 +12296,7 @@ qs@^6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.0.tgz#d1297e2a049c53119cb49cca366adbbacc80b409" integrity sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA== -qs@~6.5.1, qs@~6.5.2: +qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== @@ -12319,6 +12316,11 @@ quick-format-unescaped@^3.0.2: resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-3.0.2.tgz#0137e94d8fb37ffeb70040535111c378e75396fb" integrity sha512-FXTaCkwvpIlkdKeGDNgcq07SXWS383noQUuZjvdE1QcTt+eLuqof6/BDiEPqB59FWLie/l91+HtlJSw7iCViSA== +quick-format-unescaped@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-3.0.3.tgz#fb3e468ac64c01d22305806c39f121ddac0d1fb9" + integrity sha512-dy1yjycmn9blucmJLXOfZDx1ikZJUi6E8bBZLnhPG5gBrVhHXx2xVyqqgKBubVNEXmx51dBACMHpoMQK/N/AXQ== + quick-lru@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" @@ -12565,21 +12567,11 @@ regenerator-runtime@0.13.3: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - regenerator-runtime@^0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== -regenerator-runtime@^0.9.5: - version "0.9.6" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" - integrity sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck= - regenerator-transform@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf" @@ -12698,33 +12690,7 @@ request-progress@3.0.0: dependencies: throttleit "^1.0.0" -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@^2.83.0, request@~2.88.0: +request@2.88.0, request@^2.83.0, request@~2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -13068,21 +13034,33 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: version "5.7.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -semver@6.3.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.1.tgz#29104598a197d6cbe4733eeecbe968f7b43a9667" + integrity sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A== semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + semver@~5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -13251,21 +13229,21 @@ shx@0.3.2: minimist "^1.2.0" shelljs "^0.8.1" -sign-addon@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/sign-addon/-/sign-addon-0.3.1.tgz#7798ba994c8cd803a64a11a12a377ae6f714565e" - integrity sha512-feaoG7+8IXr9SymOEd8VTZCSlVZArWcBDZ33IIdfXlU5NWWzXdCxCjPDqAkLQplFa7RRZr1S4lSmgMPn80Ze1A== - dependencies: - babel-polyfill "6.16.0" - deepcopy "0.6.3" - es6-error "4.0.0" - es6-promisify "5.0.0" - jsonwebtoken "8.2.1" - mz "2.5.0" - request "2.87.0" - source-map-support "0.4.6" +sign-addon@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/sign-addon/-/sign-addon-2.0.5.tgz#bfb1033bd77436c2f7c49168c6ea794f65c01b44" + integrity sha512-dVjIWe1VJ2VQCdScREWXWECmJhgjpJMqwPKkW+L78PPx2Jyr/t+//kNHqG1hYrmIsvQN7vGjAjv9s7ix0vw0zA== + dependencies: + common-tags "1.8.0" + core-js "3.6.4" + deepcopy "2.0.0" + es6-error "4.1.1" + es6-promisify "6.0.2" + jsonwebtoken "8.5.1" + mz "2.7.0" + request "2.88.0" + source-map-support "0.5.16" stream-to-promise "2.2.0" - when "3.7.7" signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" @@ -13519,17 +13497,10 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb" - integrity sha1-MlUqpktFg5KoXqs7C17mFScWeus= - dependencies: - source-map "^0.5.3" - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== +source-map-support@0.5.16: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -13547,7 +13518,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: +source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -13810,6 +13781,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.0.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + string-width@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" @@ -13819,15 +13799,6 @@ string-width@^4.1.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^5.2.0" -string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - string.prototype.padend@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" @@ -13916,11 +13887,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" - integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE= - strip-bom-buf@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-2.0.0.tgz#ff9c223937f8e7154b77e9de9bde094186885c15" @@ -14076,6 +14042,13 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -14218,6 +14191,11 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" +term-size@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" + integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== + terser-webpack-plugin@2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.2.2.tgz#2a6e00237125564a455ad69b22e08ee59420473a" @@ -14443,13 +14421,6 @@ tosource@1.0.0: resolved "https://registry.yarnpkg.com/tosource/-/tosource-1.0.0.tgz#42d88dd116618bcf00d6106dd5446f3427902ff1" integrity sha1-QtiN0RZhi88A1hBt1URvNCeQL/E= -tough-cookie@~2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA== - dependencies: - punycode "^1.4.1" - tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -14458,12 +14429,12 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= +tr46@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" + integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== dependencies: - punycode "^2.1.0" + punycode "^2.1.1" transform-ast@^2.4.0: version "2.4.4" @@ -14568,7 +14539,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -14588,6 +14559,11 @@ type-fest@^0.6.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -14601,7 +14577,7 @@ type@^1.0.1: resolved "https://registry.yarnpkg.com/type/-/type-1.0.1.tgz#084c9a17fcc9151a2cdb1459905c2e45e4bb7d61" integrity sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw== -typedarray-to-buffer@^3.1.2, typedarray-to-buffer@~3.1.5: +typedarray-to-buffer@^3.1.2, typedarray-to-buffer@^3.1.5, typedarray-to-buffer@~3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== @@ -14644,11 +14620,6 @@ unbzip2-stream@^1.0.9: buffer "^5.2.1" through "^2.3.8" -underscore@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" - integrity sha1-izixDKze9jM3uLJOT/htRa6lKag= - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -14713,6 +14684,13 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -14749,7 +14727,25 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== -update-notifier@3.0.1, update-notifier@^3.0.1: +update-notifier@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.0.0.tgz#f344a6f8b03e00e31b323d632a0e632e9f0e0654" + integrity sha512-p9zf71hWt5GVXM4iEBujpUgx8mK9AWiCCapEJm/O1z5ntCim83Z1ATqzZFBHFYqx03laMqv8LiDgs/7ikXjf/g== + dependencies: + boxen "^4.2.0" + chalk "^3.0.0" + configstore "^5.0.0" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.3.1" + is-npm "^4.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +update-notifier@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-3.0.1.tgz#78ecb68b915e2fd1be9f767f6e298ce87b736250" integrity sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ== @@ -14886,7 +14882,7 @@ uuid-parse@^1.0.0: resolved "https://registry.yarnpkg.com/uuid-parse/-/uuid-parse-1.1.0.tgz#7061c5a1384ae0e1f943c538094597e1b5f3a65b" integrity sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A== -uuid@^3.0.0, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.2.2, uuid@^3.3.2: +uuid@^3.0.0, uuid@^3.2.1, uuid@^3.2.2, uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== @@ -14968,44 +14964,44 @@ wcwidth@^1.0.0, wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-ext@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-ext/-/web-ext-3.2.1.tgz#5fa9f683d4ca804b42324593b1acedca375ab68d" - integrity sha512-WzZbCDIjIUshZRVaiYFbaMp/1/xPjW7qeTQ0F7Xx1MYkamZ4RN5dnhxWFz+Hzg6GzhFdny+zucNDKOwYfAV3LA== +web-ext@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/web-ext/-/web-ext-4.1.0.tgz#7175a539971014d9334017b98d6d7a59aea23ace" + integrity sha512-nhAeZ3BHI4rCT/J+s7JHg0U3G6qUMV8Bi44ohWm8X6GjlQV8tGcD6rkvN4Zk2zzMGaF9sHUOcRjyN79Ih8P/PQ== dependencies: - "@babel/polyfill" "7.6.0" - "@babel/runtime" "7.6.2" + "@babel/polyfill" "7.7.0" + "@babel/runtime" "7.7.7" "@cliqz-oss/firefox-client" "0.3.1" "@cliqz-oss/node-firefox-connect" "1.2.1" adbkit "2.11.1" - addons-linter "1.14.0" + addons-linter "1.20.0" bunyan "1.8.12" camelcase "5.3.1" - chrome-launcher "0.11.2" + chrome-launcher "0.12.0" debounce "1.2.0" decamelize "3.2.0" es6-error "4.1.1" event-to-promise "0.8.0" - firefox-profile "1.2.0" + firefox-profile "1.3.0" fx-runner "1.0.11" - git-rev-sync "1.12.0" - import-fresh "3.1.0" + git-rev-sync "2.0.0" + import-fresh "3.2.1" mkdirp "0.5.1" multimatch "4.0.0" mz "2.7.0" node-notifier "6.0.0" - open "6.4.0" + open "7.0.0" parse-json "5.0.0" - sign-addon "0.3.1" - source-map-support "0.5.13" + sign-addon "2.0.5" + source-map-support "0.5.16" stream-to-promise "2.2.0" strip-bom "4.0.0" strip-json-comments "3.0.1" tmp "0.1.0" - update-notifier "3.0.1" + update-notifier "4.0.0" watchpack "1.6.0" - ws "7.1.2" - yargs "13.3.0" + ws "7.2.1" + yargs "15.1.0" zip-dir "1.0.2" "webcrypto-shim@github:dignifiedquire/webcrypto-shim#master": @@ -15025,10 +15021,10 @@ webextension-polyfill@0.5.0: resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.5.0.tgz#795e0bf6a2b8eadcdb6edaecd169e9228c747519" integrity sha512-aFrl38x43t1bTboX/paCT8I97+idzX/TY0+fuM52hrIkCpYfROEF9kSn0BXuEIi3J9LTYt2ZZKkhx9NB1qF3nA== -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== webpack-bundle-analyzer@3.6.0: version "3.6.0" @@ -15121,14 +15117,14 @@ webrtc-ips@0.1.4: version "2.2.0" resolved "https://codeload.github.com/ipfs/webrtcsupport/tar.gz/0669f576582c53a3a42aa5ac014fcc5966809615" -whatwg-url@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" - integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== +whatwg-url@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.0.0.tgz#37f256cb746398e19b107bd6ef820b4ae2d15871" + integrity sha512-41ou2Dugpij8/LPO5Pq64K5q++MnRCBpEHvQr26/mArEKTkCV5aoXIqyhuYtE0pkqScXwhf2JP57rkRTYM29lQ== dependencies: lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" + tr46 "^2.0.0" + webidl-conversions "^5.0.0" when@3.7.7: version "3.7.7" @@ -15169,6 +15165,13 @@ widest-line@^2.0.0: dependencies: string-width "^2.1.1" +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + wif@^2.0.1, wif@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/wif/-/wif-2.0.6.tgz#08d3f52056c66679299726fade0d432ae74b4704" @@ -15246,6 +15249,16 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + write@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" @@ -15260,12 +15273,10 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.1.2.tgz#c672d1629de8bb27a9699eb599be47aeeedd8f73" - integrity sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg== - dependencies: - async-limiter "^1.0.0" +ws@7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" + integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A== ws@^1.1.0: version "1.1.5" @@ -15294,6 +15305,11 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + xml2js@~0.4.4: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" @@ -15451,22 +15467,22 @@ yargs@13.3.0, yargs@^13.2.1, yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.1" -yargs@14.0.0, yargs@^14.0.0, yargs@~14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.0.0.tgz#ba4cacc802b3c0b3e36a9e791723763d57a85066" - integrity sha512-ssa5JuRjMeZEUjg7bEL99AwpitxU/zWGAGpdj0di41pOEmJti8NR6kyUIJBkR78DTYNPZOU08luUo0GTHuB+ow== +yargs@15.1.0, yargs@~15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219" + integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg== dependencies: - cliui "^5.0.0" + cliui "^6.0.0" decamelize "^1.2.0" - find-up "^3.0.0" + find-up "^4.1.0" get-caller-file "^2.0.1" require-directory "^2.1.1" require-main-filename "^2.0.0" set-blocking "^2.0.0" - string-width "^3.0.0" + string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^13.1.1" + yargs-parser "^16.1.0" yargs@^10.0.3: version "10.1.2" @@ -15486,6 +15502,23 @@ yargs@^10.0.3: y18n "^3.2.1" yargs-parser "^8.1.0" +yargs@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.0.0.tgz#ba4cacc802b3c0b3e36a9e791723763d57a85066" + integrity sha512-ssa5JuRjMeZEUjg7bEL99AwpitxU/zWGAGpdj0di41pOEmJti8NR6kyUIJBkR78DTYNPZOU08luUo0GTHuB+ow== + dependencies: + cliui "^5.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.1" + yargs@^14.2.0: version "14.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.0.tgz#f116a9242c4ed8668790b40759b4906c276e76c3" From 4bf9d091498077132f9378e92f281cfb4e3e1a8a Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 19 Mar 2020 00:02:00 +0100 Subject: [PATCH 02/12] chore: yarn@1.22.4 --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2a66fd4b1..2de9d4f60 100644 --- a/package.json +++ b/package.json @@ -63,13 +63,13 @@ "get-firefox-nightly": "shx test -e ./firefox/firefox || get-firefox -b nightly -e", "changelog": "npx conventional-changelog-cli -p angular -i CHANGELOG.md -s", "ci": "run-s ci:*", - "ci:install": "npx yarn@1.19.2 install --frozen-lockfile || npx yarn@1.19.2 install --frozen-lockfile", - "ci:build": "./ci/update-manifest.sh && npx yarn@1.19.2 build", - "ci:test": "npx yarn@1.19.2 test", - "ci:lint": "npx yarn@1.19.2 lint", + "ci:install": "npx yarn@1.22.4 install --frozen-lockfile || npx yarn@1.22.4 install --frozen-lockfile", + "ci:build": "./ci/update-manifest.sh && npx yarn@1.22.4 build", + "ci:test": "npx yarn@1.22.4 test", + "ci:lint": "npx yarn@1.22.4 lint", "beta-build": "docker build -t ipfs-companion-beta-build --build-arg USER_ID=$(id -u ${USER}) --build-arg GROUP_ID=$(id -g ${USER}) . && mkdir -p build && docker run --rm -it --net=host -e RELEASE_CHANNEL=beta -v $(pwd)/build:/home/node/app/build ipfs-companion-beta-build yarn ci:build", "release-build": "docker build -t ipfs-companion-release-build --build-arg USER_ID=$(id -u ${USER}) --build-arg GROUP_ID=$(id -g ${USER}) . && mkdir -p build && docker run --rm -it --net=host -e RELEASE_CHANNEL=stable -v $(pwd)/build:/home/node/app/build ipfs-companion-release-build yarn ci:build", - "dev-build": "npx yarn@1.19.2 && npx yarn@1.19.2 build", + "dev-build": "npx yarn@1.22.4 && npx yarn@1.22.4 build", "yarn-build": "npm run dev-build" }, "private": true, From a736a5f15475ec622751c4850eff8a91bb71b9b6 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 20 Mar 2020 01:07:11 +0100 Subject: [PATCH 03/12] feat: subdomain gateway via HTTP proxy This adds support for subdomain gateways introduced in go-ipfs v0.5.0, specifically, one running at *.localhost subdomains They key challenge was to ensure *.localhost DNS names resolve to 127.0.0.1 on all platforms. We do that by setting up HTTP Gateway port of local go-ipfs to act as HTTP Proxy. This removes DNS lookup step from the browser, and go-ipfs ships with implicit support for subdomain gateway when request comes with "Host: .ipfs.localhost:8080" or similar. We register HTTP proxy using Firefox and Chromium-specific APIs, but the end result is the same. When enableid, default gateway uses 'localhost' hostname (subdomain gateway) instead of '127.0.0.1' (path gateway) and every path-pased request gets redirected to subdomain by go-ipfs itself, which decreases complexity on browser extension side. By default, extension will now redirect from public subdomain gateways such as dweb.link: https://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq.ipfs.dweb.link/wiki/ to the local one: http://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq.ipfs.localhost:8080/wiki/ Redirect to gateway logic was path based, this is wip surgical refactor to unify subdomain and path handling, hopefully decreasing maintenance buden going forward This is work in progress. Fixes will be applied in separate commits. --- .gitignore | 1 + add-on/_locales/en/messages.json | 10 +- add-on/_locales/nl/messages.json | 2 +- add-on/manifest.common.json | 1 + add-on/src/lib/dnslink.js | 15 +- add-on/src/lib/http-proxy.js | 130 ++ add-on/src/lib/ipfs-companion.js | 42 +- add-on/src/lib/ipfs-import.js | 6 +- add-on/src/lib/ipfs-path.js | 305 ++-- add-on/src/lib/ipfs-request.js | 135 +- add-on/src/lib/options.js | 52 +- add-on/src/lib/state.js | 27 +- add-on/src/options/forms/api-form.js | 4 +- add-on/src/options/forms/gateways-form.js | 30 +- add-on/src/options/page.js | 1 + .../popup/browser-action/context-actions.js | 11 +- package.json | 20 +- test/functional/lib/dnslink.test.js | 36 +- test/functional/lib/ipfs-path.test.js | 63 +- .../lib/ipfs-request-gateway-recover.test.js | 19 +- .../lib/ipfs-request-gateway-redirect.test.js | 118 +- yarn.lock | 1508 ++++++++++------- 22 files changed, 1543 insertions(+), 993 deletions(-) create mode 100644 add-on/src/lib/http-proxy.js diff --git a/.gitignore b/.gitignore index a609aa0fa..6cca7dbc8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build npm-debug.log yarn-error.log crowdin.yml +.connect-deps* .*~ add-on/dist add-on/webui/ diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json index 02152da13..4434db2ac 100644 --- a/add-on/_locales/en/messages.json +++ b/add-on/_locales/en/messages.json @@ -279,6 +279,14 @@ "message": "Redirect requests for IPFS resources to the Custom gateway", "description": "An option description on the Preferences screen (option_useCustomGateway_description)" }, + "option_useSubdomainProxy_title": { + "message": "Use Subdomain Proxy", + "description": "An option title on the Preferences screen (option_useSubdomainProxy_title)" + }, + "option_useSubdomainProxy_description": { + "message": "Use Custom Gateway as HTTP Proxy to enable Origin isolation per content root at *.ipfs.localhost", + "description": "An option description on the Preferences screen (option_useSubdomainProxy_description)" + }, "option_dnslinkRedirect_title": { "message": "Load websites from Custom Gateway", "description": "An option title on the Preferences screen (option_dnslinkRedirect_title)" @@ -296,7 +304,7 @@ "description": "An option description on the Preferences screen (option_dnslinkDataPreload_description)" }, "option_dnslinkRedirect_warning": { - "message": "Redirecting to a path-based gateway breaks Origin-based security isolation of DNSLink websites. Make sure you understand related risks.", + "message": "Avoid using this if your IPFS Node does not support *.ipfs.localhost. Redirecting to a path-based gateway breaks Origin-based security isolation of DNSLink websites. Make sure you understand related risks.", "description": "A warning on the Preferences screen, displayed when URL does not belong to Secure Context (option_customGatewayUrl_warning)" }, "option_noIntegrationsHostnames_title": { diff --git a/add-on/_locales/nl/messages.json b/add-on/_locales/nl/messages.json index f3d8ee959..2f04b3e0f 100644 --- a/add-on/_locales/nl/messages.json +++ b/add-on/_locales/nl/messages.json @@ -268,7 +268,7 @@ "description": "An option description on the Preferences screen (option_customGatewayUrl_description)" }, "option_customGatewayUrl_warning": { - "message": "IPFS content will be blocked from loading on HTTPS websites unless your gateway URL starts with “http://127.0.0.1”, “http://[::1]” or “https://”", + "message": "IPFS content will be blocked from loading on HTTPS websites unless your gateway URL starts with “http://localhost”, “http://127.0.0.1”, “http://[::1]” or “https://”", "description": "A warning on the Preferences screen, displayed when URL does not belong to Secure Context (option_customGatewayUrl_warning)" }, "option_useCustomGateway_title": { diff --git a/add-on/manifest.common.json b/add-on/manifest.common.json index bd5abd409..8aa8f9f80 100644 --- a/add-on/manifest.common.json +++ b/add-on/manifest.common.json @@ -20,6 +20,7 @@ "unlimitedStorage", "contextMenus", "clipboardWrite", + "proxy", "webNavigation", "webRequest", "webRequestBlocking" diff --git a/add-on/src/lib/dnslink.js b/add-on/src/lib/dnslink.js index d6c03dc78..79a8ee558 100644 --- a/add-on/src/lib/dnslink.js +++ b/add-on/src/lib/dnslink.js @@ -9,7 +9,7 @@ const IsIpfs = require('is-ipfs') const LRU = require('lru-cache') const { default: PQueue } = require('p-queue') const { offlinePeerCount } = require('./state') -const { pathAtHttpGateway } = require('./ipfs-path') +const { sameGateway, pathAtHttpGateway } = require('./ipfs-path') // TODO: add Preferences toggle to disable redirect of DNSLink websites (while keeping async dnslink lookup) @@ -47,11 +47,11 @@ module.exports = function createDnslinkResolver (getState) { return state.dnslinkPolicy && requestUrl.startsWith('http') && !IsIpfs.url(requestUrl) && - !requestUrl.startsWith(state.apiURLString) && - !requestUrl.startsWith(state.gwURLString) + !sameGateway(requestUrl, state.apiURL) && + !sameGateway(requestUrl, state.gwURL) }, - dnslinkRedirect (url, dnslink) { + dnslinkAtGateway (url, dnslink) { if (typeof url === 'string') { url = new URL(url) } @@ -61,9 +61,8 @@ module.exports = function createDnslinkResolver (getState) { // to load the correct path from IPFS // - https://github.com/ipfs/ipfs-companion/issues/298 const ipnsPath = dnslinkResolver.convertToIpnsPath(url) - const gateway = state.ipfsNodeType === 'embedded' ? state.pubGwURLString : state.gwURLString - // TODO: redirect to `ipns://` if hasNativeProtocolHandler === true - return { redirectUrl: pathAtHttpGateway(ipnsPath, gateway) } + const gateway = state.localGwAvailable ? state.gwURLString : state.pubGwURLString + return pathAtHttpGateway(ipnsPath, gateway) } }, @@ -111,7 +110,7 @@ module.exports = function createDnslinkResolver (getState) { preloadUrlCache.set(url, true) const dnslink = await dnslinkResolver.resolve(url) if (!dnslink) return - if (state.ipfsNodeType === 'embedded') return + if (!state.localGwAvailable) return if (state.peerCount < 1) return return preloadQueue.add(async () => { const { pathname } = new URL(url) diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js new file mode 100644 index 000000000..381b12c1c --- /dev/null +++ b/add-on/src/lib/http-proxy.js @@ -0,0 +1,130 @@ +'use strict' +/* eslint-env browser, webextensions */ + +const browser = require('webextension-polyfill') +const { safeURL } = require('./options') + +const debug = require('debug') +const log = debug('ipfs-companion:http-proxy') +log.error = debug('ipfs-companion:http-proxy:error') + +// Preface: +// +// When go-ipfs runs on localhost, it exposes two types of gateway: +// 127.0.0.1:8080 - old school path gateway +// localhost:8080 - subdomain gateway supporting Origins like $cid.ipfs.localhost +// More: https://docs-beta.ipfs.io/how-to/address-ipfs-on-web/#subdomain-gateway +// +// In a web browser contexts we care about Origin per content root (CID) +// because entire web security model uses it as a basis for sandboxing and +// access controls: +// https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy + +// registerSubdomainProxy is necessary wourkaround for supporting subdomains +// under 'localhost' (*.ipfs.localhost) because some operating systems do not +// resolve them to local IP and return NX error not found instead +async function registerSubdomainProxy (getState, runtime, notify) { + try { + const { useSubdomainProxy: enable, gwURLString } = getState() + + // HTTP Proxy feature is exposed on the gateway port + // Just ensure we use localhost IP to remove any dependency on DNS + const proxy = safeURL(gwURLString, { useLocalhostName: false }) + + // Firefox uses own APIs for selective proxying + if (runtime.isFirefox) { + return await registerSubdomainProxyFirefox(enable, proxy.hostname, proxy.port) + } + + // at this point we asume Chromium + return await registerSubdomainProxyChromium(enable, proxy.host) + } catch (err) { + // registerSubdomainProxy is just a failsafe, not necessary in most cases, + // so we should not break init when it fails. + // For now we just log error and exit as NOOP + log.error('registerSubdomainProxy failed', err) + // Show pop-up only the first time, during init() when notify is passed + try { + if (notify) notify('notify_addonIssueTitle', 'notify_addonIssueMsg') + } catch (_) {} + } +} + +// storing listener for later +var onRequestProxyListener + +// registerSubdomainProxyFirefox sets proxy using API available in Firefox +// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/onRequest +async function registerSubdomainProxyFirefox (enable, host, port) { + const { onRequest } = browser.proxy + + // always remove the old listener (host and port could change) + const oldListener = onRequestProxyListener + if (oldListener && onRequest.hasListener(oldListener)) { + onRequest.removeListener(oldListener) + } + + if (enable) { + // create new listener with the latest host:port + onRequestProxyListener = (request) => ({ type: 'http', host, port }) + + // register the listener + onRequest.addListener(onRequestProxyListener, { + urls: ['http://*.localhost/*'], + incognito: false + }) + log(`enabled ${host}:${port} as HTTP proxy for *.localhost`) + return + } + + // at this point we effectively disabled proxy + log('disabled HTTP proxy for *.localhost') +} + +// Helpers for converting callback chrome.* API to promises +const cb = (resolve, reject) => (result) => { + const err = chrome.runtime.lastError + if (err) return reject(err) + return resolve(result) +} +const get = async (opts) => new Promise((resolve, reject) => chrome.proxy.settings.get(opts, cb(resolve, reject))) +const set = async (opts) => new Promise((resolve, reject) => chrome.proxy.settings.set(opts, cb(resolve, reject))) +const clear = async (opts) => new Promise((resolve, reject) => chrome.proxy.settings.clear(opts, cb(resolve, reject))) + +// registerSubdomainProxyChromium sets proxy using API available in Chromium +// https://developer.chrome.com/extensions/proxy +async function registerSubdomainProxyChromium (enable, proxyHost) { + const scope = 'regular_only' + + // read current proxy settings + const settings = await get({ incognito: false }) + + // set or update, if enabled + if (enable) { + // PAC script enables selective routing to PROXY at host+port + // here, PROXY is the same as HTTP API endpoint + const pacConfig = { + mode: 'pac_script', + pacScript: { + data: 'function FindProxyForURL(url, host) {\n' + + " if (shExpMatch(host, '*.localhost'))\n" + + ` return 'PROXY ${proxyHost}';\n` + + " return 'DIRECT';\n" + + '}' + } + } + await set({ value: pacConfig, scope }) + log(`enabled ${proxyHost} as HTTP proxy for *.localhost`) + // log('updated chrome.proxy.settings', await get({ incognito: false })) + return + } + + // else: remove any existing proxy settings + if (settings && settings.levelOfControl === 'controlled_by_this_extension') { + // remove any proxy settings ipfs-companion set up before + await clear({ scope }) + log('disabled HTTP proxy for *.localhost') + } +} + +module.exports.registerSubdomainProxy = registerSubdomainProxy diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 334ad25cb..89fb6119a 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -8,9 +8,9 @@ log.error = debug('ipfs-companion:main:error') const browser = require('webextension-polyfill') const toMultiaddr = require('uri-to-multiaddr') const pMemoize = require('p-memoize') -const { optionDefaults, storeMissingOptions, migrateOptions } = require('./options') +const { optionDefaults, storeMissingOptions, migrateOptions, guiURLString } = require('./options') const { initState, offlinePeerCount } = require('./state') -const { createIpfsPathValidator } = require('./ipfs-path') +const { createIpfsPathValidator, sameGateway } = require('./ipfs-path') const createDnslinkResolver = require('./dnslink') const { createRequestModifier } = require('./ipfs-request') const { initIpfsClient, destroyIpfsClient } = require('./ipfs-client') @@ -22,6 +22,7 @@ const createInspector = require('./inspector') const { createRuntimeChecks } = require('./runtime-checks') const { createContextMenus, findValueForContext, contextMenuCopyAddressAtPublicGw, contextMenuCopyRawCid, contextMenuCopyCanonicalAddress, contextMenuViewOnGateway } = require('./context-menus') const createIpfsProxy = require('./ipfs-proxy') +const { registerSubdomainProxy } = require('./http-proxy') const { showPendingLandingPages } = require('./on-installed') // init happens on addon load in background/background.js @@ -84,6 +85,7 @@ module.exports = async function init () { log('register all listeners') registerListeners() await setApiStatusUpdateInterval(options.ipfsApiPollMs) + await registerSubdomainProxy(getState, runtime, notify) log('init done') await showPendingLandingPages() } catch (error) { @@ -189,7 +191,8 @@ module.exports = async function init () { // console.log((sender.tab ? 'Message from a content script:' + sender.tab.url : 'Message from the extension'), request) if (request.pubGwUrlForIpfsOrIpnsPath) { const path = request.pubGwUrlForIpfsOrIpnsPath - const result = ipfsPathValidator.validIpfsOrIpnsPath(path) ? ipfsPathValidator.resolveToPublicUrl(path, state.pubGwURLString) : null + const { validIpfsOrIpns, resolveToPublicUrl } = ipfsPathValidator + const result = validIpfsOrIpns(path) ? resolveToPublicUrl(path) : null return Promise.resolve({ pubGwUrlForIpfsOrIpnsPath: result }) } } @@ -321,7 +324,7 @@ module.exports = async function init () { } ipfsImportHandler.copyShareLink(result) ipfsImportHandler.preloadFilesAtPublicGateway(result) - if (state.ipfsNodeType === 'embedded' || !state.openViaWebUI) { + if (!state.localGwAvailable || !state.openViaWebUI) { return ipfsImportHandler.openFilesAtGateway({ result, openRootInNewTab: true }) } else { return ipfsImportHandler.openFilesAtWebUI(importDir) @@ -353,7 +356,7 @@ module.exports = async function init () { // Chrome does not permit for both pageAction and browserAction to be enabled at the same time // https://github.com/ipfs-shipyard/ipfs-companion/issues/398 if (runtime.isFirefox && ipfsPathValidator.isIpfsPageActionsContext(url)) { - if (url.startsWith(state.gwURLString) || url.startsWith(state.apiURLString)) { + if (sameGateway(url, state.gwURL) || sameGateway(url, state.apiURL)) { await browser.pageAction.setIcon({ tabId: tabId, path: '/icons/ipfs-logo-on.svg' }) await browser.pageAction.setTitle({ tabId: tabId, title: browser.i18n.getMessage('pageAction_titleIpfsAtCustomGateway') }) } else { @@ -554,7 +557,7 @@ module.exports = async function init () { // enable/disable gw redirect based on API going online or offline // newPeerCount === -1 currently implies node is offline. // TODO: use `node.isOnline()` if available (js-ipfs) - if (state.automaticMode && state.ipfsNodeType !== 'embedded') { + if (state.automaticMode && state.localGwAvailable) { if (oldPeerCount === offlinePeerCount && newPeerCount > offlinePeerCount && !state.redirect) { browser.storage.local.set({ useCustomGateway: true }) .then(() => notify('notify_apiOnlineTitle', 'notify_apiOnlineAutomaticModeMsg')) @@ -619,7 +622,8 @@ module.exports = async function init () { case 'customGatewayUrl': state.gwURL = new URL(change.newValue) state.gwURLString = state.gwURL.toString() - state.webuiRootUrl = `${state.gwURLString}ipfs/${state.webuiCid}/` + // TODO: for now we load webui from API port, should we remove this? + // state.webuiRootUrl = `${state.gwURLString}ipfs/${state.webuiCid}/` break case 'publicGatewayUrl': state.pubGwURL = new URL(change.newValue) @@ -632,8 +636,26 @@ module.exports = async function init () { case 'useCustomGateway': state.redirect = change.newValue break + case 'useSubdomainProxy': + state[key] = change.newValue + // More work is needed, as this key decides how requests are routed + // to the gateway: + await browser.storage.local.set({ + // We need to update the hostname in customGatewayUrl: + // 127.0.0.1 - path gateway + // localhost - subdomain gateway + customGatewayUrl: guiURLString( + state.gwURLString, { + useLocalhostName: state.useSubdomainProxy + } + ) + }) + // Finally, update proxy settings based on the state + await registerSubdomainProxy(getState, runtime) + break case 'ipfsProxy': state[key] = change.newValue + // This is window.ipfs proxy, requires update of the content script: ipfsProxyContentScript = await registerIpfsProxyContentScript() break case 'dnslinkPolicy': @@ -642,16 +664,12 @@ module.exports = async function init () { await browser.storage.local.set({ detectIpfsPathHeader: true }) } break - case 'recoverFailedHttpRequests': - state[key] = change.newValue - break case 'logNamespaces': shouldReloadExtension = true state[key] = localStorage.debug = change.newValue break + case 'recoverFailedHttpRequests': case 'importDir': - state[key] = change.newValue - break case 'linkify': case 'catchUnhandledProtocols': case 'displayNotifications': diff --git a/add-on/src/lib/ipfs-import.js b/add-on/src/lib/ipfs-import.js index 984b45880..cbae7a950 100644 --- a/add-on/src/lib/ipfs-import.js +++ b/add-on/src/lib/ipfs-import.js @@ -6,6 +6,7 @@ const browser = require('webextension-polyfill') const { redirectOptOutHint } = require('./ipfs-request') function createIpfsImportHandler (getState, getIpfs, ipfsPathValidator, runtime, copier) { + const { resolveToPublicUrl } = ipfsPathValidator const ipfsImportHandler = { formatImportDirectory (path) { path = path.replace(/\/$|$/, '/') @@ -72,7 +73,7 @@ function createIpfsImportHandler (getState, getIpfs, ipfsPathValidator, runtime, return new Promise((resolve, reject) => { const http = new XMLHttpRequest() // Make sure preload request is excluded from global redirect - const preloadUrl = ipfsPathValidator.resolveToPublicUrl(`${path}#${redirectOptOutHint}`, state.pubGwURLString) + const preloadUrl = resolveToPublicUrl(`${path}#${redirectOptOutHint}`) http.open('HEAD', preloadUrl) http.onreadystatechange = function () { if (this.readyState === this.DONE) { @@ -100,8 +101,7 @@ function createIpfsImportHandler (getState, getIpfs, ipfsPathValidator, runtime, // share wrapping dir path = `/ipfs/${root.hash}/` } - const state = getState() - const url = ipfsPathValidator.resolveToPublicUrl(path, state.pubGwURLString) + const url = resolveToPublicUrl(path) await copier.copyTextToClipboard(url) }, async preloadFilesAtPublicGateway (files) { diff --git a/add-on/src/lib/ipfs-path.js b/add-on/src/lib/ipfs-path.js index 7aa623758..5e7e1f9c7 100644 --- a/add-on/src/lib/ipfs-path.js +++ b/add-on/src/lib/ipfs-path.js @@ -1,37 +1,52 @@ 'use strict' /* eslint-env browser */ -const IsIpfs = require('is-ipfs') +const isIPFS = require('is-ipfs') const isFQDN = require('is-fqdn') -function normalizedIpfsPath (urlOrPath) { - let result = urlOrPath - // Convert CID-in-subdomain URL to /ipns// path - if (IsIpfs.subdomain(urlOrPath)) { - result = subdomainToIpfsPath(urlOrPath) +// Turns URL or URIencoded path into a content path +function ipfsContentPath (urlOrPath, opts) { + opts = opts || {} + + // Fail fast if no content path can be extracted from input + if (!isIPFS.urlOrPath(urlOrPath)) return null + + // Turn path to URL (hostname does not matter, let's use localhost) + if (isIPFS.path(urlOrPath)) urlOrPath = `https://localhost${urlOrPath}` + + // Create URL + let url = typeof urlOrPath === 'string' ? new URL(urlOrPath) : urlOrPath + + if (isIPFS.subdomain(urlOrPath)) { + // Move CID-in-subdomain to URL pathname + const { id, ns } = subdomainPatternMatch(url) + url = new URL(`https://localhost/${ns}/${id}${url.pathname}${url.search}${url.hash}`) } - // Drop everything before the IPFS path - result = result.replace(/^.*(\/ip(f|n)s\/.+)$/, '$1') - // Remove Unescape special characters - // https://github.com/ipfs/ipfs-companion/issues/303 - result = decodeURIComponent(result) - // Return a valid IPFS path or null otherwise - return IsIpfs.path(result) ? result : null + + // To get IPFS content path we need to reverse URI encoding of special + // characters (https://github.com/ipfs/ipfs-companion/issues/303) + const contentPath = decodeURIComponent(url.pathname) + + // End if not a content path + if (!isIPFS.path(contentPath)) return null + + // Attach suffix with query parameters or hash if explicitly asked to do so + if (opts.keepURIParams) return `${contentPath}${url.search}${url.hash}` + + // Else, return content path as-is + return contentPath } -exports.normalizedIpfsPath = normalizedIpfsPath +exports.ipfsContentPath = ipfsContentPath -function subdomainToIpfsPath (url) { +function subdomainPatternMatch (url) { if (typeof url === 'string') { url = new URL(url) } - const match = url.toString().match(IsIpfs.subdomainPattern) - if (!match) throw new Error('no match for IsIpfs.subdomainPattern') - - // TODO: support CID split with commas - const cid = match[1] - // TODO: support .ip(f|n)s. being at deeper levels - const protocol = match[2] - return `/${protocol}/${cid}${url.pathname}${url.search}${url.hash}` + const match = url.toString().match(isIPFS.subdomainGatewayPattern) + if (!match || match.length < 3) return false + const id = match[1] + const ns = match[2] + return { id, ns } } function pathAtHttpGateway (path, gatewayUrl) { @@ -40,17 +55,16 @@ function pathAtHttpGateway (path, gatewayUrl) { } exports.pathAtHttpGateway = pathAtHttpGateway -function redirectSubdomainGateway (url, subdomainGateway) { +function swapSubdomainGateway (url, subdomainGwURL) { if (typeof url === 'string') { url = new URL(url) } - const match = url.toString().match(IsIpfs.subdomainPattern) - if (!match) throw new Error('no match for IsIpfs.subdomainPattern') - const cid = match[1] - const protocol = match[2] - return trimDoubleSlashes(`${subdomainGateway.protocol}//${cid}.${protocol}.${subdomainGateway.hostname}${url.pathname}${url.search}${url.hash}`) + const { id, ns } = subdomainPatternMatch(url) + if (!id || !ns) throw new Error('no matching isIPFS.*subdomainPattern') + return new URL(trimDoubleSlashes( + `${subdomainGwURL.protocol}//${id}.${ns}.${subdomainGwURL.hostname}${url.pathname}${url.search}${url.hash}` + )).toString() } -exports.redirectSubdomainGateway = redirectSubdomainGateway function trimDoubleSlashes (urlString) { return urlString.replace(/([^:]\/)\/+/g, '$1') @@ -63,79 +77,168 @@ function trimHashAndSearch (urlString) { } exports.trimHashAndSearch = trimHashAndSearch +// Returns true if URL belongs to the gateway. +// The check includes subdomain gateways and quirks of ipfs.io +function sameGateway (url, gwUrl) { + if (typeof url === 'string') { + url = new URL(url) + } + if (typeof gwUrl === 'string') { + gwUrl = new URL(gwUrl) + } + + if (url.hostname === 'ipfs.io') { + // canonical gateway uses the same hostname as various DNSLink websites + // related to IPFS project. To avoid false-positive we reduce it to only + // match as path-based gateway, and not subdomains. + return url.hostname === gwUrl.hostname + } + + const gws = [gwUrl.hostname] + + // localhost gateway has more than one hostname + if (gwUrl.hostname === 'localhost') { + gws.push(`127.0.0.1:${gwUrl.port}`) + } + if (gwUrl.hostname === '127.0.0.1' || gwUrl.hostname === '[::1]') { + gws.push(`localhost:${gwUrl.port}`) + } + + for (const gwName of gws) { + // match against the end to include subdomain gateways + if (url.hostname.endsWith(gwName)) return true + } + return false +} +exports.sameGateway = sameGateway + function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { const ipfsPathValidator = { // Test if URL is a Public IPFS resource - // (pass validIpfsOrIpnsUrl(url) and not at the local gateway or API) + // (pass validIpfsOrIpns(url) and not at the local gateway or API) publicIpfsOrIpnsResource (url) { // exclude custom gateway and api, otherwise we have infinite loops - if (!url.startsWith(getState().gwURLString) && !url.startsWith(getState().apiURLString)) { - return validIpfsOrIpnsUrl(url, dnslinkResolver) + const { gwURL, apiURL } = getState() + if (!sameGateway(url, gwURL) && !sameGateway(url, apiURL)) { + return this.validIpfsOrIpns(url) } return false }, - // Test if URL is a valid IPFS or IPNS + // Test if URL or a path is a valid IPFS resource // (IPFS needs to be a CID, IPNS can be PeerId or have dnslink entry) - validIpfsOrIpnsUrl (url) { - return validIpfsOrIpnsUrl(url, dnslinkResolver) - }, + validIpfsOrIpns (urlOrPath) { + // normalize input to a content path + const path = ipfsContentPath(urlOrPath) + if (!path) return false - // Same as validIpfsOrIpnsUrl (url) but for paths - // (we have separate methods to avoid 'new URL' where possible) - validIpfsOrIpnsPath (path) { - return validIpfsOrIpnsPath(path, dnslinkResolver) - }, - // Test if URL is a subdomain gateway resource - // TODO: add test if URL is a public subdomain resource - ipfsOrIpnsSubdomain (url) { - return IsIpfs.subdomain(url) + // `/ipfs/` is easy to validate, we just check if CID is correct + if (isIPFS.ipfsPath(path)) { + return true + } + // `/ipns/` requires multiple stages/branches (can be FQDN with dnslink or CID) + if (isIPFS.ipnsPath(path)) { + // we may have false-positives here, so we do additional checks below + const ipnsRoot = path.match(/^\/ipns\/([^/?#]+)/)[1] + // console.log('==> IPNS root', ipnsRoot) + // first check if root is a regular CID + // TODO: support all peerIds, not just cids? + if (isIPFS.cid(ipnsRoot)) { + // console.log('==> IPNS is a valid CID', ipnsRoot) + return true + } + // then see if there is an DNSLink entry for 'ipnsRoot' hostname + // TODO: use dnslink cache only + if (dnslinkResolver.readAndCacheDnslink(ipnsRoot)) { + // console.log('==> IPNS for FQDN with valid dnslink: ', ipnsRoot) + return true + } + } + // everything else is not IPFS-related + return false }, + // Test if actions such as 'copy URL', 'pin/unpin' should be enabled for the URL isIpfsPageActionsContext (url) { - return Boolean(url && !url.startsWith(getState().apiURLString) && ( - IsIpfs.url(url) || - IsIpfs.subdomain(url) || - dnslinkResolver.cachedDnslink(new URL(url).hostname) + const { apiURLString } = getState() + const { hostname } = new URL(url) + return Boolean(url && !url.startsWith(apiURLString) && ( + isIPFS.url(url) || + dnslinkResolver.cachedDnslink(hostname) )) }, // Test if actions such as 'per site redirect toggle' should be enabled for the URL isRedirectPageActionsContext (url) { - const state = getState() - return state.ipfsNodeType !== 'embedded' && // hide with embedded node - (IsIpfs.ipnsUrl(url) || // show on /ipns/ + const { ipfsNodeType, gwURL, apiURL } = getState() + return ipfsNodeType !== 'embedded' && // hide with embedded node + (isIPFS.ipnsUrl(url) || // show on /ipns/ (url.startsWith('http') && // hide on non-HTTP pages - !url.startsWith(state.gwURLString) && // hide on /ipfs/* - !url.startsWith(state.apiURLString))) // hide on api port + !sameGateway(url, gwURL) && // hide on /ipfs/* and *.ipfs. + !sameGateway(url, apiURL))) // hide on api port }, // Resolve URL or path to HTTP URL: - // - IPFS paths are attached to HTTP Gateway root + // - IPFS paths are attached to HTTP Path Gateway root + // - IPFS subdomains are attached to HTTP Subdomain Gateway root // - URL of DNSLinked websites are returned as-is + // // The purpose of this resolver is to always return a meaningful, publicly // accessible URL that can be accessed without the need of IPFS client. - resolveToPublicUrl (urlOrPath, optionalGatewayUrl) { + // TODO: add Local version + resolveToPublicUrl (urlOrPath) { + const { pubSubdomainGwURL, pubGwURLString } = getState() const input = urlOrPath - // CID-in-subdomain is good as-is - if (IsIpfs.subdomain(input)) return input + + // SUBDOMAINS + // Detect *.dweb.link and other subdomain gateways + if (isIPFS.subdomain(input)) { + // Switch Origin to prefered public subdomain gateway (default: dweb.link) + const subdomainUrl = swapSubdomainGateway(input, pubSubdomainGwURL) + + // *.ipfs namespace is easy, just return + if (isIPFS.ipfsSubdomain(subdomainUrl)) return subdomainUrl + + // DNSLink in subdomains does not make sense outside of *.localhost + // and is usually not supported due to limitation of TLS wildcart certs. + // Instead, we resolve it to the canonical FQDN Origin + // + // Remove gateway suffix to get potential FQDN + const url = new URL(input) + const ipnsId = url.hostname.replace(`.ipns.${pubSubdomainGwURL.hostname}`, '') + // Ensure it includes .tld (needs at least one dot) + if (ipnsId.includes('.')) { + // Confirm DNSLink record is present and its not a false-positive + const dnslink = dnslinkResolver.readAndCacheDnslink(ipnsId) + if (dnslink) { + // return URL to DNSLink hostname (FQDN without any suffix) + url.hostname = ipnsId + return url.toString() + } + } + + // Return *.ipns with libp2p-key + if (isIPFS.ipnsSubdomain(subdomainUrl)) return subdomainUrl + } + + // PATHS + const ipfsPath = ipfsContentPath(input, { keepURIParams: true }) + // IPFS Paths should be attached to the public gateway - const ipfsPath = normalizedIpfsPath(input) - const gateway = optionalGatewayUrl || getState().pubGwURLString - if (ipfsPath) return pathAtHttpGateway(ipfsPath, gateway) - // Return original URL (eg. DNSLink domains) or null if not an URL - return input.startsWith('http') ? input : null + if (isIPFS.path(ipfsPath)) return pathAtHttpGateway(ipfsPath, pubGwURLString) + + // Return original URL as-is (eg. DNSLink domains) or null if not an URL + return input && input.startsWith('http') ? input : null }, - // Resolve URL or path to subdomain gateway - // - non-subdomain path is returned as-is - // The purpose of this resolver is to return a valid IPFS - // subdomain URL - resolveToPublicSubdomainUrl (url, optionalGatewayUrl) { - // if non-subdomain return as-is - if (!IsIpfs.subdomain(url)) return url - - const gateway = optionalGatewayUrl || getState().pubSubdomainGwURL - return redirectSubdomainGateway(url, gateway) + + // Version of resolveToPublicUrl that always resolves to URL representing + // path gateway at local machine (This is ok, as subdomain will redirect + // to corre + resolveToLocalUrl (urlOrPath) { + const { gwURLString } = getState() + const ipfsPath = ipfsContentPath(urlOrPath, { keepURIParams: true }) + if (isIPFS.path(ipfsPath)) return pathAtHttpGateway(ipfsPath, gwURLString) + return null }, // Resolve URL or path to IPFS Path: @@ -147,7 +250,7 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { resolveToIpfsPath (urlOrPath) { const input = urlOrPath // Try to normalize to IPFS path (gateway path or CID-in-subdomain) - const ipfsPath = normalizedIpfsPath(input) + const ipfsPath = ipfsContentPath(input, { keepURIParams: true }) if (ipfsPath) return ipfsPath // Check URL for DNSLink if (!input.startsWith('http')) return null @@ -172,7 +275,7 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { // Fail fast if no IPFS Path if (!path) return null // Resolve /ipns/ → /ipfs/ - if (IsIpfs.ipnsPath(path)) { + if (isIPFS.ipnsPath(path)) { const labels = path.split('/') // We resolve /ipns/ as value in DNSLink cache may be out of date const ipnsRoot = `/ipns/${labels[2]}` @@ -240,7 +343,7 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { if (rawPath !== safePath) { const result = await ipfsPathValidator.resolveToCid(safePath) // return in format of ipfs.resolve() - return IsIpfs.cid(result) ? `/ipfs/${result}` : result + return isIPFS.cid(result) ? `/ipfs/${result}` : result } } } @@ -252,7 +355,7 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { getIpfs().resolve(rawPath, { recursive: true, dhtt: '5s', dhtrc: 1 }) ) - const directCid = IsIpfs.ipfsPath(result) ? result.split('/')[2] : result + const directCid = isIPFS.ipfsPath(result) ? result.split('/')[2] : result return directCid } } @@ -260,49 +363,3 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { return ipfsPathValidator } exports.createIpfsPathValidator = createIpfsPathValidator - -function validIpfsOrIpnsUrl (url, dnsLink) { - // `/ipfs/` is easy to validate, we just check if CID is correct - if (IsIpfs.ipfsUrl(url)) { - return true - } - // `/ipns/` requires multiple stages/branches (can be FQDN with dnslink or CID) - if (validIpnsPath(new URL(url).pathname, dnsLink)) { - return true - } - // everything else is not IPFS-related - return false -} - -function validIpfsOrIpnsPath (path, dnsLink) { - // `/ipfs/` is easy to validate, we just check if CID is correct - if (IsIpfs.ipfsPath(path)) { - return true - } - // `/ipns/` requires multiple stages/branches (can be FQDN with dnslink or CID) - if (validIpnsPath(path, dnsLink)) { - return true - } - // everything else is not IPFS-related - return false -} - -function validIpnsPath (path, dnsLink) { - if (IsIpfs.ipnsPath(path)) { - // we may have false-positives here, so we do additional checks below - const ipnsRoot = path.match(/^\/ipns\/([^/]+)/)[1] - // console.log('==> IPNS root', ipnsRoot) - // first check if root is a regular CID - if (IsIpfs.cid(ipnsRoot)) { - // console.log('==> IPNS is a valid CID', ipnsRoot) - return true - } - // then see if there is an DNSLink entry for 'ipnsRoot' hostname - // TODO: use dnslink cache only - if (dnsLink.readAndCacheDnslink(ipnsRoot)) { - // console.log('==> IPNS for FQDN with valid dnslink: ', ipnsRoot) - return true - } - } - return false -} diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index 26f34a528..f524afc1d 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -6,9 +6,9 @@ const log = debug('ipfs-companion:request') log.error = debug('ipfs-companion:request:error') const LRU = require('lru-cache') -const IsIpfs = require('is-ipfs') +const isIPFS = require('is-ipfs') const isFQDN = require('is-fqdn') -const { pathAtHttpGateway } = require('./ipfs-path') +const { pathAtHttpGateway, sameGateway } = require('./ipfs-path') const redirectOptOutHint = 'x-ipfs-companion-no-redirect' const recoverableNetworkErrors = new Set([ @@ -65,7 +65,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru const preNormalizationSkip = (state, request) => { // skip requests to the custom gateway or API (otherwise we have too much recursion) - if (request.url.startsWith(state.gwURLString) || request.url.startsWith(state.apiURLString)) { + if (sameGateway(request.url, state.gwURL) || sameGateway(request.url, state.apiURL)) { ignore(request.requestId) } // skip websocket handshake (not supported by HTTP2IPFS gateways) @@ -96,8 +96,9 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru } const postNormalizationSkip = (state, request) => { - // skip requests to the public gateway if embedded node is running (otherwise we have too much recursion) - if (state.ipfsNodeType === 'embedded' && request.url.startsWith(state.pubGwURLString)) { + // skip requests to the public gateway if we can't reedirect them to local + // node is running (otherwise we have too much recursion) + if (!state.localGwAvailable && sameGateway(request.url, state.pubGwURL)) { ignore(request.requestId) // TODO: do not skip and redirect to `ipfs://` and `ipns://` if hasNativeProtocolHandler === true } @@ -139,15 +140,15 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru } // Detect valid /ipfs/ and /ipns/ on any site if (ipfsPathValidator.publicIpfsOrIpnsResource(request.url) && isSafeToRedirect(request, runtime)) { - return redirectToGateway(request.url, state, ipfsPathValidator) + return redirectToGateway(request, request.url, state, ipfsPathValidator) } // Detect dnslink using heuristics enabled in Preferences if (state.dnslinkPolicy && dnslinkResolver.canLookupURL(request.url)) { if (state.dnslinkRedirect) { - const dnslinkRedirect = dnslinkResolver.dnslinkRedirect(request.url) - if (dnslinkRedirect && isSafeToRedirect(request, runtime)) { + const redirectUrl = dnslinkResolver.dnslinkAtGateway(request.url) + if (redirectUrl && isSafeToRedirect(request, runtime)) { // console.log('onBeforeRequest.dnslinkRedirect', dnslinkRedirect) - return dnslinkRedirect + return { redirectUrl } } } else if (state.dnslinkDataPreload) { dnslinkResolver.preloadData(request.url) @@ -167,7 +168,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (!state.active) return // Special handling of requests made to API - if (request.url.startsWith(state.apiURLString)) { + if (sameGateway(request.url, state.apiURL)) { // Requests made by 'blessed' Web UI // -------------------------------------------- // Goal: Web UI works without setting CORS at go-ipfs @@ -278,7 +279,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (!state.active) return // Special handling of requests made to API - if (request.url.startsWith(state.apiURLString)) { + if (sameGateway(request.url, state.apiURL)) { // Special handling of requests made by 'blessed' Web UI from local Gateway // Goal: Web UI works without setting CORS at go-ipfs // (This includes 'ignored' requests: CORS needs to be fixed even if no redirect is done) @@ -323,19 +324,19 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (runtime.requiresXHRCORSfix && onHeadersReceivedRedirect.has(request.requestId)) { onHeadersReceivedRedirect.delete(request.requestId) if (state.dnslinkPolicy) { - const dnslinkRedirect = dnslinkResolver.dnslinkRedirect(request.url) - if (dnslinkRedirect) { - return dnslinkRedirect + const redirectUrl = dnslinkResolver.dnslinkAtGateway(request.url) + if (redirectUrl) { + return { redirectUrl } } } - return redirectToGateway(request.url, state, ipfsPathValidator) + return redirectToGateway(request, request.url, state, ipfsPathValidator) } // Detect X-Ipfs-Path Header and upgrade transport to IPFS: // 1. Check if DNSLink exists and redirect to it. // 2. If there is no DNSLink, validate path from the header and redirect - const url = request.url - const notActiveGatewayOrApi = !(url.startsWith(state.pubGwURLString) || url.startsWith(state.gwURLString) || url.startsWith(state.apiURLString)) + const { url } = request + const notActiveGatewayOrApi = !(sameGateway(url, state.pubGwURL) || sameGateway(url, state.gwURL) || sameGateway(url, state.apiURL)) if (state.detectIpfsPathHeader && request.responseHeaders && notActiveGatewayOrApi) { // console.log('onHeadersReceived.request', request) for (const header of request.responseHeaders) { @@ -350,18 +351,20 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru // in a way that works even when state.dnslinkPolicy !== 'enabled' // All the following requests will be upgraded to IPNS const cachedDnslink = dnslinkResolver.readAndCacheDnslink(new URL(request.url).hostname) - const dnslinkRedirect = dnslinkResolver.dnslinkRedirect(request.url, cachedDnslink) - if (dnslinkRedirect) { - log(`onHeadersReceived: dnslinkRedirect from ${request.url} to ${dnslinkRedirect.redirectUrl}`) - return dnslinkRedirect + const redirectUrl = dnslinkResolver.dnslinkAtGateway(request.url, cachedDnslink) + // redirect only if local node is around, as we can't guarantee DNSLink support + // at a public subdomain gateway (requires more than 1 level of wildcard TLS certs) + if (redirectUrl && state.localGwAvailable) { + log(`onHeadersReceived: dnslinkRedirect from ${request.url} to ${redirectUrl}`) + return { redirectUrl } } } // Additional validation of X-Ipfs-Path - if (IsIpfs.ipnsPath(xIpfsPath)) { + if (isIPFS.ipnsPath(xIpfsPath)) { // Ignore unhandled IPNS path by this point // (means DNSLink is disabled so we don't want to make a redirect that works like DNSLink) // log(`onHeadersReceived: ignoring x-ipfs-path=${xIpfsPath} (dnslinkRedirect=false, dnslinkPolicy=false or missing DNS TXT record)`) - } else if (IsIpfs.ipfsPath(xIpfsPath)) { + } else if (isIPFS.ipfsPath(xIpfsPath)) { // It is possible that someone exposed /ipfs// under / // and our path-based onBeforeRequest heuristics were unable // to identify request as IPFS one until onHeadersReceived revealed @@ -371,10 +374,10 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru const url = new URL(request.url) const pathWithArgs = `${xIpfsPath}${url.search}${url.hash}` const newUrl = pathAtHttpGateway(pathWithArgs, state.pubGwURLString) - // redirect only if anything changed - if (newUrl !== request.url) { + // redirect only if local node is around + if (newUrl && state.localGwAvailable) { log(`onHeadersReceived: normalized ${request.url} to ${newUrl}`) - return redirectToGateway(newUrl, state, ipfsPathValidator) + return redirectToGateway(request, newUrl, state, ipfsPathValidator) } } } @@ -407,9 +410,10 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (isRecoverableViaEthDNS(request, state)) { const url = new URL(request.url) url.hostname = `${url.hostname}.link` - const redirect = { redirectUrl: url.toString() } - log(`onErrorOccurred: attempting to recover from DNS error (${request.error}) using EthDNS for ${request.url} → ${redirect.redirectUrl}`, request) - return createTabWithURL(redirect, browser, recoveredTabs) + const redirectUrl = url.toString() + log(`onErrorOccurred: attempting to recover from DNS error (${request.error}) using EthDNS for ${request.url} → ${redirectUrl}`, request) + // TODO: update existing tab + return createTabWithURL(request, redirectUrl, browser, recoveredTabs) } // Check if error can be recovered via DNSLink @@ -417,9 +421,9 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru const { hostname } = new URL(request.url) const dnslink = dnslinkResolver.readAndCacheDnslink(hostname) if (dnslink) { - const redirect = dnslinkResolver.dnslinkRedirect(request.url, dnslink) - log(`onErrorOccurred: attempting to recover from network error (${request.error}) using dnslink for ${request.url} → ${redirect.redirectUrl}`, request) - return createTabWithURL(redirect, browser, recoveredTabs) + const redirectUrl = dnslinkResolver.dnslinkAtGateway(request.url, dnslink) + log(`onErrorOccurred: attempting to recover from network error (${request.error}) using dnslink for ${request.url} → ${redirectUrl}`, request) + return createTabWithURL(request, redirectUrl, browser, recoveredTabs) } } @@ -431,15 +435,9 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru // Check if error can be recovered by opening same content-addresed path // using active gateway (public or local, depending on redirect state) if (isRecoverable(request, state, ipfsPathValidator)) { - let redirectUrl - // if subdomain request redirect to default public subdomain url - if (ipfsPathValidator.ipfsOrIpnsSubdomain(request.url)) { - redirectUrl = ipfsPathValidator.resolveToPublicSubdomainUrl(request.url, state.pubSubdomainGwURL) - } else { - redirectUrl = ipfsPathValidator.resolveToPublicUrl(request.url, state.pubGwURLString) - } + const redirectUrl = ipfsPathValidator.resolveToPublicUrl(request.url) log(`onErrorOccurred: attempting to recover from network error (${request.error}) for ${request.url} → ${redirectUrl}`, request) - return createTabWithURL({ redirectUrl }, browser, recoveredTabs) + return createTabWithURL(request, redirectUrl, browser, recoveredTabs) } }, @@ -466,16 +464,10 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru return browser.tabs.update({ url: fixedUrl }) } - let redirectUrl if (isRecoverable(request, state, ipfsPathValidator)) { - // if subdomain request redirect to default public subdomain url - if (ipfsPathValidator.ipfsOrIpnsSubdomain(request.url)) { - redirectUrl = ipfsPathValidator.resolveToPublicSubdomainUrl(request.url, state.pubSubdomainGwURL) - } else { - redirectUrl = ipfsPathValidator.resolveToPublicUrl(request.url, state.pubGwURLString) - } + const redirectUrl = ipfsPathValidator.resolveToPublicUrl(request.url) log(`onCompleted: attempting to recover from HTTP Error ${request.statusCode} for ${request.url} → ${redirectUrl}`, request) - return createTabWithURL({ redirectUrl }, browser, recoveredTabs) + return createTabWithURL(request, redirectUrl, browser, recoveredTabs) } } } @@ -484,11 +476,11 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru exports.redirectOptOutHint = redirectOptOutHint exports.createRequestModifier = createRequestModifier -function redirectToGateway (requestUrl, state, ipfsPathValidator) { - // TODO: redirect to `ipfs://` if hasNativeProtocolHandler === true - const gateway = state.ipfsNodeType === 'embedded' ? state.pubGwURLString : state.gwURLString - const redirectUrl = ipfsPathValidator.resolveToPublicUrl(requestUrl, gateway) - return { redirectUrl } +function redirectToGateway (request, url, state, ipfsPathValidator) { + const { resolveToPublicUrl, resolveToLocalUrl } = ipfsPathValidator + const redirectUrl = state.localGwAvailable ? resolveToLocalUrl(url) : resolveToPublicUrl(url) + // redirect only if we actually change anything + if (redirectUrl && request.url !== redirectUrl) return { redirectUrl } } function isSafeToRedirect (request, runtime) { @@ -497,12 +489,6 @@ function isSafeToRedirect (request, runtime) { return false } - // For now we do not redirect if cid-in-subdomain is used - // as it would break origin-based security perimeter - if (IsIpfs.subdomain(request.url)) { - return false - } - // Ignore XHR requests for which redirect would fail due to CORS bug in Firefox // See: https://github.com/ipfs-shipyard/ipfs-companion/issues/436 if (runtime.requiresXHRCORSfix && request.type === 'xmlhttprequest' && !request.responseHeaders) { @@ -547,7 +533,7 @@ function normalizedRedirectingProtocolRequest (request, pubGwUrl) { path = path.replace(/^#ipns:\/\//i, '/ipns/') // ipns://Qm → /ipns/Qm // additional fixups of the final path path = fixupDnslinkPath(path) // /ipfs/example.com → /ipns/example.com - if (oldPath !== path && IsIpfs.path(path)) { + if (oldPath !== path && isIPFS.path(path)) { return { redirectUrl: pathAtHttpGateway(path, pubGwUrl) } } return null @@ -557,7 +543,7 @@ function normalizedRedirectingProtocolRequest (request, pubGwUrl) { function fixupDnslinkPath (path) { if (!(path && path.startsWith('/ipfs/'))) return path const [, root] = path.match(/^\/ipfs\/([^/?#]+)/) - if (root && !IsIpfs.cid(root) && isFQDN(root)) { + if (root && !isIPFS.cid(root) && isFQDN(root)) { return path.replace(/^\/ipfs\//, '/ipns/') } return path @@ -579,7 +565,7 @@ function unhandledIpfsPath (requestUrl) { if (unhandled && unhandled.length > 1) { const unhandledProtocol = decodeURIComponent(unhandled[1]) const unhandledPath = `/${decodeURIComponent(unhandled[2])}` - return IsIpfs.path(unhandledPath) ? unhandledPath : `/${unhandledProtocol}${unhandledPath}` + return isIPFS.path(unhandledPath) ? unhandledPath : `/${unhandledProtocol}${unhandledPath}` } return null } @@ -587,7 +573,7 @@ function unhandledIpfsPath (requestUrl) { function normalizedUnhandledIpfsProtocol (request, pubGwUrl) { let path = unhandledIpfsPath(request.url) path = fixupDnslinkPath(path) // /ipfs/example.com → /ipns/example.com - if (IsIpfs.path(path)) { + if (isIPFS.path(path)) { // replace search query with a request to a public gateway // (will be redirected later, if needed) return { redirectUrl: pathAtHttpGateway(path, pubGwUrl) } @@ -603,11 +589,17 @@ function findHeaderIndex (name, headers) { // Recovery check for onErrorOccurred (request.error) and onCompleted (request.statusCode) function isRecoverable (request, state, ipfsPathValidator) { - return state.recoverFailedHttpRequests && + // Note: we are unable to recover default public gateways without a local one + const { error, statusCode, url } = request + const { redirect, localGwAvailable, pubGwURL, pubSubdomainGwURL } = state + return (state.recoverFailedHttpRequests && request.type === 'main_frame' && - (recoverableNetworkErrors.has(request.error) || recoverableHttpError(request.statusCode)) && - (ipfsPathValidator.publicIpfsOrIpnsResource(request.url) || ipfsPathValidator.ipfsOrIpnsSubdomain(request.url)) && - !request.url.startsWith(state.pubGwURLString) && !request.url.includes(state.pubSubdomainGwURL.hostname) + (recoverableNetworkErrors.has(error) || + recoverableHttpError(statusCode)) && + ipfsPathValidator.publicIpfsOrIpnsResource(url) && + ((redirect && localGwAvailable) || + (!sameGateway(url, pubGwURL) && + !sameGateway(url, pubSubdomainGwURL)))) } // Recovery check for onErrorOccurred (request.error) @@ -631,8 +623,11 @@ function isRecoverableViaEthDNS (request, state) { // We can't redirect in onErrorOccurred/onCompleted // Indead, we recover by opening URL in a new tab that replaces the failed one // TODO: display an user-friendly prompt when the very first recovery is done -async function createTabWithURL (redirect, browser, recoveredTabs) { - const tabKey = redirect.redirectUrl +async function createTabWithURL (request, redirectUrl, browser, recoveredTabs) { + // Do nothing if the URL remains the same + if (request.url === redirectUrl) return + + const tabKey = redirectUrl // reuse existing tab, if exists // (this avoids duplicated tabs - https://github.com/ipfs-shipyard/ipfs-companion/issues/805) try { @@ -650,7 +645,7 @@ async function createTabWithURL (redirect, browser, recoveredTabs) { const newTab = await browser.tabs.create({ active: true, openerTabId, - url: redirect.redirectUrl + url: redirectUrl }) if (newTab) recoveredTabs.set(tabKey, newTab.id) } diff --git a/add-on/src/lib/options.js b/add-on/src/lib/options.js index dc8ee2b00..8e7be5c7f 100644 --- a/add-on/src/lib/options.js +++ b/add-on/src/lib/options.js @@ -13,6 +13,7 @@ exports.optionDefaults = Object.freeze({ publicGatewayUrl: 'https://ipfs.io', publicSubdomainGatewayUrl: 'https://dweb.link', useCustomGateway: true, + useSubdomainProxy: true, noIntegrationsHostnames: [], automaticMode: true, linkify: false, @@ -36,7 +37,7 @@ exports.optionDefaults = Object.freeze({ function buildCustomGatewayUrl () { // TODO: make more robust (sync with buildDefaultIpfsNodeConfig) const port = DEFAULT_TO_EMBEDDED_GATEWAY ? 9091 : 8080 - return `http://127.0.0.1:${port}` + return `http://localhost:${port}` } function buildIpfsApiUrl () { @@ -79,19 +80,31 @@ exports.storeMissingOptions = async (read, defaults, storage) => { return changes } -function normalizeGatewayURL (url) { +// safeURL produces URL object with optional normalizations +function safeURL (url, opts) { + opts = opts || { useLocalhostName: true } if (typeof url === 'string') { url = new URL(url) } - // https://github.com/ipfs/ipfs-companion/issues/328 - if (url.hostname.toLowerCase() === 'localhost') { + // "localhost" gateway normalization matters because: + // - 127.0.0.1 is a path gateway + // - localhost is a subdomain gateway + // https://github.com/ipfs-shipyard/ipfs-companion/issues/328#issuecomment-537383212 + if (opts.useLocalhostName && localhostIpUrl(url)) { + url.hostname = 'localhost' + } + if (!opts.useLocalhostName && localhostNameUrl(url)) { url.hostname = '127.0.0.1' } - // Return string without trailing slash - return url.toString().replace(/\/$/, '') + return url +} + +// Return string without trailing slash +function guiURLString (url, opts) { + return safeURL(url, opts).toString().replace(/\/$/, '') } -exports.normalizeGatewayURL = normalizeGatewayURL -exports.safeURL = (url) => new URL(normalizeGatewayURL(url)) +exports.safeURL = safeURL +exports.guiURLString = guiURLString // convert JS array to multiline textarea function hostArrayCleanup (array) { @@ -110,6 +123,19 @@ function hostTextToArray (text) { exports.hostArrayToText = hostArrayToText exports.hostTextToArray = hostTextToArray +function localhostIpUrl (url) { + if (typeof url === 'string') { + url = new URL(url) + } + return url.hostname === '127.0.0.1' || url.hostname === '[::1]' +} +function localhostNameUrl (url) { + if (typeof url === 'string') { + url = new URL(url) + } + return url.hostname.toLowerCase() === 'localhost' +} + exports.migrateOptions = async (storage) => { // <= v2.4.4 // DNSLINK: convert old on/off 'dnslink' flag to text-based 'dnslinkPolicy' @@ -139,4 +165,14 @@ exports.migrateOptions = async (storage) => { await storage.set({ noIntegrationsHostnames: noRedirectHostnames }) await storage.remove('noRedirectHostnames') } + // ~v2.11: subdomain proxy at *.ipfs.localhost + // migrate old default 127.0.0.1 to localhost hostname + const { customGatewayUrl: gwUrl } = await storage.get('customGatewayUrl') + if (gwUrl && (localhostIpUrl(gwUrl) || localhostNameUrl(gwUrl))) { + const { useSubdomainProxy } = await storage.get('useSubdomainProxy') + const newUrl = guiURLString(gwUrl, { useLocalhostName: useSubdomainProxy }) + if (gwUrl !== newUrl) { + await storage.set({ customGatewayUrl: newUrl }) + } + } } diff --git a/add-on/src/lib/state.js b/add-on/src/lib/state.js index 59d703305..48523a76b 100644 --- a/add-on/src/lib/state.js +++ b/add-on/src/lib/state.js @@ -22,15 +22,30 @@ function initState (options, overrides) { delete state.publicSubdomainGatewayUrl state.redirect = options.useCustomGateway delete state.useCustomGateway - state.apiURL = safeURL(options.ipfsApiUrl) + state.apiURL = safeURL(options.ipfsApiUrl, { useLocalhostName: false }) // go-ipfs returns 403 if IP is beautified to 'localhost' state.apiURLString = state.apiURL.toString() delete state.ipfsApiUrl - state.gwURL = safeURL(options.customGatewayUrl) + state.gwURL = safeURL(options.customGatewayUrl, { useLocalhostName: state.useSubdomainProxy }) state.gwURLString = state.gwURL.toString() delete state.customGatewayUrl state.dnslinkPolicy = String(options.dnslinkPolicy) === 'false' ? false : options.dnslinkPolicy state.webuiCid = webuiCid - state.webuiRootUrl = `${state.gwURLString}ipfs/${state.webuiCid}/` + + // TODO: unify the way webui is opened + // - https://github.com/ipfs-shipyard/ipfs-companion/pull/737 + // - https://github.com/ipfs-shipyard/ipfs-companion/pull/738 + // Context: previously, we loaded webui from gateway port + // (`${state.gwURLString}ipfs/${state.webuiCid}/`) because API port + // has hardcoded list of whitelisted webui versions. + // To enable API access from webui loaded from Gateway port Companion + // removed Origin header to avoid CORS, now we move away from that + // complexity and for now just load version whitelisted on API port. + // In the future, we want to load webui from $webuiCid.ipfs.localhost + // and whitelist API access from that specific hostname + // by appending it to API.HTTPHeaders.Access-Control-Allow-Origin list + // When that is possible, we can remove Origin manipulation (see PR #737 for PoC) + state.webuiRootUrl = `${state.apiURLString}webui/` + // attach helper functions state.activeIntegrations = (url) => { if (!state.active) return false @@ -41,6 +56,12 @@ function initState (options, overrides) { return false } } + // TODO state.connected ~= state.peerCount > 0 + // TODO state.nodeActive ~= API is online,eg. state.peerCount > offlinePeerCount + Object.defineProperty(state, 'localGwAvailable', { + // TODO: make quick fetch to confirm it works? + get: function () { return this.ipfsNodeType !== 'embedded' } + }) // apply optional overrides if (overrides) Object.assign(state, overrides) return state diff --git a/add-on/src/options/forms/api-form.js b/add-on/src/options/forms/api-form.js index 780ad2862..68c008e90 100644 --- a/add-on/src/options/forms/api-form.js +++ b/add-on/src/options/forms/api-form.js @@ -3,11 +3,11 @@ const browser = require('webextension-polyfill') const html = require('choo/html') -const { normalizeGatewayURL } = require('../../lib/options') +const { guiURLString } = require('../../lib/options') const switchToggle = require('../../pages/components/switch-toggle') function apiForm ({ ipfsApiUrl, ipfsApiPollMs, automaticMode, onOptionChange }) { - const onIpfsApiUrlChange = onOptionChange('ipfsApiUrl', normalizeGatewayURL) + const onIpfsApiUrlChange = onOptionChange('ipfsApiUrl', (url) => guiURLString(url, { useLocalhostName: false })) const onIpfsApiPollMsChange = onOptionChange('ipfsApiPollMs') const onAutomaticModeChange = onOptionChange('automaticMode') diff --git a/add-on/src/options/forms/gateways-form.js b/add-on/src/options/forms/gateways-form.js index 1d6133f94..dbeec8cb1 100644 --- a/add-on/src/options/forms/gateways-form.js +++ b/add-on/src/options/forms/gateways-form.js @@ -4,25 +4,28 @@ const browser = require('webextension-polyfill') const html = require('choo/html') const switchToggle = require('../../pages/components/switch-toggle') -const { normalizeGatewayURL, hostTextToArray, hostArrayToText } = require('../../lib/options') +const { guiURLString, hostTextToArray, hostArrayToText } = require('../../lib/options') // Warn about mixed content issues when changing the gateway +// to something other than HTTP or localhost // https://github.com/ipfs-shipyard/ipfs-companion/issues/648 -const secureContextUrl = /^https:\/\/|^http:\/\/127.0.0.1|^http:\/\/\[::1\]/ +const secureContextUrl = /^https:\/\/|^http:\/\/localhost|^http:\/\/127.0.0.1|^http:\/\/\[::1\]/ function gatewaysForm ({ ipfsNodeType, customGatewayUrl, useCustomGateway, + useSubdomainProxy, noIntegrationsHostnames, publicGatewayUrl, publicSubdomainGatewayUrl, onOptionChange }) { - const onCustomGatewayUrlChange = onOptionChange('customGatewayUrl', normalizeGatewayURL) + const onCustomGatewayUrlChange = onOptionChange('customGatewayUrl', (url) => guiURLString(url, { useLocalhostName: useSubdomainProxy })) const onUseCustomGatewayChange = onOptionChange('useCustomGateway') - const onPublicGatewayUrlChange = onOptionChange('publicGatewayUrl', normalizeGatewayURL) - const onPublicSubdomainGatewayUrlChange = onOptionChange('publicSubdomainGatewayUrl', normalizeGatewayURL) + const onUseSubdomainProxyChange = onOptionChange('useSubdomainProxy') + const onPublicGatewayUrlChange = onOptionChange('publicGatewayUrl', guiURLString) + const onPublicSubdomainGatewayUrlChange = onOptionChange('publicSubdomainGatewayUrl', guiURLString) const onNoIntegrationsHostnamesChange = onOptionChange('noIntegrationsHostnames', hostTextToArray) const mixedContentWarning = !secureContextUrl.test(customGatewayUrl) const supportRedirectToCustomGateway = ipfsNodeType !== 'embedded' @@ -108,6 +111,22 @@ function gatewaysForm ({
${switchToggle({ id: 'useCustomGateway', checked: useCustomGateway, onchange: onUseCustomGatewayChange })}
` : null} + ${supportRedirectToCustomGateway ? html` +
+ +
${switchToggle({ id: 'useSubdomainProxy', checked: useSubdomainProxy, onchange: onUseSubdomainProxyChange })}
+
+ ` : null} ${supportRedirectToCustomGateway ? html`
` : null} + ` diff --git a/add-on/src/options/page.js b/add-on/src/options/page.js index c616327f9..e3173fae0 100644 --- a/add-on/src/options/page.js +++ b/add-on/src/options/page.js @@ -67,6 +67,7 @@ module.exports = function optionsPage (state, emit) { ipfsNodeType: state.options.ipfsNodeType, customGatewayUrl: state.options.customGatewayUrl, useCustomGateway: state.options.useCustomGateway, + useSubdomainProxy: state.options.useSubdomainProxy, publicGatewayUrl: state.options.publicGatewayUrl, publicSubdomainGatewayUrl: state.options.publicSubdomainGatewayUrl, noIntegrationsHostnames: state.options.noIntegrationsHostnames, diff --git a/add-on/src/popup/browser-action/context-actions.js b/add-on/src/popup/browser-action/context-actions.js index 3af22fdad..4673d9e7d 100644 --- a/add-on/src/popup/browser-action/context-actions.js +++ b/add-on/src/popup/browser-action/context-actions.js @@ -5,6 +5,7 @@ const browser = require('webextension-polyfill') const html = require('choo/html') const navItem = require('./nav-item') const navHeader = require('./nav-header') +const { sameGateway } = require('../../lib/ipfs-path') const { contextMenuViewOnGateway, contextMenuCopyAddressAtPublicGw, @@ -38,11 +39,16 @@ function contextActions ({ }) { const activeCidResolver = active && isIpfsOnline && isApiAvailable const activePinControls = active && isIpfsOnline && isApiAvailable - const activeViewOnGateway = currentTab && !(currentTab.url.startsWith(pubGwURLString) || currentTab.url.startsWith(gwURLString)) + const activeViewOnGateway = (currentTab) => { + if (!currentTab) return false + const { url } = currentTab + return !(sameGateway(url, gwURLString) || sameGateway(url, pubGwURLString)) + } + const renderIpfsContextItems = () => { if (!isIpfsContext) return return html`
- ${activeViewOnGateway ? navItem({ + ${activeViewOnGateway(currentTab) ? navItem({ text: browser.i18n.getMessage(contextMenuViewOnGateway), onClick: () => onViewOnGateway(contextMenuViewOnGateway) }) : null} @@ -105,4 +111,5 @@ function activeTabActions (state) {
` } + module.exports.activeTabActions = activeTabActions diff --git a/package.json b/package.json index 2de9d4f60..f7c5bb621 100644 --- a/package.json +++ b/package.json @@ -83,8 +83,8 @@ "multiaddr": "6.1.0" }, "devDependencies": { - "@babel/core": "7.7.5", - "@babel/preset-env": "7.7.5", + "@babel/core": "7.9.0", + "@babel/preset-env": "7.9.0", "babel-loader": "8.0.6", "babel-plugin-syntax-async-generators": "6.13.0", "chai": "4.2.0", @@ -110,13 +110,13 @@ "sinon-chrome": "3.0.1", "standard": "14.3.1", "tar": "5.0.5", - "terser": "4.4.2", - "terser-webpack-plugin": "2.2.2", + "terser": "4.6.7", + "terser-webpack-plugin": "2.3.5", "transform-loader": "0.2.4", "web-ext": "4.1.0", - "webpack": "4.41.2", - "webpack-bundle-analyzer": "3.6.0", - "webpack-cli": "3.3.10", + "webpack": "4.42.0", + "webpack-bundle-analyzer": "3.6.1", + "webpack-cli": "3.3.11", "webpack-merge": "4.2.2" }, "dependencies": { @@ -140,7 +140,7 @@ "ipfs-postmsg-proxy": "3.1.1", "ipfsx": "0.17.0", "is-fqdn": "1.0.1", - "is-ipfs": "0.6.1", + "is-ipfs": "https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz", "is-svg": "4.2.0", "it-to-stream": "0.1.1", "lru-cache": "5.1.1", @@ -156,10 +156,10 @@ "pull-file-reader": "1.0.2", "readable-stream": "3.4.0", "tachyons": "4.11.1", - "tar-stream": "2.1.0", + "tar-stream": "2.1.2", "timers-browserify-full": "0.0.1", "uri-to-multiaddr": "3.0.1", - "webextension-polyfill": "0.5.0", + "webextension-polyfill": "0.6.0", "webrtc-ips": "0.1.4" }, "engines": { diff --git a/test/functional/lib/dnslink.test.js b/test/functional/lib/dnslink.test.js index 464fa4258..a06ebe19c 100644 --- a/test/functional/lib/dnslink.test.js +++ b/test/functional/lib/dnslink.test.js @@ -63,17 +63,17 @@ describe('dnslinkResolver (dnslinkPolicy=detectIpfsPathHeader)', function () { dnslinkPolicy: 'detectIpfsPathHeader', peerCount: 1 }) - const getExternalNodeState = () => Object.assign({}, getState(), { ipfsNodeType: 'external' }) - const getEmbeddedNodeState = () => Object.assign({}, getState(), { ipfsNodeType: 'embedded' }) + const getExternalNodeState = () => Object.assign(getState(), { ipfsNodeType: 'external' }) + const getEmbeddedNodeState = () => Object.assign(getState(), { ipfsNodeType: 'embedded' }) - describe('dnslinkRedirect(url)', function () { + describe('dnslinkAtGateway(url)', function () { ['/api/v0/foo', '/ipfs/foo', '/ipns/foo'].forEach(path => { it('should return nothing if dnslink is present in cache but path starts with ' + path, function () { const url = new URL('https://dnslinksite1.io' + path) const dnslinkResolver = createDnslinkResolver(getState) dnslinkResolver.setDnslink(url.hostname, '/ipfs/bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge') expectNoDnsTxtRecordLookup(url.hostname, dnslinkResolver) - expect(dnslinkResolver.dnslinkRedirect(url.toString())).to.equal(undefined) + expect(dnslinkResolver.dnslinkAtGateway(url.toString())).to.equal(undefined) }) }) it('[external node] should return redirect to custom gateway if dnslink is present in cache', function () { @@ -81,15 +81,17 @@ describe('dnslinkResolver (dnslinkPolicy=detectIpfsPathHeader)', function () { const dnslinkResolver = createDnslinkResolver(getExternalNodeState) dnslinkResolver.setDnslink(url.hostname, '/ipfs/bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge') expectNoDnsTxtRecordLookup(url.hostname, dnslinkResolver) - expect(dnslinkResolver.dnslinkRedirect(url.toString()).redirectUrl) - .to.equal('http://127.0.0.1:8080/ipns/dnslinksite4.io/foo/barl?a=b#c=d') + // note: locahost will redirect to subdomain if its go-ipfs >0.5, + // so companion does not need to handle that + expect(dnslinkResolver.dnslinkAtGateway(url.toString())) + .to.equal('http://localhost:8080/ipns/dnslinksite4.io/foo/barl?a=b#c=d') }) it('[embedded node] should return redirect to public gateway if dnslink is present in cache', function () { const url = new URL('https://dnslinksite4.io/foo/barl?a=b#c=d') const dnslinkResolver = createDnslinkResolver(getEmbeddedNodeState) dnslinkResolver.setDnslink(url.hostname, '/ipfs/bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge') expectNoDnsTxtRecordLookup(url.hostname, dnslinkResolver) - expect(dnslinkResolver.dnslinkRedirect(url.toString()).redirectUrl) + expect(dnslinkResolver.dnslinkAtGateway(url.toString())) .to.equal('https://gateway.foobar.io/ipns/dnslinksite4.io/foo/barl?a=b#c=d') }) it('[external node] should not return redirect to custom gateway if dnslink is not in cache and path does not belong to a gateway', function () { @@ -97,14 +99,14 @@ describe('dnslinkResolver (dnslinkPolicy=detectIpfsPathHeader)', function () { const dnslinkResolver = createDnslinkResolver(getExternalNodeState) dnslinkResolver.clearCache() expectNoDnsTxtRecordLookup(url.hostname, dnslinkResolver) - expect(dnslinkResolver.dnslinkRedirect(url.toString())).to.equal(undefined) + expect(dnslinkResolver.dnslinkAtGateway(url.toString())).to.equal(undefined) }) it('[embedded node] should not return redirect to public gateway if dnslink is not in cache and path does not belong to a gateway', function () { const url = new URL('https://dnslinksite4.io/foo/barl?a=b#c=d') const dnslinkResolver = createDnslinkResolver(getEmbeddedNodeState) dnslinkResolver.clearCache() expectNoDnsTxtRecordLookup(url.hostname, dnslinkResolver) - expect(dnslinkResolver.dnslinkRedirect(url.toString())).to.equal(undefined) + expect(dnslinkResolver.dnslinkAtGateway(url.toString())).to.equal(undefined) }) }) @@ -147,30 +149,32 @@ describe('dnslinkResolver (dnslinkPolicy=enabled)', function () { dnslinkPolicy: 'enabled', peerCount: 1 }) - const getExternalNodeState = () => Object.assign({}, getState(), { ipfsNodeType: 'external' }) - const getEmbeddedNodeState = () => Object.assign({}, getState(), { ipfsNodeType: 'embedded' }) + const getExternalNodeState = () => Object.assign(getState(), { ipfsNodeType: 'external' }) + const getEmbeddedNodeState = () => Object.assign(getState(), { ipfsNodeType: 'embedded' }) - describe('dnslinkRedirect(url)', function () { + describe('dnslinkAtGateway(url)', function () { ['/api/v0/foo', '/ipfs/foo', '/ipns/foo'].forEach(path => { it('should return nothing if DNS TXT record is present but path starts with ' + path, function () { const url = new URL('https://dnslinksite1.io' + path) const dnslinkResolver = createDnslinkResolver(getState) spoofDnsTxtRecord(url.hostname, dnslinkResolver, dnslinkValue) - expect(dnslinkResolver.dnslinkRedirect(url.toString())).to.equal(undefined) + expect(dnslinkResolver.dnslinkAtGateway(url.toString())).to.equal(undefined) }) }) it('[external node] should return redirect to custom gateway if DNS TXT record is present and path does not belong to a gateway', function () { const url = new URL('https://dnslinksite4.io/foo/barl?a=b#c=d') const dnslinkResolver = createDnslinkResolver(getExternalNodeState) spoofDnsTxtRecord(url.hostname, dnslinkResolver, dnslinkValue) - expect(dnslinkResolver.dnslinkRedirect(url.toString()).redirectUrl) - .to.equal('http://127.0.0.1:8080/ipns/dnslinksite4.io/foo/barl?a=b#c=d') + // note: locahost will redirect to subdomain if its go-ipfs >0.5, + // so companion does not need to handle that + expect(dnslinkResolver.dnslinkAtGateway(url.toString())) + .to.equal('http://localhost:8080/ipns/dnslinksite4.io/foo/barl?a=b#c=d') }) it('[embedded node] should return redirect to public gateway if DNS TXT record is present and path does not belong to a gateway', function () { const url = new URL('https://dnslinksite4.io/foo/barl?a=b#c=d') const dnslinkResolver = createDnslinkResolver(getEmbeddedNodeState) spoofDnsTxtRecord(url.hostname, dnslinkResolver, dnslinkValue) - expect(dnslinkResolver.dnslinkRedirect(url.toString()).redirectUrl) + expect(dnslinkResolver.dnslinkAtGateway(url.toString())) .to.equal('https://gateway.foobar.io/ipns/dnslinksite4.io/foo/barl?a=b#c=d') }) }) diff --git a/test/functional/lib/ipfs-path.test.js b/test/functional/lib/ipfs-path.test.js index 9aa1cc79a..8ddda691c 100644 --- a/test/functional/lib/ipfs-path.test.js +++ b/test/functional/lib/ipfs-path.test.js @@ -3,7 +3,7 @@ const { stub } = require('sinon') const { describe, it, beforeEach, afterEach } = require('mocha') const { expect } = require('chai') const { URL } = require('url') -const { normalizedIpfsPath, createIpfsPathValidator } = require('../../../add-on/src/lib/ipfs-path') +const { ipfsContentPath, createIpfsPathValidator } = require('../../../add-on/src/lib/ipfs-path') const { initState } = require('../../../add-on/src/lib/state') const createDnslinkResolver = require('../../../add-on/src/lib/dnslink') const { optionDefaults } = require('../../../add-on/src/lib/options') @@ -47,74 +47,79 @@ describe('ipfs-path.js', function () { if (ipfs.resolve.reset) ipfs.resolve.reset() }) - describe('normalizedIpfsPath', function () { + describe('ipfsContentPath', function () { it('should detect /ipfs/ path in URL from a public gateway', function () { const url = 'https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar' - expect(normalizedIpfsPath(url)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar') + expect(ipfsContentPath(url)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar') }) it('should detect /ipfs/ path in detached IPFS path', function () { const path = '/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar' - expect(normalizedIpfsPath(path)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar') + expect(ipfsContentPath(path)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar') }) it('should detect /ipns/ path in URL from a public gateway', function () { const url = 'https://ipfs.io/ipns/libp2p.io/bundles/' - expect(normalizedIpfsPath(url)).to.equal('/ipns/libp2p.io/bundles/') + expect(ipfsContentPath(url)).to.equal('/ipns/libp2p.io/bundles/') }) it('should detect /ipns/ path in detached IPFS path', function () { const path = '/ipns/libp2p.io/bundles/' - expect(normalizedIpfsPath(path)).to.equal('/ipns/libp2p.io/bundles/') + expect(ipfsContentPath(path)).to.equal('/ipns/libp2p.io/bundles/') }) - it('should preserve search and hash in URL from a public gateway', function () { + it('should drop search and hash from URL by default', function () { const url = 'https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' - expect(normalizedIpfsPath(url)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(ipfsContentPath(url)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR') }) - it('should preserve search and hash in detached IPFS path', function () { + it('should keep search and hash from URL if keepURIParams=true', function () { + const url = 'https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' + expect(ipfsContentPath(url, { keepURIParams: true })).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + }) + it('should drop search and hash in detached IPFS path by default', function () { + const path = '/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' + expect(ipfsContentPath(path)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR') + }) + it('should preserve search and hash in detached IPFS path if keepURIParams=true', function () { const path = '/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' - expect(normalizedIpfsPath(path)).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(ipfsContentPath(path, { keepURIParams: true })).to.equal('/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should decode special characters in URL', function () { const url = 'https://ipfs.io/ipfs/Qmb8wsGZNXt5VXZh1pEmYynjB6Euqpq3HYyeAdw2vScTkQ/1%20-%20Barrel%20-%20Part%201' - expect(normalizedIpfsPath(url)).to.equal('/ipfs/Qmb8wsGZNXt5VXZh1pEmYynjB6Euqpq3HYyeAdw2vScTkQ/1 - Barrel - Part 1') + expect(ipfsContentPath(url)).to.equal('/ipfs/Qmb8wsGZNXt5VXZh1pEmYynjB6Euqpq3HYyeAdw2vScTkQ/1 - Barrel - Part 1') }) it('should decode special characters in path', function () { const path = '/ipfs/Qmb8wsGZNXt5VXZh1pEmYynjB6Euqpq3HYyeAdw2vScTkQ/1%20-%20Barrel%20-%20Part%201' - expect(normalizedIpfsPath(path)).to.equal('/ipfs/Qmb8wsGZNXt5VXZh1pEmYynjB6Euqpq3HYyeAdw2vScTkQ/1 - Barrel - Part 1') + expect(ipfsContentPath(path)).to.equal('/ipfs/Qmb8wsGZNXt5VXZh1pEmYynjB6Euqpq3HYyeAdw2vScTkQ/1 - Barrel - Part 1') }) it('should resolve CID-in-subdomain URL to IPFS path', function () { const url = 'https://bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa.ipfs.dweb.link/wiki/Mars.html?argTest#hashTest' - expect(normalizedIpfsPath(url)).to.equal('/ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest') + expect(ipfsContentPath(url)).to.equal('/ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html') }) it('should return null if there is no valid path for input URL', function () { const url = 'https://foo.io/invalid/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' - expect(normalizedIpfsPath(url)).to.equal(null) + expect(ipfsContentPath(url)).to.equal(null) }) it('should return null if there is no valid path for input path', function () { const path = '/invalid/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR' - expect(normalizedIpfsPath(path)).to.equal(null) + expect(ipfsContentPath(path)).to.equal(null) }) }) - describe('validIpfsOrIpnsPath', function () { + describe('validIpfsOrIpns', function () { // this is just a smoke test, extensive tests are in is-ipfs package it('should return true for IPFS NURI', function () { const path = '/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' - expect(ipfsPathValidator.validIpfsOrIpnsPath(path)).to.equal(true) + expect(ipfsPathValidator.validIpfsOrIpns(path)).to.equal(true) }) it('should return false for non-IPFS NURI', function () { const path = '/ipfs/NotAValidCid' - expect(ipfsPathValidator.validIpfsOrIpnsPath(path)).to.equal(false) + expect(ipfsPathValidator.validIpfsOrIpns(path)).to.equal(false) }) - }) - - describe('validIpfsOrIpnsUrl', function () { // this is just a smoke test, extensive tests are in is-ipfs package it('should return true for URL at IPFS Gateway', function () { const url = 'https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest' - expect(ipfsPathValidator.validIpfsOrIpnsUrl(url)).to.equal(true) + expect(ipfsPathValidator.validIpfsOrIpns(url)).to.equal(true) }) it('should return false for non-IPFS URL', function () { const url = 'https://ipfs.io/ipfs/NotACid?argTest#hashTest' - expect(ipfsPathValidator.validIpfsOrIpnsUrl(url)).to.equal(false) + expect(ipfsPathValidator.validIpfsOrIpns(url)).to.equal(false) }) }) @@ -130,12 +135,12 @@ describe('ipfs-path.js', function () { it('should return false for IPFS URL at API port', function () { const url = `${state.apiURL}ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest` expect(ipfsPathValidator.publicIpfsOrIpnsResource(url)).to.equal(false) - expect(ipfsPathValidator.validIpfsOrIpnsUrl(url)).to.equal(true) + expect(ipfsPathValidator.validIpfsOrIpns(url)).to.equal(true) }) it('should return false for non-IPFS URL', function () { const url = 'https://ipfs.io/ipfs/NotACid?argTest#hashTest' expect(ipfsPathValidator.publicIpfsOrIpnsResource(url)).to.equal(false) - expect(ipfsPathValidator.validIpfsOrIpnsUrl(url)).to.equal(false) + expect(ipfsPathValidator.validIpfsOrIpns(url)).to.equal(false) }) describe('isIpfsPageActionsContext', function () { it('should return true for URL at Public IPFS Gateway', function () { @@ -149,12 +154,12 @@ describe('ipfs-path.js', function () { it('should return false for IPFS URL at API port', function () { const url = `${state.apiURL}ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest` expect(ipfsPathValidator.isIpfsPageActionsContext(url)).to.equal(false) - expect(ipfsPathValidator.validIpfsOrIpnsUrl(url)).to.equal(true) + expect(ipfsPathValidator.validIpfsOrIpns(url)).to.equal(true) }) it('should return false for non-IPFS URL', function () { const url = 'https://ipfs.io/ipfs/NotACid?argTest#hashTest' expect(ipfsPathValidator.publicIpfsOrIpnsResource(url)).to.equal(false) - expect(ipfsPathValidator.validIpfsOrIpnsUrl(url)).to.equal(false) + expect(ipfsPathValidator.validIpfsOrIpns(url)).to.equal(false) }) }) }) @@ -225,10 +230,6 @@ describe('ipfs-path.js', function () { const url = 'https://example.com/ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest' expect(ipfsPathValidator.resolveToPublicUrl(url)).to.equal(`${state.pubGwURL}ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest`) }) - it('should resolve URL with /ipfs/ path to the custom gateway if provided', function () { - const url = 'https://example.com/ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest' - expect(ipfsPathValidator.resolveToPublicUrl(url, 'https://example.com/')).to.equal('https://example.com/ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest') - }) it('should resolve /ipfs/ path to itself attached to the default public gateway', function () { const path = '/ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest' expect(ipfsPathValidator.resolveToPublicUrl(path)).to.equal(`${state.pubGwURL}ipfs/bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa/wiki/Mars.html?argTest#hashTest`) diff --git a/test/functional/lib/ipfs-request-gateway-recover.test.js b/test/functional/lib/ipfs-request-gateway-recover.test.js index fc5d1644f..5f680dd7a 100644 --- a/test/functional/lib/ipfs-request-gateway-recover.test.js +++ b/test/functional/lib/ipfs-request-gateway-recover.test.js @@ -61,11 +61,21 @@ describe('requestHandler.onCompleted:', function () { // HTTP-level errors await requestHandler.onCompleted(request) assert.ok(browser.tabs.create.notCalled, 'tabs.create should not be called') }) - it('should do nothing if broken request is a non-public IPFS request', async function () { + it('should do nothing if broken request is a local request to 127.0.0.1/ipfs', async function () { const request = urlRequestWithStatus('http://127.0.0.1:8080/ipfs/QmYzZgeWE7r8HXkH8zbb8J9ddHQvp8LTqm6isL791eo14h', 500) await requestHandler.onCompleted(request) assert.ok(browser.tabs.create.notCalled, 'tabs.create should not be called') }) + it('should do nothing if broken request is a local request to localhost/ipfs', async function () { + const request = urlRequestWithStatus('http://localhost:8080/ipfs/QmYzZgeWE7r8HXkH8zbb8J9ddHQvp8LTqm6isL791eo14h', 500) + await requestHandler.onCompleted(request) + assert.ok(browser.tabs.create.notCalled, 'tabs.create should not be called') + }) + it('should do nothing if broken request is a local request to *.ipfs.localhost', async function () { + const request = urlRequestWithStatus('http://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhw.ipfs.localhost:8080/', 500) + await requestHandler.onCompleted(request) + assert.ok(browser.tabs.create.notCalled, 'tabs.create should not be called') + }) it('should do nothing if broken request is to the default public gateway', async function () { const request = urlRequestWithStatus('https://ipfs.io/ipfs/QmYbZgeWE7y8HXkH8zbb8J9ddHQvp8LTqm6isL791eo14h', 500) await requestHandler.onCompleted(request) @@ -171,13 +181,14 @@ describe('requestHandler.onErrorOccurred:', function () { // network errors await requestHandler.onErrorOccurred(request) assert.ok(browser.tabs.create.withArgs({ url: 'https://ipfs.io/ipfs/QmYbZgeWE7y8HXkH8zbb8J9ddHQvp8LTqm6isL791eo14h', active: true, openerTabId: 20 }).calledOnce, 'tabs.create should be called with IPFS default public gateway URL') }) - it('should recover from unreachable HTTP server by reopening DNSLink on the public gateway', async function () { + it('should recover from unreachable HTTP server by reopening DNSLink on the active gateway', async function () { state.dnslinkPolicy = 'best-effort' dnslinkResolver.setDnslink('en.wikipedia-on-ipfs.org', '/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco') - const expectedUrl = 'http://127.0.0.1:8080/ipns/en.wikipedia-on-ipfs.org/' + // avoid DNS failures when recovering to local gateweay (if available) + const expectedUrl = 'http://localhost:8080/ipns/en.wikipedia-on-ipfs.org/' const request = urlRequestWithNetworkError('https://en.wikipedia-on-ipfs.org/') await requestHandler.onErrorOccurred(request) - assert.ok(browser.tabs.create.withArgs({ url: expectedUrl, active: true, openerTabId: 20 }).calledOnce, 'tabs.create should be called with ENS resource on local gateway URL') + assert.ok(browser.tabs.create.withArgs({ url: expectedUrl, active: true, openerTabId: 20 }).calledOnce, 'tabs.create should be called with DNSLink on local gateway URL') dnslinkResolver.clearCache() }) it('should recover from failed DNS for .eth opening it on EthDNS gateway at .eth.link', async function () { diff --git a/test/functional/lib/ipfs-request-gateway-redirect.test.js b/test/functional/lib/ipfs-request-gateway-redirect.test.js index 91916e1a7..0f31f47ad 100644 --- a/test/functional/lib/ipfs-request-gateway-redirect.test.js +++ b/test/functional/lib/ipfs-request-gateway-redirect.test.js @@ -41,10 +41,12 @@ describe('modifyRequest.onBeforeRequest:', function () { redirect: true, dnslinkPolicy: false, // dnslink testi suite is in ipfs-request-dnslink.test.js catchUnhandledProtocols: true, - gwURLString: 'http://127.0.0.1:8080', - gwURL: new URL('http://127.0.0.1:8080'), + gwURLString: 'http://localhost:8080', + gwURL: new URL('http://localhost:8080'), pubGwURLString: 'https://ipfs.io', - pubGwURL: new URL('https://ipfs.io') + pubGwURL: new URL('https://ipfs.io'), + pubSubdomainGwURLString: 'https://dweb.link', + pubSubdomainGwURL: new URL('https://dweb.link') }) const getState = () => state const getIpfs = () => {} @@ -61,7 +63,7 @@ describe('modifyRequest.onBeforeRequest:', function () { }) it('should be served from custom gateway if redirect is enabled', function () { const request = url2request('https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') - expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) }) describe('with embedded node', function () { @@ -117,22 +119,22 @@ describe('modifyRequest.onBeforeRequest:', function () { it('should be served from custom gateway if fetched from the same origin and redirect is enabled in Firefox', function () { runtime.isFirefox = true const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', originUrl: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if fetched from the same origin and redirect is enabled in Chromium', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if XHR is cross-origin and redirect is enabled in Chromium', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://www.nasa.gov/foo.html', requestId: fakeRequestId() } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if XHR is cross-origin and redirect is enabled in Firefox', function () { runtime.isFirefox = true const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', originUrl: 'https://www.nasa.gov/foo.html', requestId: fakeRequestId() } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) }) describe('with embedded node', function () { @@ -168,17 +170,17 @@ describe('modifyRequest.onBeforeRequest:', function () { it('should be served from custom gateway if fetched from the same origin and redirect is enabled in Firefox', function () { runtime.isFirefox = true const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', originUrl: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if fetched from the same origin and redirect is enabled in non-Firefox', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if XHR is cross-origin and redirect is enabled in non-Firefox', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://www.nasa.gov/foo.html', requestId: fakeRequestId() } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway via late redirect in onHeadersReceived if XHR is cross-origin and redirect is enabled in Firefox', function () { // Context for CORS XHR problems in Firefox: https://github.com/ipfs-shipyard/ipfs-companion/issues/436 @@ -187,7 +189,7 @@ describe('modifyRequest.onBeforeRequest:', function () { // onBeforeRequest should not change anything, as it will trigger false-positive CORS error expect(modifyRequest.onBeforeRequest(xhrRequest)).to.equal(undefined) // onHeadersReceived is after CORS validation happens, so its ok to cancel and redirect late - expect(modifyRequest.onHeadersReceived(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onHeadersReceived(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) }) }) @@ -204,12 +206,12 @@ describe('modifyRequest.onBeforeRequest:', function () { dnslinkResolver.readDnslinkFromTxtRecord = sinon.stub().withArgs(fqdn).returns('/ipfs/Qmazvovg6Sic3m9igZMKoAPjkiVZsvbWWc8ZvgjjK1qMss') // pretend API is online and we can do dns lookups with it state.peerCount = 1 - expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('http://127.0.0.1:8080/ipns/ipfs.git.sexy/index.html?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('http://localhost:8080/ipns/ipfs.git.sexy/index.html?argTest#hashTest') }) it('should be served from custom gateway if {path} starts with a valid PeerID', function () { const request = url2request('https://google.com/ipns/QmSWnBwMKZ28tcgMFdihD8XS7p6QzdRSGf71cCybaETSsU/index.html?argTest#hashTest') dnslinkResolver.readDnslinkFromTxtRecord = sinon.stub().returns(false) - expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('http://127.0.0.1:8080/ipns/QmSWnBwMKZ28tcgMFdihD8XS7p6QzdRSGf71cCybaETSsU/index.html?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('http://localhost:8080/ipns/QmSWnBwMKZ28tcgMFdihD8XS7p6QzdRSGf71cCybaETSsU/index.html?argTest#hashTest') }) }) @@ -253,6 +255,71 @@ describe('modifyRequest.onBeforeRequest:', function () { }) }) + describe('request to a public subdomain gateway (CID in subdomain)', function () { + const cid = 'bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge' + const peerid = 'bafzbeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge' + + describe('with external node', function () { + beforeEach(function () { + state.ipfsNodeType = 'external' + // dweb.link is the default subdomain gw + }) + it('should be redirected to localhost gateway (*.ipfs on default gw)', function () { + state.redirect = true + const request = url2request(`https://${cid}.ipfs.dweb.link/`) + + // X-Ipfs-Path to ensure value from URL takes a priority + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + + /// We expect redirect to path-based gateway because go-ipfs >=0.5 will + // return redirect to subdomain, and we don't want to break older + // versions + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://localhost:8080/ipfs/${cid}/`) + }) + it('should be redirected to localhost gateway (*.ipfs on 3rd party gw)', function () { + state.redirect = true + const request = url2request(`https://${cid}.ipfs.cf-ipfs.com/`) + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://localhost:8080/ipfs/${cid}/`) + }) + it('should be redirected to localhost gateway (*.ipns on default gw)', function () { + state.redirect = true + const request = url2request(`https://${peerid}.ipns.dweb.link/`) + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipns/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://localhost:8080/ipns/${peerid}/`) + }) + }) + + describe('with embedded node', function () { + beforeEach(function () { + state.ipfsNodeType = 'embedded' + // dweb.link is the default subdomain gw + }) + it('should be left untouched for *.ipfs at default public subdomain gw', function () { + state.redirect = true + const request = url2request(`https://${cid}.ipfs.dweb.link/`) + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + expectNoRedirect(modifyRequest, request) + }) + it('should be redirected to user-prefered public gateway if 3rd party subdomain gw', function () { + state.redirect = true + const request = url2request(`https://${cid}.ipfs.cf-ipfs.com/`) + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`https://${cid}.ipfs.dweb.link/`) + }) + it('should be left untouched for *.ipns at default public subdomain gw', function () { + state.redirect = true + const request = url2request(`https://${peerid}.ipns.dweb.link/`) + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipns/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + expectNoRedirect(modifyRequest, request) + }) + }) + }) + // tests in which results should be the same for all node types nodeTypes.forEach(function (nodeType) { beforeEach(function () { @@ -262,9 +329,9 @@ describe('modifyRequest.onBeforeRequest:', function () { describe(`with ${nodeType} node:`, function () { describe('request for IPFS path at a localhost', function () { // we do not touch local requests, as it may interfere with other nodes running at the same machine - // or could produce false-positives such as redirection from 127.0.0.1:5001/ipfs/path to 127.0.0.1:8080/ipfs/path - it('should be left untouched if 127.0.0.1 is used', function () { - const request = url2request('http://127.0.0.1:5001/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ/') + // or could produce false-positives such as redirection from localhost:5001/ipfs/path to localhost:8080/ipfs/path + it('should be left untouched if localhost is used', function () { + const request = url2request('http://localhost:5001/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ/') expectNoRedirect(modifyRequest, request) }) it('should be left untouched if localhost is used', function () { @@ -284,23 +351,6 @@ describe('modifyRequest.onBeforeRequest:', function () { expectNoRedirect(modifyRequest, request) }) }) - - describe('request to FQDN with valid CID in subdomain', function () { - // we do not touch such requests for now, as HTTP-based local node usually can't provide the same origin-based guarantees - // we will redirect subdomains to ipfs:// when native handler is available - it('should be left untouched for IPFS', function () { - state.redirect = true - const request = url2request('http://bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge.ipfs.dweb.link/') - request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] - expectNoRedirect(modifyRequest, request) - }) - it('should be left untouched for IPNS', function () { - state.redirect = true - const request = url2request('http://bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge.ipns.dweb.link/') - request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] - expectNoRedirect(modifyRequest, request) - }) - }) }) }) diff --git a/yarn.lock b/yarn.lock index c2453911e..bdfdbde64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,28 +9,39 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/code-frame@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== +"@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== dependencies: - "@babel/highlight" "^7.0.0" + "@babel/highlight" "^7.8.3" + +"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" + integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== + dependencies: + browserslist "^4.9.1" + invariant "^2.2.4" + semver "^5.5.0" -"@babel/core@7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.5.tgz#ae1323cd035b5160293307f50647e83f8ba62f7e" - integrity sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.4" - "@babel/helpers" "^7.7.4" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" +"@babel/core@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" + integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.0" + "@babel/parser" "^7.9.0" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" convert-source-map "^1.7.0" debug "^4.1.0" - json5 "^2.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" lodash "^4.17.13" resolve "^1.3.2" semver "^5.4.1" @@ -47,64 +58,67 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" - integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg== +"@babel/generator@^7.9.0": + version "7.9.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.3.tgz#7c8b2956c6f68b3ab732bd16305916fbba521d94" + integrity sha512-RpxM252EYsz9qLUIq6F7YJyK1sv0wWDBFuztfDGWaQKzHjqDHysxSiRUpA/X9jmfqo+WzkAVKFaUily5h+gDCQ== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.9.0" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" - integrity sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og== +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz#5f73f2b28580e224b5b9bd03146a4015d6217f5f" - integrity sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-call-delegate@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz#621b83e596722b50c0066f9dc37d3232e461b801" - integrity sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA== +"@babel/helper-compilation-targets@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" + integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== dependencies: - "@babel/helper-hoist-variables" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/compat-data" "^7.8.6" + browserslist "^4.9.1" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" -"@babel/helper-create-regexp-features-plugin@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz#6d5762359fd34f4da1500e4cff9955b5299aaf59" - integrity sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A== +"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== dependencies: - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.6.0" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.7.0" -"@babel/helper-define-map@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz#2841bf92eb8bd9c906851546fe6b9d45e162f176" - integrity sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg== +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" lodash "^4.17.13" -"@babel/helper-explode-assignable-expression@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz#fa700878e008d85dc51ba43e9fb835cddfe05c84" - integrity sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg== +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== dependencies: - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-function-name@^7.1.0": version "7.1.0" @@ -115,14 +129,14 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-function-name@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" - integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ== +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== dependencies: - "@babel/helper-get-function-arity" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" @@ -131,105 +145,99 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-get-function-arity@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" - integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA== +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-hoist-variables@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz#612384e3d823fdfaaf9fce31550fe5d4db0f3d12" - integrity sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ== +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-member-expression-to-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz#356438e2569df7321a8326644d4b790d2122cb74" - integrity sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw== +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-module-imports@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" - integrity sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ== +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-module-transforms@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz#8d7cdb1e1f8ea3d8c38b067345924ac4f8e0879a" - integrity sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA== +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-simple-access" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" lodash "^4.17.13" -"@babel/helper-module-transforms@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz#d044da7ffd91ec967db25cd6748f704b6b244835" - integrity sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw== +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-simple-access" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz#034af31370d2995242aa4df402c3b7794b2dcdf2" - integrity sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg== - dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== -"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" - integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== +"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== dependencies: - lodash "^4.17.11" + lodash "^4.17.13" -"@babel/helper-remap-async-to-generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz#c68c2407350d9af0e061ed6726afb4fff16d0234" - integrity sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw== +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-wrap-function" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-replace-supers@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz#3c881a6a6a7571275a72d82e6107126ec9e2cdd2" - integrity sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg== +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.7.4" - "@babel/helper-optimise-call-expression" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" -"@babel/helper-simple-access@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz#a169a0adb1b5f418cfc19f22586b2ebf58a9a294" - integrity sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A== +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== dependencies: - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-split-export-declaration@^7.4.4": version "7.4.4" @@ -238,31 +246,36 @@ dependencies: "@babel/types" "^7.4.4" -"@babel/helper-split-export-declaration@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" - integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug== +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" + +"@babel/helper-validator-identifier@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" + integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== -"@babel/helper-wrap-function@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" - integrity sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg== +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helpers@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" - integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg== +"@babel/helpers@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" + integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== dependencies: - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" "@babel/highlight@^7.0.0": version "7.5.0" @@ -273,355 +286,404 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.8.3": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" + integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== -"@babel/parser@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" - integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== +"@babel/parser@^7.8.6", "@babel/parser@^7.9.0": + version "7.9.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.3.tgz#043a5fc2ad8b7ea9facddc4e802a1f0f25da7255" + integrity sha512-E6SpIDJZ0cZAKoCNk+qSDd0ChfTnpiJN9FfNf3RZ20dzwA2vL2oq5IX1XTVT+4vDmRlta2nGk5HGMMskJAR+4A== -"@babel/parser@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71" - integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig== +"@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-async-generator-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" - integrity sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw== +"@babel/plugin-proposal-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" - "@babel/plugin-syntax-async-generators" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-dynamic-import@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz#dde64a7f127691758cbfed6cf70de0fa5879d52d" - integrity sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ== +"@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/plugin-proposal-json-strings@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz#7700a6bfda771d8dc81973249eac416c6b4c697d" - integrity sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@babel/plugin-proposal-object-rest-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz#cc57849894a5c774214178c8ab64f6334ec8af71" - integrity sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ== +"@babel/plugin-proposal-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" + integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" -"@babel/plugin-proposal-optional-catch-binding@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz#ec21e8aeb09ec6711bc0a39ca49520abee1de379" - integrity sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w== +"@babel/plugin-proposal-object-rest-spread@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" + integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" -"@babel/plugin-proposal-unicode-property-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz#7c239ccaf09470dbe1d453d50057460e84517ebb" - integrity sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA== +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-syntax-async-generators@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" - integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== +"@babel/plugin-proposal-optional-chaining@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" + integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-syntax-dynamic-import@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" - integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== +"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.8" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-json-strings@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" - integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-object-rest-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" - integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" - integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz#bd7d8fa7b9fee793a36e4027fd6dd1aa32f946da" - integrity sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg== +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-arrow-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" - integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== +"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" + integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-async-to-generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz#694cbeae6d613a34ef0292713fa42fb45c4470ba" - integrity sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg== +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-block-scoped-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" - integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-block-scoping@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" - integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.13" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-classes@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" - integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-define-map" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-optimise-call-expression" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" + integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" - integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== +"@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-destructuring@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" - integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== +"@babel/plugin-transform-destructuring@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" + integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-dotall-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz#f7ccda61118c5b7a2599a72d5e3210884a021e96" - integrity sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw== +"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-duplicate-keys@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz#3d21731a42e3f598a73835299dd0169c3b90ac91" - integrity sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA== +"@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz#dd30c0191e3a1ba19bcc7e389bdfddc0729d5db9" - integrity sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ== +"@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-for-of@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" - integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== +"@babel/plugin-transform-for-of@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" + integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-function-name@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" - integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== +"@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" - integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== +"@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-member-expression-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" - integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== +"@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-modules-amd@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz#39e0fb717224b59475b306402bb8eedab01e729c" - integrity sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ== +"@babel/plugin-transform-modules-amd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" + integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== dependencies: - "@babel/helper-module-transforms" "^7.7.5" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-commonjs@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz#1d27f5eb0bcf7543e774950e5b2fa782e637b345" - integrity sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q== +"@babel/plugin-transform-modules-commonjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" + integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== dependencies: - "@babel/helper-module-transforms" "^7.7.5" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.7.4" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-systemjs@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz#cd98152339d3e763dfe838b7d4273edaf520bb30" - integrity sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw== +"@babel/plugin-transform-modules-systemjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" + integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== dependencies: - "@babel/helper-hoist-variables" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-umd@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz#1027c355a118de0aae9fee00ad7813c584d9061f" - integrity sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw== +"@babel/plugin-transform-modules-umd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" + integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== dependencies: - "@babel/helper-module-transforms" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz#fb3bcc4ee4198e7385805007373d6b6f42c98220" - integrity sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" -"@babel/plugin-transform-new-target@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz#4a0753d2d60639437be07b592a9e58ee00720167" - integrity sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg== +"@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-object-super@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" - integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== +"@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz#da4555c97f39b51ac089d31c7380f03bca4075ce" - integrity sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw== +"@babel/plugin-transform-parameters@^7.8.7": + version "7.9.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a" + integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg== dependencies: - "@babel/helper-call-delegate" "^7.7.4" - "@babel/helper-get-function-arity" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-property-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" - integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== +"@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz#3a8757ee1a2780f390e89f246065ecf59c26fce9" - integrity sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw== +"@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== dependencies: - regenerator-transform "^0.14.0" + regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz#6a7cf123ad175bb5c69aec8f6f0770387ed3f1eb" - integrity sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ== +"@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-shorthand-properties@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" - integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== +"@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" - integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== +"@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-sticky-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz#ffb68c05090c30732076b1285dc1401b404a123c" - integrity sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A== +"@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" -"@babel/plugin-transform-template-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" - integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== +"@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-typeof-symbol@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz#3174626214f2d6de322882e498a38e8371b2140e" - integrity sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg== +"@babel/plugin-transform-typeof-symbol@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-unicode-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz#a3c0f65b117c4c81c5b6484f2a5e7b95346b83ae" - integrity sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw== +"@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" "@babel/polyfill@7.7.0": version "7.7.0" @@ -631,63 +693,83 @@ core-js "^2.6.5" regenerator-runtime "^0.13.2" -"@babel/preset-env@7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.5.tgz#f28573ed493edb4ba763b37fb4fbb85601469370" - integrity sha512-wDPbiaZdGzsJuTWlpLHJxmwslwHGLZ8F5v69zX3oAWeTOFWdy4OJHoTKg26oAnFg052v+/LAPY5os9KB0LrOEA== - dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.7.4" - "@babel/plugin-proposal-dynamic-import" "^7.7.4" - "@babel/plugin-proposal-json-strings" "^7.7.4" - "@babel/plugin-proposal-object-rest-spread" "^7.7.4" - "@babel/plugin-proposal-optional-catch-binding" "^7.7.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.7.4" - "@babel/plugin-syntax-async-generators" "^7.7.4" - "@babel/plugin-syntax-dynamic-import" "^7.7.4" - "@babel/plugin-syntax-json-strings" "^7.7.4" - "@babel/plugin-syntax-object-rest-spread" "^7.7.4" - "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" - "@babel/plugin-syntax-top-level-await" "^7.7.4" - "@babel/plugin-transform-arrow-functions" "^7.7.4" - "@babel/plugin-transform-async-to-generator" "^7.7.4" - "@babel/plugin-transform-block-scoped-functions" "^7.7.4" - "@babel/plugin-transform-block-scoping" "^7.7.4" - "@babel/plugin-transform-classes" "^7.7.4" - "@babel/plugin-transform-computed-properties" "^7.7.4" - "@babel/plugin-transform-destructuring" "^7.7.4" - "@babel/plugin-transform-dotall-regex" "^7.7.4" - "@babel/plugin-transform-duplicate-keys" "^7.7.4" - "@babel/plugin-transform-exponentiation-operator" "^7.7.4" - "@babel/plugin-transform-for-of" "^7.7.4" - "@babel/plugin-transform-function-name" "^7.7.4" - "@babel/plugin-transform-literals" "^7.7.4" - "@babel/plugin-transform-member-expression-literals" "^7.7.4" - "@babel/plugin-transform-modules-amd" "^7.7.5" - "@babel/plugin-transform-modules-commonjs" "^7.7.5" - "@babel/plugin-transform-modules-systemjs" "^7.7.4" - "@babel/plugin-transform-modules-umd" "^7.7.4" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.4" - "@babel/plugin-transform-new-target" "^7.7.4" - "@babel/plugin-transform-object-super" "^7.7.4" - "@babel/plugin-transform-parameters" "^7.7.4" - "@babel/plugin-transform-property-literals" "^7.7.4" - "@babel/plugin-transform-regenerator" "^7.7.5" - "@babel/plugin-transform-reserved-words" "^7.7.4" - "@babel/plugin-transform-shorthand-properties" "^7.7.4" - "@babel/plugin-transform-spread" "^7.7.4" - "@babel/plugin-transform-sticky-regex" "^7.7.4" - "@babel/plugin-transform-template-literals" "^7.7.4" - "@babel/plugin-transform-typeof-symbol" "^7.7.4" - "@babel/plugin-transform-unicode-regex" "^7.7.4" - "@babel/types" "^7.7.4" - browserslist "^4.6.0" - core-js-compat "^3.4.7" +"@babel/preset-env@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" + integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== + dependencies: + "@babel/compat-data" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.0" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.8.3" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-modules-commonjs" "^7.9.0" + "@babel/plugin-transform-modules-systemjs" "^7.9.0" + "@babel/plugin-transform-modules-umd" "^7.9.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.8.7" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.0" + browserslist "^4.9.1" + core-js-compat "^3.6.2" invariant "^2.2.2" - js-levenshtein "^1.1.3" + levenary "^1.1.1" semver "^5.5.0" +"@babel/preset-modules@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" + integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + "@babel/runtime-corejs2@^7.2.0": version "7.5.4" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.5.4.tgz#7111dbb344acce1f7dd601786cff40d516b27a96" @@ -703,6 +785,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.8.4": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.1.0", "@babel/template@^7.4.0": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" @@ -712,14 +801,14 @@ "@babel/parser" "^7.4.4" "@babel/types" "^7.4.4" -"@babel/template@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" - integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== +"@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" "@babel/traverse@^7.4.3": version "7.5.0" @@ -736,17 +825,17 @@ globals "^11.1.0" lodash "^4.17.11" -"@babel/traverse@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" - integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/parser" "^7.7.4" - "@babel/types" "^7.7.4" +"@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" + integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.9.0" + "@babel/types" "^7.9.0" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" @@ -760,12 +849,12 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" -"@babel/types@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" - integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== +"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" + integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== dependencies: - esutils "^2.0.2" + "@babel/helper-validator-identifier" "^7.9.0" lodash "^4.17.13" to-fast-properties "^2.0.0" @@ -1540,6 +1629,11 @@ acorn-walk@^6.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== +acorn-walk@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" + integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== + acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" @@ -1565,7 +1659,7 @@ acorn@^7.0.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== -acorn@^7.1.0: +acorn@^7.1.0, acorn@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== @@ -1706,6 +1800,16 @@ ajv@^6.1.0, ajv@^6.5.5, ajv@^6.9.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" + integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== + 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" + ansi-align@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" @@ -2199,6 +2303,13 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base-x@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" + integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA== + dependencies: + safe-buffer "^5.0.1" + base32-encode@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/base32-encode/-/base32-encode-1.1.1.tgz#d022d86aca0002a751bbe1bf20eb4a9b1cef4e95" @@ -2379,6 +2490,15 @@ bl@^4.0.0: dependencies: readable-stream "^3.4.0" +bl@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.2.tgz#52b71e9088515d0606d9dd9cc7aa48dc1f98e73a" + integrity sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + blakejs@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" @@ -2587,23 +2707,15 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.6.0: - version "4.6.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.4.tgz#fd0638b3f8867fec2c604ed0ed9300379f8ec7c2" - integrity sha512-ErJT8qGfRt/VWHSr1HeqZzz50DvxHtr1fVL1m5wf20aGrG8e1ce8fpZ2EjZEfs09DDZYSvtRaDlMpWslBf8Low== - dependencies: - caniuse-lite "^1.0.30000981" - electron-to-chromium "^1.3.188" - node-releases "^1.1.25" - -browserslist@^4.8.0: - version "4.8.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289" - integrity sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA== +browserslist@^4.8.3, browserslist@^4.9.1: + version "4.11.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.0.tgz#aef4357b10a8abda00f97aac7cd587b2082ba1ad" + integrity sha512-WqEC7Yr5wUH5sg6ruR++v2SGOQYpyUdYYd4tZoAq1F7y+QXoLoYGXVbxhtaIqWmAJjtNTRjVD3HuJc1OXTel2A== dependencies: - caniuse-lite "^1.0.30001015" - electron-to-chromium "^1.3.322" - node-releases "^1.1.42" + caniuse-lite "^1.0.30001035" + electron-to-chromium "^1.3.380" + node-releases "^1.1.52" + pkg-up "^3.1.0" bs58@4.0.1, bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" @@ -2719,6 +2831,14 @@ buffer@^5.4.3: base64-js "^1.0.2" ieee754 "^1.1.4" +buffer@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.5.0.tgz#9c3caa3d623c33dd1c7ef584b89b88bf9c9bc1ce" + integrity sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + buffers@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" @@ -2923,15 +3043,10 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -caniuse-lite@^1.0.30000981: - version "1.0.30000983" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000983.tgz#ab3c70061ca2a3467182a10ac75109b199b647f8" - integrity sha512-/llD1bZ6qwNkt41AsvjsmwNOoA4ZB+8iqmf5LVyeSXuBODT/hAMFNVOh84NdUzoiYiSKqo5vQ3ZzeYHSi/olDQ== - -caniuse-lite@^1.0.30001015: - version "1.0.30001015" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz#15a7ddf66aba786a71d99626bc8f2b91c6f0f5f0" - integrity sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ== +caniuse-lite@^1.0.30001035: + version "1.0.30001035" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001035.tgz#2bb53b8aa4716b2ed08e088d4dc816a5fe089a1e" + integrity sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ== caseless@~0.12.0: version "0.12.0" @@ -3540,13 +3655,13 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.4.7: - version "3.4.7" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.4.7.tgz#39f8080b1d92a524d6d90505c42b9c5c1eb90611" - integrity sha512-57+mgz/P/xsGdjwQYkwtBZR3LuISaxD1dEwVDtbk8xJMqAmwqaxLOvnNT7kdJ7jYE/NjNptyzXi+IQFMi/2fCw== +core-js-compat@^3.6.2: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" + integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== dependencies: - browserslist "^4.8.0" - semver "^6.3.0" + browserslist "^4.8.3" + semver "7.0.0" core-js@3.6.4: version "3.6.4" @@ -4372,15 +4487,10 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.2.tgz#3a32c63d1cd16d11266cd4703b14fec4e74ab4f6" integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q== -electron-to-chromium@^1.3.188: - version "1.3.190" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.190.tgz#5bf599519983bfffd9d4387817039a3ed7ca085f" - integrity sha512-cs9WnTnGBGnYYVFMCtLmr9jXNTOkdp95RLz5VhwzDn7dErg1Lnt9o4d01gEH69XlmRKWUr91Yu1hA+Hi8qW0PA== - -electron-to-chromium@^1.3.322: - version "1.3.322" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8" - integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA== +electron-to-chromium@^1.3.380: + version "1.3.380" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.380.tgz#1e1f07091b42b54bccd0ad6d3a14f2b73b60dc9d" + integrity sha512-2jhQxJKcjcSpVOQm0NAfuLq8o+130blrcawoumdXT6411xG/xIAOyZodO/y7WTaYlz/NHe3sCCAe/cJLnDsqTw== elegant-spinner@^1.0.1: version "1.0.1" @@ -5286,6 +5396,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + fast-fifo@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.0.0.tgz#9bc72e6860347bb045a876d1c5c0af11e9b984e7" @@ -5473,13 +5588,13 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-cache-dir@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.1.0.tgz#9935894999debef4cf9f677fdf646d002c4cdecb" - integrity sha512-zw+EFiNBNPgI2NTrKkDd1xd7q0cs6wr/iWnr/oUkI0yF9K9GqQ+riIt4aiyFaaqpaWbxPrJXHI+QvmNUQbX+0Q== +find-cache-dir@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== dependencies: commondir "^1.0.1" - make-dir "^3.0.0" + make-dir "^3.0.2" pkg-dir "^4.1.0" find-root@^1.0.0: @@ -5896,6 +6011,11 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + get-browser-rtc@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9" @@ -6692,7 +6812,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6807,7 +6927,7 @@ into-stream@^5.1.1: from2 "^2.3.0" p-is-promise "^3.0.0" -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -7811,16 +7931,15 @@ is-ip@^3.1.0: dependencies: ip-regex "^4.0.0" -is-ipfs@0.6.1, is-ipfs@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-0.6.1.tgz#c85069c73275dc6a60673c791a9be731e2b4bfc4" - integrity sha512-WhqQylam6pODS2RyqT/u0PR5KWtBZNCgPjgargFOVQjzw/3+6d0midXenzU65klM4LH13IUiCC6ObhDUdXZ7Nw== +"is-ipfs@https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz": + version "0.6.3" + resolved "https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz#733850d100cb80d08d251706d4b91ab14b58bd56" dependencies: bs58 "^4.0.1" cids "~0.7.0" - mafmt "^6.0.7" - multiaddr "^6.0.4" - multibase "~0.6.0" + mafmt "^7.0.0" + multiaddr "^7.2.1" + multibase "~0.7.0" multihashes "~0.4.13" is-ipfs@~0.4.2: @@ -7833,6 +7952,18 @@ is-ipfs@~0.4.2: multibase "~0.6.0" multihashes "~0.4.13" +is-ipfs@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-0.6.1.tgz#c85069c73275dc6a60673c791a9be731e2b4bfc4" + integrity sha512-WhqQylam6pODS2RyqT/u0PR5KWtBZNCgPjgargFOVQjzw/3+6d0midXenzU65klM4LH13IUiCC6ObhDUdXZ7Nw== + dependencies: + bs58 "^4.0.1" + cids "~0.7.0" + mafmt "^6.0.7" + multiaddr "^6.0.4" + multibase "~0.6.0" + multihashes "~0.4.13" + is-mergeable-object@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz#faaa3ed1cfce87d6f7d2f5885e92cc30af3e2ebf" @@ -8222,13 +8353,13 @@ jed@1.1.1: resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4" integrity sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ= -jest-worker@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== +jest-worker@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.1.0.tgz#75d038bad6fdf58eba0d2ec1835856c497e3907a" + integrity sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg== dependencies: merge-stream "^2.0.0" - supports-color "^6.1.0" + supports-color "^7.0.0" jetpack-id@1.0.0: version "1.0.0" @@ -8245,11 +8376,6 @@ joi-browser@^13.4.0: resolved "https://registry.yarnpkg.com/joi-browser/-/joi-browser-13.4.0.tgz#b72ba61b610e3f58e51b563a14e0f5225cfb6896" integrity sha512-TfzJd2JaJ/lg/gU+q5j9rLAjnfUNF9DUmXTP9w+GfmG79LjFOXFeM7hIFuXCBcZCivUDFwd9l1btTV9rhHumtQ== -js-levenshtein@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" - integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== - js-select@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/js-select/-/js-select-0.6.0.tgz#c284e22824d5927aec962dcdf247174aefb0d190" @@ -8364,12 +8490,12 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== +json5@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" + integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== dependencies: - minimist "^1.2.0" + minimist "^1.2.5" json@9.0.6: version "9.0.6" @@ -8807,6 +8933,18 @@ leven@2.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -9608,6 +9746,13 @@ mafmt@^6.0.10: dependencies: multiaddr "^6.1.0" +mafmt@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/mafmt/-/mafmt-7.1.0.tgz#4126f6d0eded070ace7dbbb6fb04977412d380b5" + integrity sha512-vpeo9S+hepT3k2h5iFxzEHvvR0GPBx9uKaErmnRzYNcaKb03DgOArjEMlgG4a9LcuZZ89a3I8xbeto487n26eA== + dependencies: + multiaddr "^7.3.0" + magic-string@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.23.2.tgz#204d7c3ea36c7d940209fcc54c39b9f243f13369" @@ -9637,6 +9782,13 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-dir@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" + integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== + dependencies: + semver "^6.0.0" + mamacro@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" @@ -9988,6 +10140,11 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" @@ -10207,7 +10364,7 @@ multiaddr-to-uri@^4.0.1: dependencies: multiaddr "^6.0.3" -multiaddr@6.1.0, multiaddr@^4.0.0, multiaddr@^5.0.0, multiaddr@^6.0.3, multiaddr@^6.0.4, multiaddr@^6.0.6, multiaddr@^6.1.0, multiaddr@^6.1.1: +multiaddr@6.1.0, multiaddr@^4.0.0, multiaddr@^5.0.0, multiaddr@^6.0.3, multiaddr@^6.0.4, multiaddr@^6.0.6, multiaddr@^6.1.0, multiaddr@^6.1.1, multiaddr@^7.2.1, multiaddr@^7.3.0: version "6.1.0" resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-6.1.0.tgz#1f93afce58a33db5cc32a5917d8a14105d94330e" integrity sha512-+XTP3OzG2m6JVcjxA9QBmGDr0Vk8WwnohC/fCC3puXb5qJqfJwLVJLEtdTc6vK7ri/hw+Nn4wyT4LkZaPnvGfQ== @@ -10239,6 +10396,14 @@ multibase@~0.6.0: dependencies: base-x "3.0.4" +multibase@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + multicast-dns@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.0.tgz#7aa49a7efba931a346011aa02e7d1c314a65ac77" @@ -10748,17 +10913,10 @@ node-pre-gyp@^0.13.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.25: - version "1.1.25" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" - integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ== - dependencies: - semver "^5.3.0" - -node-releases@^1.1.42: - version "1.1.42" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.42.tgz#a999f6a62f8746981f6da90627a8d2fc090bbad7" - integrity sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA== +node-releases@^1.1.52: + version "1.1.52" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" + integrity sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ== dependencies: semver "^6.3.0" @@ -11256,6 +11414,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -11811,6 +11976,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -11879,7 +12051,7 @@ priorityqueue@~0.2.1: resolved "https://registry.yarnpkg.com/priorityqueue/-/priorityqueue-0.2.1.tgz#f57e623f20237f30c142d4cb45fafed9e7d51403" integrity sha512-Dr6ZkRFGZHoAri6iNp5KvspOrFPfhxJ5AExXqLy5ChgdwALd3nC+q5/QG+gmjmf9W63joDXc+Zp0h05Ug/RtYg== -private@^0.1.6: +private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -12550,10 +12722,10 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" -regenerate-unicode-properties@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" - integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== dependencies: regenerate "^1.4.0" @@ -12572,12 +12744,18 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== -regenerator-transform@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf" - integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + +regenerator-transform@^0.14.2: + version "0.14.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" + integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== dependencies: - private "^0.1.6" + "@babel/runtime" "^7.8.4" + private "^0.1.8" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" @@ -12597,17 +12775,17 @@ regexpp@^3.0.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== -regexpu-core@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" - integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== dependencies: regenerate "^1.4.0" - regenerate-unicode-properties "^8.1.0" - regjsgen "^0.5.0" - regjsparser "^0.6.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.1.0" + unicode-match-property-value-ecmascript "^1.2.0" registry-auth-token@^3.4.0: version "3.4.0" @@ -12624,15 +12802,15 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" -regjsgen@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" - integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== +regjsgen@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== -regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== dependencies: jsesc "~0.5.0" @@ -12983,12 +13161,12 @@ schema-utils@^2.5.0: ajv "^6.10.2" ajv-keywords "^3.4.1" -schema-utils@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f" - integrity sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg== +schema-utils@^2.6.4: + version "2.6.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a" + integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ== dependencies: - ajv "^6.10.2" + ajv "^6.12.0" ajv-keywords "^3.4.1" scroll-to-anchor@^1.0.0: @@ -13046,6 +13224,11 @@ semver-diff@^3.1.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + semver@7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.1.tgz#29104598a197d6cbe4733eeecbe968f7b43a9667" @@ -13085,15 +13268,10 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-javascript@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" - integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== - -serialize-javascript@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.1.tgz#952907a04a3e3a75af7f73d92d15e233862048b2" - integrity sha512-MPLPRpD4FNqWq9tTIjYG5LesFouDhdyH0EPY3gVK4DRD5+g4aDqdNSzLIwceulo3Yj+PL1bPh6laE5+H6LTcrQ== +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== serve-static@1.14.1: version "1.14.1" @@ -14042,7 +14220,7 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== @@ -14086,12 +14264,12 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar-stream@2.1.0, tar-stream@^2.0.0, tar-stream@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3" - integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw== +tar-stream@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.2.tgz#6d5ef1a7e5783a95ff70b69b97455a5968dc1325" + integrity sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q== dependencies: - bl "^3.0.0" + bl "^4.0.1" end-of-stream "^1.4.1" fs-constants "^1.0.0" inherits "^2.0.3" @@ -14110,6 +14288,17 @@ tar-stream@^1.5.0, tar-stream@^1.5.2: to-buffer "^1.1.1" xtend "^4.0.0" +tar-stream@^2.0.0, tar-stream@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3" + integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw== + dependencies: + bl "^3.0.0" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tar@5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/tar/-/tar-5.0.5.tgz#03fcdb7105bc8ea3ce6c86642b9c942495b04f93" @@ -14196,39 +14385,40 @@ term-size@^2.1.0: resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== -terser-webpack-plugin@2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.2.2.tgz#2a6e00237125564a455ad69b22e08ee59420473a" - integrity sha512-/CHMNswPMAwuD2kd++qys8UmBRmsshPSzHw4BlDwurPtK9YjeK93OV89YWkJulHk972cs07K/7Z92V6PNjWF8A== +terser-webpack-plugin@2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz#5ad971acce5c517440ba873ea4f09687de2f4a81" + integrity sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w== dependencies: cacache "^13.0.1" - find-cache-dir "^3.1.0" - jest-worker "^24.9.0" - schema-utils "^2.6.1" - serialize-javascript "^2.1.1" + find-cache-dir "^3.2.0" + jest-worker "^25.1.0" + p-limit "^2.2.2" + schema-utils "^2.6.4" + serialize-javascript "^2.1.2" source-map "^0.6.1" - terser "^4.4.2" + terser "^4.4.3" webpack-sources "^1.4.3" -terser-webpack-plugin@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" - integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== dependencies: cacache "^12.0.2" find-cache-dir "^2.1.0" is-wsl "^1.1.0" schema-utils "^1.0.0" - serialize-javascript "^1.7.0" + serialize-javascript "^2.1.2" source-map "^0.6.1" terser "^4.1.2" webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser@4.4.2, terser@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.2.tgz#448fffad0245f4c8a277ce89788b458bfd7706e8" - integrity sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ== +terser@4.6.7, terser@^4.4.3: + version "4.6.7" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.7.tgz#478d7f9394ec1907f0e488c5f6a6a9a2bad55e72" + integrity sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -14633,10 +14823,10 @@ unicode-match-property-ecmascript@^1.0.4: unicode-canonical-property-names-ecmascript "^1.0.4" unicode-property-aliases-ecmascript "^1.0.4" -unicode-match-property-value-ecmascript@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" - integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== unicode-property-aliases-ecmascript@^1.0.4: version "1.0.5" @@ -15016,23 +15206,23 @@ webcrypto@~0.1.1: crypto-browserify "^3.10.0" detect-node "^2.0.3" -webextension-polyfill@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.5.0.tgz#795e0bf6a2b8eadcdb6edaecd169e9228c747519" - integrity sha512-aFrl38x43t1bTboX/paCT8I97+idzX/TY0+fuM52hrIkCpYfROEF9kSn0BXuEIi3J9LTYt2ZZKkhx9NB1qF3nA== +webextension-polyfill@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.6.0.tgz#1afd925f3274a0d4848083579b9c0b649a5c6763" + integrity sha512-PlYwiX8e4bNZrEeBFxbFFsLtm0SMPxJliLTGdNCA0Bq2XkWrAn2ejUd+89vZm+8BnfFB1BclJyCz3iKsm2atNg== webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== -webpack-bundle-analyzer@3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.0.tgz#39b3a8f829ca044682bc6f9e011c95deb554aefd" - integrity sha512-orUfvVYEfBMDXgEKAKVvab5iQ2wXneIEorGNsyuOyVYpjYrI7CUOhhXNDd3huMwQ3vNNWWlGP+hzflMFYNzi2g== +webpack-bundle-analyzer@3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.1.tgz#bdb637c2304424f2fbff9a950c7be42a839ae73b" + integrity sha512-Nfd8HDwfSx1xBwC+P8QMGvHAOITxNBSvu/J/mCJvOwv+G4VWkU7zir9SSenTtyCi0LnVtmsc7G5SZo1uV+bxRw== dependencies: - acorn "^6.0.7" - acorn-walk "^6.1.1" + acorn "^7.1.1" + acorn-walk "^7.1.1" bfj "^6.1.1" chalk "^2.4.1" commander "^2.18.0" @@ -15045,10 +15235,10 @@ webpack-bundle-analyzer@3.6.0: opener "^1.5.1" ws "^6.0.0" -webpack-cli@3.3.10: - version "3.3.10" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" - integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== +webpack-cli@3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.11.tgz#3bf21889bf597b5d82c38f215135a411edfdc631" + integrity sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g== dependencies: chalk "2.4.2" cross-spawn "6.0.5" @@ -15077,10 +15267,10 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@4.41.2: - version "4.41.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.2.tgz#c34ec76daa3a8468c9b61a50336d8e3303dce74e" - integrity sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A== +webpack@4.42.0: + version "4.42.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8" + integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -15102,7 +15292,7 @@ webpack@4.41.2: node-libs-browser "^2.2.1" schema-utils "^1.0.0" tapable "^1.1.3" - terser-webpack-plugin "^1.4.1" + terser-webpack-plugin "^1.4.3" watchpack "^1.6.0" webpack-sources "^1.4.1" From e5889f2c97af693544b24a0e24a5de0b11a66c7c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 28 Mar 2020 00:01:47 +0100 Subject: [PATCH 04/12] fix: toggle per website on .ipfs.localhost --- add-on/src/lib/dnslink.js | 15 ++++---- add-on/src/lib/http-proxy.js | 3 +- add-on/src/lib/ipfs-path.js | 9 ++--- add-on/src/lib/ipfs-request.js | 41 ++++++++++++++++++---- add-on/src/popup/browser-action/store.js | 13 +++---- test/functional/lib/dnslink.test.js | 38 ++++++++++++++++++++ test/functional/lib/ipfs-companion.test.js | 6 ++-- 7 files changed, 97 insertions(+), 28 deletions(-) diff --git a/add-on/src/lib/dnslink.js b/add-on/src/lib/dnslink.js index 79a8ee558..2cda65dee 100644 --- a/add-on/src/lib/dnslink.js +++ b/add-on/src/lib/dnslink.js @@ -9,9 +9,7 @@ const IsIpfs = require('is-ipfs') const LRU = require('lru-cache') const { default: PQueue } = require('p-queue') const { offlinePeerCount } = require('./state') -const { sameGateway, pathAtHttpGateway } = require('./ipfs-path') - -// TODO: add Preferences toggle to disable redirect of DNSLink websites (while keeping async dnslink lookup) +const { ipfsContentPath, sameGateway, pathAtHttpGateway } = require('./ipfs-path') module.exports = function createDnslinkResolver (getState) { // DNSLink lookup result cache @@ -203,11 +201,11 @@ module.exports = function createDnslinkResolver (getState) { // in url.hostname OR in url.pathname (/ipns/) // and return matching FQDN if present findDNSLinkHostname (url) { - const { hostname, pathname } = new URL(url) - // check //foo.tld/ipns/ - if (IsIpfs.ipnsPath(pathname)) { + // Normalize subdomain and path gateways to to /ipns/ + const contentPath = ipfsContentPath(url) + if (IsIpfs.ipnsPath(contentPath)) { // we may have false-positives here, so we do additional checks below - const ipnsRoot = pathname.match(/^\/ipns\/([^/]+)/)[1] + const ipnsRoot = contentPath.match(/^\/ipns\/([^/]+)/)[1] // console.log('findDNSLinkHostname ==> inspecting IPNS root', ipnsRoot) // Ignore PeerIDs, match DNSLink only if (!IsIpfs.cid(ipnsRoot) && dnslinkResolver.readAndCacheDnslink(ipnsRoot)) { @@ -215,7 +213,8 @@ module.exports = function createDnslinkResolver (getState) { return ipnsRoot } } - // check ///foo/bar + // Check main hostname + const { hostname } = new URL(url) if (dnslinkResolver.readAndCacheDnslink(hostname)) { // console.log('findDNSLinkHostname ==> found DNSLink for url.hostname', hostname) return hostname diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js index 381b12c1c..7eda290c9 100644 --- a/add-on/src/lib/http-proxy.js +++ b/add-on/src/lib/http-proxy.js @@ -46,7 +46,8 @@ async function registerSubdomainProxy (getState, runtime, notify) { // Show pop-up only the first time, during init() when notify is passed try { if (notify) notify('notify_addonIssueTitle', 'notify_addonIssueMsg') - } catch (_) {} + } catch (_) { + } } } diff --git a/add-on/src/lib/ipfs-path.js b/add-on/src/lib/ipfs-path.js index 5e7e1f9c7..c623b07c9 100644 --- a/add-on/src/lib/ipfs-path.js +++ b/add-on/src/lib/ipfs-path.js @@ -170,8 +170,8 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { // Test if actions such as 'per site redirect toggle' should be enabled for the URL isRedirectPageActionsContext (url) { - const { ipfsNodeType, gwURL, apiURL } = getState() - return ipfsNodeType !== 'embedded' && // hide with embedded node + const { localGwAvailable, gwURL, apiURL } = getState() + return localGwAvailable && // show only when redirect is possible (isIPFS.ipnsUrl(url) || // show on /ipns/ (url.startsWith('http') && // hide on non-HTTP pages !sameGateway(url, gwURL) && // hide on /ipfs/* and *.ipfs. @@ -204,8 +204,9 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { // Instead, we resolve it to the canonical FQDN Origin // // Remove gateway suffix to get potential FQDN - const url = new URL(input) - const ipnsId = url.hostname.replace(`.ipns.${pubSubdomainGwURL.hostname}`, '') + const url = new URL(subdomainUrl) + // TODO: replace below with regex that match any subdomain gw + const { id: ipnsId } = subdomainPatternMatch(url) // Ensure it includes .tld (needs at least one dot) if (ipnsId.includes('.')) { // Confirm DNSLink record is present and its not a false-positive diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index f524afc1d..b9d546b37 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -63,6 +63,31 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru } } + // Returns a canonical hostname representing the site from url + // Main reason for this is unwrapping DNSLink from local subdomain + // .ipns.localhost → + const findSiteFqdn = (url) => { + if (isIPFS.ipnsSubdomain(url)) { + // convert subdomain's .ipns.gateway.tld to + const fqdn = dnslinkResolver.findDNSLinkHostname(url) + if (fqdn) return fqdn + } + return new URL(url).hostname + } + + // Finds canonical hostname of request.url and its parent page (if present) + const findSiteHostnames = (request) => { + const { url, originUrl, initiator } = request + const fqdn = findSiteFqdn(url) + // FF: originUrl (Referer-like Origin URL), Chrome: initiator (just Origin) + const parentUrl = originUrl || initiator + // String value 'null' is explicitly set by Chromium in some contexts + const parentFqdn = parentUrl && parentUrl !== 'null' && url !== parentUrl + ? findSiteFqdn(parentUrl) + : null + return { fqdn, parentFqdn } + } + const preNormalizationSkip = (state, request) => { // skip requests to the custom gateway or API (otherwise we have too much recursion) if (sameGateway(request.url, state.gwURL) || sameGateway(request.url, state.apiURL)) { @@ -76,15 +101,19 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (request.url.startsWith('http://127.0.0.1') || request.url.startsWith('http://localhost') || request.url.startsWith('http://[::1]')) { ignore(request.requestId) } + // skip if a per-site opt-out exists - const parentUrl = request.originUrl || request.initiator // FF: originUrl (Referer-like Origin URL), Chrome: initiator (just Origin) - const fqdn = new URL(request.url).hostname - const parentFqdn = parentUrl && parentUrl !== 'null' && request.url !== parentUrl ? new URL(parentUrl).hostname : null - if (state.noIntegrationsHostnames.some(optout => - fqdn !== 'gateway.ipfs.io' && (fqdn.endsWith(optout) || (parentFqdn && parentFqdn.endsWith(optout)) - ))) { + const { fqdn, parentFqdn } = findSiteHostnames(request) + const triggerOptOut = (optout) => { + // Disable optout on canonical public gateway + if (fqdn === 'gateway.ipfs.io') return false + if (fqdn.endsWith(optout) || (parentFqdn && parentFqdn.endsWith(optout))) return true + return false + } + if (state.noIntegrationsHostnames.some(triggerOptOut)) { ignore(request.requestId) } + // additional checks limited to requests for root documents if (request.type === 'main_frame') { // lazily trigger DNSLink lookup (will do anything only if status for root domain is not in cache) diff --git a/add-on/src/popup/browser-action/store.js b/add-on/src/popup/browser-action/store.js index e1ae791f6..9655a7e88 100644 --- a/add-on/src/popup/browser-action/store.js +++ b/add-on/src/popup/browser-action/store.js @@ -2,8 +2,8 @@ /* eslint-env browser, webextensions */ const browser = require('webextension-polyfill') -const IsIpfs = require('is-ipfs') -const { trimHashAndSearch } = require('../../lib/ipfs-path') +const isIPFS = require('is-ipfs') +const { trimHashAndSearch, ipfsContentPath } = require('../../lib/ipfs-path') const { contextMenuViewOnGateway, contextMenuCopyAddressAtPublicGw, contextMenuCopyRawCid, contextMenuCopyCanonicalAddress } = require('../../lib/context-menus') // The store contains and mutates the state for the app @@ -182,17 +182,18 @@ module.exports = (state, emitter) => { // console.dir('toggleSiteIntegrations', state) await browser.storage.local.set({ noIntegrationsHostnames }) - // TODO: remove below? does it still make sense in "integrations toggle" context? // Reload the current tab to apply updated redirect preference - if (!state.currentDnslinkFqdn || !IsIpfs.ipnsUrl(state.currentTab.url)) { + if (!state.currentDnslinkFqdn || !isIPFS.ipnsUrl(state.currentTab.url)) { // No DNSLink, reload URL as-is await browser.tabs.reload(state.currentTab.id) } else { // DNSLinked websites require URL change - // from http?://gateway.tld/ipns/{fqdn}/some/path + // from http?://gateway.tld/ipns/{fqdn}/some/path OR + // from http?://{fqdn}.ipns.gateway.tld/some/path // to http://{fqdn}/some/path // (defaulting to http: https websites will have HSTS or a redirect) - const originalUrl = state.currentTab.url.replace(/^.*\/ipns\//, 'http://') + const path = ipfsContentPath(state.currentTab.url, { keepURIParams: true }) + const originalUrl = path.replace(/^.*\/ipns\//, 'http://') await browser.tabs.update(state.currentTab.id, { // FF only: loadReplace: true, url: originalUrl diff --git a/test/functional/lib/dnslink.test.js b/test/functional/lib/dnslink.test.js index a06ebe19c..f61fe7626 100644 --- a/test/functional/lib/dnslink.test.js +++ b/test/functional/lib/dnslink.test.js @@ -209,6 +209,44 @@ describe('dnslinkResolver (dnslinkPolicy=enabled)', function () { }) }) + describe('findDNSLinkHostname(url)', function () { + it('should match directly', function () { + const fqdn = 'dnslink-site.com' + const url = new URL(`https://${fqdn}/some/path?ds=sdads#dfsdf`) + const dnslinkResolver = createDnslinkResolver(getState) + spoofDnsTxtRecord(fqdn, dnslinkResolver, dnslinkValue) + expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(fqdn) + }) + /* TODO + it('should return null if no DNSLink record', function () { + const url = new URL(`https://no-dnslink.example.com/some/path?ds=sdads#dfsdf`) + const dnslinkResolver = createDnslinkResolver(getState) + expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(undefined) + }) + */ + it('should match /ipns/ on path gateway', function () { + const fqdn = 'dnslink-site.com' + const url = `https://path-gateway.com/ipns/${fqdn}/some/path?ds=sdads#dfsdf` + const dnslinkResolver = createDnslinkResolver(getState) + spoofDnsTxtRecord(fqdn, dnslinkResolver, dnslinkValue) + expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(fqdn) + }) + it('should match .ipns on local subdomain gateway', function () { + const fqdn = 'dnslink-site.com' + const url = `https://${fqdn}.ipns.localhost:8080/some/path?ds=sdads#dfsdf` + const dnslinkResolver = createDnslinkResolver(getState) + spoofDnsTxtRecord(fqdn, dnslinkResolver, dnslinkValue) + expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(fqdn) + }) + it('should match .ipns on public subdomain gateway', function () { + const fqdn = 'dnslink-site.com' + const url = `https://${fqdn}.ipns.dweb.link/some/path?ds=sdads#dfsdf` + const dnslinkResolver = createDnslinkResolver(getState) + spoofDnsTxtRecord(fqdn, dnslinkResolver, dnslinkValue) + expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(fqdn) + }) + }) + after(() => { delete global.URL }) diff --git a/test/functional/lib/ipfs-companion.test.js b/test/functional/lib/ipfs-companion.test.js index 4448246e5..0f2276d47 100644 --- a/test/functional/lib/ipfs-companion.test.js +++ b/test/functional/lib/ipfs-companion.test.js @@ -25,7 +25,7 @@ describe('init', function () { browser.storage.local.set.returns(Promise.resolve()) const ipfsCompanion = await init() browser.storage.local.get.calledWith(optionDefaults) - ipfsCompanion.destroy() + await ipfsCompanion.destroy() }) it('should fixup migrated files APIs', async function () { @@ -42,7 +42,7 @@ describe('init', function () { expect(typeof ipfsCompanion.ipfs[cmd], `ipfs.${cmd} expected to be a function`).to.equal('function') expect(typeof ipfsCompanion.ipfs.files[cmd], `ipfs.files.${cmd} expected to be a function`).to.equal('function') } - ipfsCompanion.destroy() + await ipfsCompanion.destroy() }) after(function () { @@ -86,7 +86,7 @@ describe.skip('onStorageChange()', function () { const ipfs = global.window.ipfs browser.storage.onChanged.dispatch(changes, area) expect(ipfs).to.not.equal(window.ipfs) - ipfsCompanion.destroy() + await ipfsCompanion.destroy() }) after(function () { From 4ce869e8eff876e68bc07d145fd747f069175e22 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 31 Mar 2020 22:58:23 +0200 Subject: [PATCH 05/12] fix: proxy only the gateway port --- add-on/src/lib/http-proxy.js | 29 ++++++++++++++++++----------- add-on/src/lib/ipfs-path.js | 1 + 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js index 7eda290c9..59af54735 100644 --- a/add-on/src/lib/http-proxy.js +++ b/add-on/src/lib/http-proxy.js @@ -29,15 +29,15 @@ async function registerSubdomainProxy (getState, runtime, notify) { // HTTP Proxy feature is exposed on the gateway port // Just ensure we use localhost IP to remove any dependency on DNS - const proxy = safeURL(gwURLString, { useLocalhostName: false }) + const { hostname, port } = safeURL(gwURLString, { useLocalhostName: false }) // Firefox uses own APIs for selective proxying if (runtime.isFirefox) { - return await registerSubdomainProxyFirefox(enable, proxy.hostname, proxy.port) + return await registerSubdomainProxyFirefox(enable, hostname, port) } // at this point we asume Chromium - return await registerSubdomainProxyChromium(enable, proxy.host) + return await registerSubdomainProxyChromium(enable, hostname, port) } catch (err) { // registerSubdomainProxy is just a failsafe, not necessary in most cases, // so we should not break init when it fails. @@ -56,7 +56,7 @@ var onRequestProxyListener // registerSubdomainProxyFirefox sets proxy using API available in Firefox // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/onRequest -async function registerSubdomainProxyFirefox (enable, host, port) { +async function registerSubdomainProxyFirefox (enable, hostname, port) { const { onRequest } = browser.proxy // always remove the old listener (host and port could change) @@ -66,15 +66,22 @@ async function registerSubdomainProxyFirefox (enable, host, port) { } if (enable) { - // create new listener with the latest host:port - onRequestProxyListener = (request) => ({ type: 'http', host, port }) + // create new listener with the latest host:port note: the listener is + // handling requests made to all localhost ports (limitation of the API, + // port is ignored) that is why we manually check port inside of the listener + onRequestProxyListener = (request) => { + if (new URL(request.url).port === port) { + return { type: 'http', host: hostname, port } + } + return { type: 'direct' } + } // register the listener onRequest.addListener(onRequestProxyListener, { urls: ['http://*.localhost/*'], incognito: false }) - log(`enabled ${host}:${port} as HTTP proxy for *.localhost`) + log(`enabled ${hostname}:${port} as HTTP proxy for *.localhost`) return } @@ -94,7 +101,7 @@ const clear = async (opts) => new Promise((resolve, reject) => chrome.proxy.sett // registerSubdomainProxyChromium sets proxy using API available in Chromium // https://developer.chrome.com/extensions/proxy -async function registerSubdomainProxyChromium (enable, proxyHost) { +async function registerSubdomainProxyChromium (enable, hostname, port) { const scope = 'regular_only' // read current proxy settings @@ -108,14 +115,14 @@ async function registerSubdomainProxyChromium (enable, proxyHost) { mode: 'pac_script', pacScript: { data: 'function FindProxyForURL(url, host) {\n' + - " if (shExpMatch(host, '*.localhost'))\n" + - ` return 'PROXY ${proxyHost}';\n` + + ` if (shExpMatch(host, '*.localhost:${port}'))\n` + + ` return 'PROXY ${hostname}:${port}';\n` + " return 'DIRECT';\n" + '}' } } await set({ value: pacConfig, scope }) - log(`enabled ${proxyHost} as HTTP proxy for *.localhost`) + log(`enabled ${hostname}:${port} as HTTP proxy for *.localhost`) // log('updated chrome.proxy.settings', await get({ incognito: false })) return } diff --git a/add-on/src/lib/ipfs-path.js b/add-on/src/lib/ipfs-path.js index c623b07c9..ec15dc971 100644 --- a/add-on/src/lib/ipfs-path.js +++ b/add-on/src/lib/ipfs-path.js @@ -160,6 +160,7 @@ function createIpfsPathValidator (getState, getIpfs, dnslinkResolver) { // Test if actions such as 'copy URL', 'pin/unpin' should be enabled for the URL isIpfsPageActionsContext (url) { + if (!url) return false const { apiURLString } = getState() const { hostname } = new URL(url) return Boolean(url && !url.startsWith(apiURLString) && ( From 1acf89954a2ff08b4205ae35309353c520ea9575 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 1 Apr 2020 00:47:55 +0200 Subject: [PATCH 06/12] fix: decode content paths with decodeURI This avoids ibreaking IPFS content paths by converting them to URI params --- add-on/src/lib/http-proxy.js | 7 ++++++ add-on/src/lib/ipfs-path.js | 2 +- .../lib/ipfs-request-gateway-redirect.test.js | 24 ++++++++++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js index 59af54735..6ce25bad3 100644 --- a/add-on/src/lib/http-proxy.js +++ b/add-on/src/lib/http-proxy.js @@ -23,6 +23,13 @@ log.error = debug('ipfs-companion:http-proxy:error') // registerSubdomainProxy is necessary wourkaround for supporting subdomains // under 'localhost' (*.ipfs.localhost) because some operating systems do not // resolve them to local IP and return NX error not found instead +// +// State in Q2 2020: +// - Chromium hardcodes `localhost` name to point at local IP and proxy is not +// really necessary, but we do it just to be safe. +// - Firefox requires proxy to avoid DNS lookup, but there is an open issue +// that will remove that need at some point: +// https://bugzilla.mozilla.org/show_bug.cgi?id=1220810 async function registerSubdomainProxy (getState, runtime, notify) { try { const { useSubdomainProxy: enable, gwURLString } = getState() diff --git a/add-on/src/lib/ipfs-path.js b/add-on/src/lib/ipfs-path.js index ec15dc971..608ec429f 100644 --- a/add-on/src/lib/ipfs-path.js +++ b/add-on/src/lib/ipfs-path.js @@ -25,7 +25,7 @@ function ipfsContentPath (urlOrPath, opts) { // To get IPFS content path we need to reverse URI encoding of special // characters (https://github.com/ipfs/ipfs-companion/issues/303) - const contentPath = decodeURIComponent(url.pathname) + const contentPath = decodeURI(url.pathname) // End if not a content path if (!isIPFS.path(contentPath)) return null diff --git a/test/functional/lib/ipfs-request-gateway-redirect.test.js b/test/functional/lib/ipfs-request-gateway-redirect.test.js index 0f31f47ad..d833f4689 100644 --- a/test/functional/lib/ipfs-request-gateway-redirect.test.js +++ b/test/functional/lib/ipfs-request-gateway-redirect.test.js @@ -259,6 +259,10 @@ describe('modifyRequest.onBeforeRequest:', function () { const cid = 'bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge' const peerid = 'bafzbeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge' + // Tests use different CID in X-Ipfs-Path header just to ensure it does not + // override the one from path + const fakeXIpfsPathHdrVal = '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' + describe('with external node', function () { beforeEach(function () { state.ipfsNodeType = 'external' @@ -269,21 +273,29 @@ describe('modifyRequest.onBeforeRequest:', function () { const request = url2request(`https://${cid}.ipfs.dweb.link/`) // X-Ipfs-Path to ensure value from URL takes a priority - request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: fakeXIpfsPathHdrVal }] /// We expect redirect to path-based gateway because go-ipfs >=0.5 will - // return redirect to subdomain, and we don't want to break older - // versions + // return redirect to a subdomain, and we don't want to break users + // running older versions of go-ipfs by loading subdomain first and + // failing. expect(modifyRequest.onBeforeRequest(request).redirectUrl) .to.equal(`http://localhost:8080/ipfs/${cid}/`) }) it('should be redirected to localhost gateway (*.ipfs on 3rd party gw)', function () { state.redirect = true const request = url2request(`https://${cid}.ipfs.cf-ipfs.com/`) - request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: fakeXIpfsPathHdrVal }] expect(modifyRequest.onBeforeRequest(request).redirectUrl) .to.equal(`http://localhost:8080/ipfs/${cid}/`) }) + it('should be redirected to localhost gateway and keep URL encoding of original path', function () { + state.redirect = true + const request = url2request('https://bafybeigfejjsuq5im5c3w3t3krsiytszhfdc4v5myltcg4myv2n2w6jumy.ipfs.dweb.link/%3Ffilename=test.jpg?arg=val') + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: fakeXIpfsPathHdrVal }] + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal('http://localhost:8080/ipfs/bafybeigfejjsuq5im5c3w3t3krsiytszhfdc4v5myltcg4myv2n2w6jumy/%3Ffilename=test.jpg?arg=val') + }) it('should be redirected to localhost gateway (*.ipns on default gw)', function () { state.redirect = true const request = url2request(`https://${peerid}.ipns.dweb.link/`) @@ -301,13 +313,13 @@ describe('modifyRequest.onBeforeRequest:', function () { it('should be left untouched for *.ipfs at default public subdomain gw', function () { state.redirect = true const request = url2request(`https://${cid}.ipfs.dweb.link/`) - request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: fakeXIpfsPathHdrVal }] expectNoRedirect(modifyRequest, request) }) it('should be redirected to user-prefered public gateway if 3rd party subdomain gw', function () { state.redirect = true const request = url2request(`https://${cid}.ipfs.cf-ipfs.com/`) - request.responseHeaders = [{ name: 'X-Ipfs-Path', value: '/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ' }] + request.responseHeaders = [{ name: 'X-Ipfs-Path', value: fakeXIpfsPathHdrVal }] expect(modifyRequest.onBeforeRequest(request).redirectUrl) .to.equal(`https://${cid}.ipfs.dweb.link/`) }) From 2a6c67ee615658057c3830807dd92dd3abbcb17b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 1 Apr 2020 01:59:41 +0200 Subject: [PATCH 07/12] fix: disable http-proxy when extension is inactive --- add-on/src/lib/http-proxy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js index 6ce25bad3..1e7c553b5 100644 --- a/add-on/src/lib/http-proxy.js +++ b/add-on/src/lib/http-proxy.js @@ -32,7 +32,8 @@ log.error = debug('ipfs-companion:http-proxy:error') // https://bugzilla.mozilla.org/show_bug.cgi?id=1220810 async function registerSubdomainProxy (getState, runtime, notify) { try { - const { useSubdomainProxy: enable, gwURLString } = getState() + const { active, useSubdomainProxy, gwURLString } = getState() + const enable = active && useSubdomainProxy // HTTP Proxy feature is exposed on the gateway port // Just ensure we use localhost IP to remove any dependency on DNS From 207fd76c4fd33b2443ef5c9da1e1591d68f08a53 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 1 Apr 2020 02:00:36 +0200 Subject: [PATCH 08/12] fix: async setApiStatusUpdateInterval It should not block the init() --- add-on/src/lib/ipfs-companion.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 89fb6119a..08e7b54df 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -84,9 +84,9 @@ module.exports = async function init () { ipfsProxyContentScript = await registerIpfsProxyContentScript() log('register all listeners') registerListeners() - await setApiStatusUpdateInterval(options.ipfsApiPollMs) await registerSubdomainProxy(getState, runtime, notify) log('init done') + setApiStatusUpdateInterval(options.ipfsApiPollMs) await showPendingLandingPages() } catch (error) { log.error('Unable to initialize addon due to error', error) @@ -429,7 +429,7 @@ module.exports = async function init () { async function getSwarmPeerCount () { if (!ipfs) return offlinePeerCount try { - const peerInfos = await ipfs.swarm.peers() + const peerInfos = await ipfs.swarm.peers({ timeout: 2500 }) return peerInfos.length } catch (error) { console.error(`Error while ipfs.swarm.peers: ${error}`) @@ -583,6 +583,7 @@ module.exports = async function init () { case 'active': state[key] = change.newValue ipfsProxyContentScript = await registerIpfsProxyContentScript() + await registerSubdomainProxy(getState, runtime) shouldRestartIpfsClient = true shouldStopIpfsClient = !state.active break @@ -638,18 +639,16 @@ module.exports = async function init () { break case 'useSubdomainProxy': state[key] = change.newValue - // More work is needed, as this key decides how requests are routed - // to the gateway: - await browser.storage.local.set({ - // We need to update the hostname in customGatewayUrl: - // 127.0.0.1 - path gateway - // localhost - subdomain gateway - customGatewayUrl: guiURLString( - state.gwURLString, { - useLocalhostName: state.useSubdomainProxy - } - ) - }) + // Normalize hostname if enabled + if (state.useSubdomainProxy) { + await browser.storage.local.set({ + // We need to update the hostname in customGatewayUrl because: + // 127.0.0.1 - path gateway + // localhost - subdomain gateway + // and we need to use the latter + customGatewayUrl: guiURLString(state.gwURLString, { useLocalhostName: true }) + }) + } // Finally, update proxy settings based on the state await registerSubdomainProxy(getState, runtime) break From 3e6708bb1227fc447f908f545e4f157d3936caac Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 1 Apr 2020 16:06:44 +0200 Subject: [PATCH 09/12] fix: mixed-content on HTTP pages Firefox 74 does not mark *.localhost subdomains as Secure Context yet (https://bugzilla.mozilla.org/show_bug.cgi?id=1220810#c23) so we can't redirect there when we have IPFS resource embedded on HTTPS page (eg. image loaded from a public gateway) because that would cause mixed-content warning and subresource would fail to load. Given the fact that localhost/ipfs/* provided by go-ipfs 0.5+ returns a redirect to *.ipfs.localhost subdomain we need to check requests for subresources, and manually replace 'localhost' hostname with '127.0.0.1' (IP is hardcoded as Secure Context in Firefox). The need for this workaround can be revisited when Firefox closes mentioned bug. Chromium 80 seems to force HTTPS in the final URL (after all redirects) so https://*.localhost fails. This needs additional research (could be a bug in Chromium). For now we reuse the same workaround as Firefox. To unify use of 127.0.0.1 and localhost in address bar (eg. when user opens an image in a new tab etc) when Subdomain Proxy is enabled we normalize address bar requests made to the local gateway and replace raw IP with 'localhost' hostname to take advantage of subdomain redirect provided by go-ipfs >= 0.5 --- add-on/src/lib/dnslink.js | 1 + add-on/src/lib/ipfs-path.js | 4 +- add-on/src/lib/ipfs-request.js | 54 ++++++++++++++++--- test/functional/lib/ipfs-path.test.js | 25 ++++++++- .../lib/ipfs-request-gateway-redirect.test.js | 32 +++++++---- .../lib/ipfs-request-workarounds.test.js | 50 +++++++++++++++++ 6 files changed, 146 insertions(+), 20 deletions(-) diff --git a/add-on/src/lib/dnslink.js b/add-on/src/lib/dnslink.js index 2cda65dee..de346476d 100644 --- a/add-on/src/lib/dnslink.js +++ b/add-on/src/lib/dnslink.js @@ -201,6 +201,7 @@ module.exports = function createDnslinkResolver (getState) { // in url.hostname OR in url.pathname (/ipns/) // and return matching FQDN if present findDNSLinkHostname (url) { + if (!url) return // Normalize subdomain and path gateways to to /ipns/ const contentPath = ipfsContentPath(url) if (IsIpfs.ipnsPath(contentPath)) { diff --git a/add-on/src/lib/ipfs-path.js b/add-on/src/lib/ipfs-path.js index 608ec429f..0e734401e 100644 --- a/add-on/src/lib/ipfs-path.js +++ b/add-on/src/lib/ipfs-path.js @@ -94,7 +94,7 @@ function sameGateway (url, gwUrl) { return url.hostname === gwUrl.hostname } - const gws = [gwUrl.hostname] + const gws = [gwUrl.host] // localhost gateway has more than one hostname if (gwUrl.hostname === 'localhost') { @@ -106,7 +106,7 @@ function sameGateway (url, gwUrl) { for (const gwName of gws) { // match against the end to include subdomain gateways - if (url.hostname.endsWith(gwName)) return true + if (url.host.endsWith(gwName)) return true } return false } diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index b9d546b37..3645ef958 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -9,6 +9,7 @@ const LRU = require('lru-cache') const isIPFS = require('is-ipfs') const isFQDN = require('is-fqdn') const { pathAtHttpGateway, sameGateway } = require('./ipfs-path') +const { safeURL } = require('./options') const redirectOptOutHint = 'x-ipfs-companion-no-redirect' const recoverableNetworkErrors = new Set([ @@ -142,6 +143,15 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru onBeforeRequest (request) { const state = getState() if (!state.active) return + + // When Subdomain Proxy is enabled we normalize address bar requests made + // to the local gateway and replace raw IP with 'localhost' hostname to + // take advantage of subdomain redirect provided by go-ipfs >= 0.5 + if (state.redirect && request.type === 'main_frame' && sameGateway(request.url, state.gwURL)) { + const redirectUrl = safeURL(request.url, { useLocalhostName: state.useSubdomainProxy }).toString() + if (redirectUrl !== request.url) return { redirectUrl } + } + // early sanity checks if (preNormalizationSkip(state, request)) { return @@ -169,7 +179,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru } // Detect valid /ipfs/ and /ipns/ on any site if (ipfsPathValidator.publicIpfsOrIpnsResource(request.url) && isSafeToRedirect(request, runtime)) { - return redirectToGateway(request, request.url, state, ipfsPathValidator) + return redirectToGateway(request, request.url, state, ipfsPathValidator, runtime) } // Detect dnslink using heuristics enabled in Preferences if (state.dnslinkPolicy && dnslinkResolver.canLookupURL(request.url)) { @@ -358,7 +368,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru return { redirectUrl } } } - return redirectToGateway(request, request.url, state, ipfsPathValidator) + return redirectToGateway(request, request.url, state, ipfsPathValidator, runtime) } // Detect X-Ipfs-Path Header and upgrade transport to IPFS: @@ -406,7 +416,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru // redirect only if local node is around if (newUrl && state.localGwAvailable) { log(`onHeadersReceived: normalized ${request.url} to ${newUrl}`) - return redirectToGateway(request, newUrl, state, ipfsPathValidator) + return redirectToGateway(request, newUrl, state, ipfsPathValidator, runtime) } } } @@ -505,10 +515,42 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru exports.redirectOptOutHint = redirectOptOutHint exports.createRequestModifier = createRequestModifier -function redirectToGateway (request, url, state, ipfsPathValidator) { +// Returns a string with URL at the active gateway (local or public) +function redirectToGateway (request, url, state, ipfsPathValidator, runtime) { const { resolveToPublicUrl, resolveToLocalUrl } = ipfsPathValidator - const redirectUrl = state.localGwAvailable ? resolveToLocalUrl(url) : resolveToPublicUrl(url) - // redirect only if we actually change anything + let redirectUrl = state.localGwAvailable ? resolveToLocalUrl(url) : resolveToPublicUrl(url) + + // SUBRESOURCE ON HTTPS PAGE: THE WORKAROUND EXTRAVAGANZA + // ------------------------------------------------------ \o/ + // + // Firefox 74 does not mark *.localhost subdomains as Secure Context yet + // (https://bugzilla.mozilla.org/show_bug.cgi?id=1220810#c23) so we can't + // redirect there when we have IPFS resource embedded on HTTPS page (eg. + // image loaded from a public gateway) because that would cause mixed-content + // warning and subresource would fail to load. Given the fact that + // localhost/ipfs/* provided by go-ipfs 0.5+ returns a redirect to + // *.ipfs.localhost subdomain we need to check requests for subresources, and + // manually replace 'localhost' hostname with '127.0.0.1' (IP is hardcoded as + // Secure Context in Firefox). The need for this workaround can be revisited + // when Firefox closes mentioned bug. + // + // Chromium 80 seems to force HTTPS in the final URL (after all redirects) so + // https://*.localhost fails TODO: needs additional research (could be a bug + // in Chromium). For now we reuse the same workaround as Firefox. + // + if (state.localGwAvailable) { + const { type, originUrl, initiator } = request + // match request types for embedded subdresources, but skip ones coming from local gateway + const parentUrl = originUrl || initiator // FF || Chromium + if (type !== 'main_frame' && (parentUrl && !sameGateway(parentUrl, state.gwURL))) { + // use raw IP to ensure subresource will be loaded from the path gateway + // at 127.0.0.1, which is marked as Secure Context in all browsers + const useLocalhostName = false + redirectUrl = safeURL(redirectUrl, { useLocalhostName }).toString() + } + } + + // return a redirect only if URL changed if (redirectUrl && request.url !== redirectUrl) return { redirectUrl } } diff --git a/test/functional/lib/ipfs-path.test.js b/test/functional/lib/ipfs-path.test.js index 8ddda691c..78008916b 100644 --- a/test/functional/lib/ipfs-path.test.js +++ b/test/functional/lib/ipfs-path.test.js @@ -3,7 +3,7 @@ const { stub } = require('sinon') const { describe, it, beforeEach, afterEach } = require('mocha') const { expect } = require('chai') const { URL } = require('url') -const { ipfsContentPath, createIpfsPathValidator } = require('../../../add-on/src/lib/ipfs-path') +const { ipfsContentPath, createIpfsPathValidator, sameGateway } = require('../../../add-on/src/lib/ipfs-path') const { initState } = require('../../../add-on/src/lib/state') const createDnslinkResolver = require('../../../add-on/src/lib/dnslink') const { optionDefaults } = require('../../../add-on/src/lib/options') @@ -102,6 +102,29 @@ describe('ipfs-path.js', function () { }) }) + describe('sameGateway', function () { + it('should return true on direct host match', function () { + const url = 'https://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar' + const gw = 'http://127.0.0.1:8080' + expect(sameGateway(url, gw)).to.equal(true) + }) + it('should return true on localhost/127.0.0.1 host match', function () { + const url = 'https://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar' + const gw = 'http://127.0.0.1:8080' + expect(sameGateway(url, gw)).to.equal(true) + }) + it('should return true on 127.0.0.1/localhost host match', function () { + const url = 'https://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar' + const gw = 'http://localhost:8080' + expect(sameGateway(url, gw)).to.equal(true) + }) + it('should return false on hostname match but different port', function () { + const url = 'https://localhost:8081/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar' + const gw = 'http://localhost:8080' + expect(sameGateway(url, gw)).to.equal(false) + }) + }) + describe('validIpfsOrIpns', function () { // this is just a smoke test, extensive tests are in is-ipfs package it('should return true for IPFS NURI', function () { diff --git a/test/functional/lib/ipfs-request-gateway-redirect.test.js b/test/functional/lib/ipfs-request-gateway-redirect.test.js index d833f4689..7eb61cdae 100644 --- a/test/functional/lib/ipfs-request-gateway-redirect.test.js +++ b/test/functional/lib/ipfs-request-gateway-redirect.test.js @@ -111,7 +111,7 @@ describe('modifyRequest.onBeforeRequest:', function () { }) }) - describe('XHR request for a path matching /ipfs/{CIDv0}', function () { + describe('XHR request for a path matching /ipfs/{CIDv0} coming from 3rd party Origin', function () { describe('with external node', function () { beforeEach(function () { state.ipfsNodeType = 'external' @@ -119,22 +119,22 @@ describe('modifyRequest.onBeforeRequest:', function () { it('should be served from custom gateway if fetched from the same origin and redirect is enabled in Firefox', function () { runtime.isFirefox = true const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', originUrl: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if fetched from the same origin and redirect is enabled in Chromium', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if XHR is cross-origin and redirect is enabled in Chromium', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://www.nasa.gov/foo.html', requestId: fakeRequestId() } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if XHR is cross-origin and redirect is enabled in Firefox', function () { runtime.isFirefox = true const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', originUrl: 'https://www.nasa.gov/foo.html', requestId: fakeRequestId() } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) }) describe('with embedded node', function () { @@ -170,17 +170,17 @@ describe('modifyRequest.onBeforeRequest:', function () { it('should be served from custom gateway if fetched from the same origin and redirect is enabled in Firefox', function () { runtime.isFirefox = true const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', originUrl: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if fetched from the same origin and redirect is enabled in non-Firefox', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://google.com/' } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway if XHR is cross-origin and redirect is enabled in non-Firefox', function () { runtime.isFirefox = false const xhrRequest = { url: 'https://google.com/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest', type: 'xmlhttprequest', initiator: 'https://www.nasa.gov/foo.html', requestId: fakeRequestId() } - expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onBeforeRequest(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) it('should be served from custom gateway via late redirect in onHeadersReceived if XHR is cross-origin and redirect is enabled in Firefox', function () { // Context for CORS XHR problems in Firefox: https://github.com/ipfs-shipyard/ipfs-companion/issues/436 @@ -189,7 +189,7 @@ describe('modifyRequest.onBeforeRequest:', function () { // onBeforeRequest should not change anything, as it will trigger false-positive CORS error expect(modifyRequest.onBeforeRequest(xhrRequest)).to.equal(undefined) // onHeadersReceived is after CORS validation happens, so its ok to cancel and redirect late - expect(modifyRequest.onHeadersReceived(xhrRequest).redirectUrl).to.equal('http://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') + expect(modifyRequest.onHeadersReceived(xhrRequest).redirectUrl).to.equal('http://127.0.0.1:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest') }) }) }) @@ -255,7 +255,7 @@ describe('modifyRequest.onBeforeRequest:', function () { }) }) - describe('request to a public subdomain gateway (CID in subdomain)', function () { + describe('request to a subdomain gateway', function () { const cid = 'bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge' const peerid = 'bafzbeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge' @@ -339,7 +339,7 @@ describe('modifyRequest.onBeforeRequest:', function () { state.redirect = true }) describe(`with ${nodeType} node:`, function () { - describe('request for IPFS path at a localhost', function () { + describe('request for IPFS path at the localhost', function () { // we do not touch local requests, as it may interfere with other nodes running at the same machine // or could produce false-positives such as redirection from localhost:5001/ipfs/path to localhost:8080/ipfs/path it('should be left untouched if localhost is used', function () { @@ -362,6 +362,16 @@ describe('modifyRequest.onBeforeRequest:', function () { const request = url2request('http://[::1]:5001/ipfs/QmPhnvn747LqwPYMJmQVorMaGbMSgA7mRRoyyZYz3DoZRQ/') expectNoRedirect(modifyRequest, request) }) + it('should be redirected to localhost (subdomain in go-ipfs >0.5) if type=main_frame and 127.0.0.1 (path gw) is used un URL', function () { + state.redirect = true + state.useSubdomainProxy = true + expect(state.gwURL.hostname).to.equal('localhost') + const cid = 'QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR' + const request = url2request(`http://127.0.0.1:8080/ipfs/${cid}?arg=val#hash`) + request.type = 'main_frame' // explicit + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://localhost:8080/ipfs/${cid}?arg=val#hash`) + }) }) }) }) diff --git a/test/functional/lib/ipfs-request-workarounds.test.js b/test/functional/lib/ipfs-request-workarounds.test.js index 4de4838c7..fb9a74b97 100644 --- a/test/functional/lib/ipfs-request-workarounds.test.js +++ b/test/functional/lib/ipfs-request-workarounds.test.js @@ -39,6 +39,56 @@ describe('modifyRequest processing', function () { modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime) }) + // Additional handling is required for redirected IPFS subresources on regular HTTPS pages + // (eg. image embedded from public gateway on HTTPS website) + describe('a subresource request on HTTPS website', function () { + const cid = 'QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR' + it('should be routed to "127.0.0.1" gw in Chromium if type is image', function () { + runtime.isFirefox = false + const request = { + method: 'GET', + type: 'image', + url: `https://ipfs.io/ipfs/${cid}`, + initiator: 'https://some-website.example.com' // Chromium + } + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://127.0.0.1:8080/ipfs/${cid}`) + }) + it('should be routed to "localhost" gw in Chromium if not a subresource', function () { + runtime.isFirefox = false + const request = { + method: 'GET', + type: 'main_frame', + url: `https://ipfs.io/ipfs/${cid}`, + initiator: 'https://some-website.example.com' // Chromium + } + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://localhost:8080/ipfs/${cid}`) + }) + it('should be routed to "127.0.0.1" gw to avoid mixed content warning in Firefox', function () { + runtime.isFirefox = true + const request = { + method: 'GET', + type: 'image', + url: `https://ipfs.io/ipfs/${cid}`, + originUrl: 'https://some-website.example.com/some/page.html' // FF only + } + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://127.0.0.1:8080/ipfs/${cid}`) + }) + it('should be routed to "localhost" gw in Firefox if not a subresource', function () { + runtime.isFirefox = true + const request = { + method: 'GET', + type: 'main_frame', + url: `https://ipfs.io/ipfs/${cid}`, + originUrl: 'https://some-website.example.com/some/page.html' // FF only + } + expect(modifyRequest.onBeforeRequest(request).redirectUrl) + .to.equal(`http://localhost:8080/ipfs/${cid}`) + }) + }) + describe('a request to /api/v0/add with stream-channels=true', function () { const expectHeader = { name: 'Expect', value: '100-continue' } it('should apply the "Expect: 100-continue" fix for https://github.com/ipfs/go-ipfs/issues/5168 ', function () { From eb66dfa683acc1e068199e7e364b642160c646d0 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 3 Apr 2020 02:05:48 +0200 Subject: [PATCH 10/12] refactor: use HTTP proxy for subdomains only on Firefox Chromium 80 already hardcodes localhost to loopback IPs, and we don't want to add unnecessary permission as it may cause us fail review at Chrome Web Store. I also renamed the setting as its about overall Subdomain support on localhost, even when HTTP proxy is not used. --- add-on/_locales/en/messages.json | 12 ++++++------ add-on/manifest.chromium.json | 13 +++++++++++++ add-on/manifest.common.json | 14 -------------- add-on/manifest.firefox.json | 14 ++++++++++++++ add-on/src/lib/http-proxy.js | 19 ++++++++++++++----- add-on/src/lib/ipfs-companion.js | 19 +++++++++---------- add-on/src/lib/ipfs-request.js | 2 +- add-on/src/lib/options.js | 6 +++--- add-on/src/lib/state.js | 2 +- add-on/src/options/forms/gateways-form.js | 14 +++++++------- add-on/src/options/page.js | 2 +- package.json | 2 +- .../lib/ipfs-request-gateway-redirect.test.js | 2 +- yarn.lock | 4 ++-- 14 files changed, 73 insertions(+), 52 deletions(-) diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json index 4434db2ac..0b8dcf243 100644 --- a/add-on/_locales/en/messages.json +++ b/add-on/_locales/en/messages.json @@ -279,13 +279,13 @@ "message": "Redirect requests for IPFS resources to the Custom gateway", "description": "An option description on the Preferences screen (option_useCustomGateway_description)" }, - "option_useSubdomainProxy_title": { - "message": "Use Subdomain Proxy", - "description": "An option title on the Preferences screen (option_useSubdomainProxy_title)" + "option_useSubdomains_title": { + "message": "Use Subdomains", + "description": "An option title on the Preferences screen (option_useSubdomains_title)" }, - "option_useSubdomainProxy_description": { - "message": "Use Custom Gateway as HTTP Proxy to enable Origin isolation per content root at *.ipfs.localhost", - "description": "An option description on the Preferences screen (option_useSubdomainProxy_description)" + "option_useSubdomains_description": { + "message": "Isolate content roots from each other by loading them from subdomains at *.localhost and creating a unique Origin for each CID, IPNS or DNSLink record. Requires a local go-ipfs 0.5.0 or later.", + "description": "An option description on the Preferences screen (option_useSubdomains_description)" }, "option_dnslinkRedirect_title": { "message": "Load websites from Custom Gateway", diff --git a/add-on/manifest.chromium.json b/add-on/manifest.chromium.json index 81a8f2767..9949e6e1d 100644 --- a/add-on/manifest.chromium.json +++ b/add-on/manifest.chromium.json @@ -1,4 +1,17 @@ { "minimum_chrome_version": "72", + "permissions": [ + "", + "idle", + "tabs", + "notifications", + "storage", + "unlimitedStorage", + "contextMenus", + "clipboardWrite", + "webNavigation", + "webRequest", + "webRequestBlocking" + ], "incognito": "not_allowed" } diff --git a/add-on/manifest.common.json b/add-on/manifest.common.json index 8aa8f9f80..947138058 100644 --- a/add-on/manifest.common.json +++ b/add-on/manifest.common.json @@ -11,20 +11,6 @@ "38": "icons/png/ipfs-logo-on_38.png", "128": "icons/png/ipfs-logo-on_128.png" }, - "permissions": [ - "", - "idle", - "tabs", - "notifications", - "storage", - "unlimitedStorage", - "contextMenus", - "clipboardWrite", - "proxy", - "webNavigation", - "webRequest", - "webRequestBlocking" - ], "background": { "page": "dist/background/background.html" }, diff --git a/add-on/manifest.firefox.json b/add-on/manifest.firefox.json index f3229ccd5..1cb644983 100644 --- a/add-on/manifest.firefox.json +++ b/add-on/manifest.firefox.json @@ -18,6 +18,20 @@ "default_title": "__MSG_pageAction_titleNonIpfs__", "default_popup": "dist/popup/page-action/index.html" }, + "permissions": [ + "", + "idle", + "tabs", + "notifications", + "proxy", + "storage", + "unlimitedStorage", + "contextMenus", + "clipboardWrite", + "webNavigation", + "webRequest", + "webRequestBlocking" + ], "content_scripts": [ ], "protocol_handlers": [ { diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js index 1e7c553b5..3df2e8665 100644 --- a/add-on/src/lib/http-proxy.js +++ b/add-on/src/lib/http-proxy.js @@ -26,14 +26,17 @@ log.error = debug('ipfs-companion:http-proxy:error') // // State in Q2 2020: // - Chromium hardcodes `localhost` name to point at local IP and proxy is not -// really necessary, but we do it just to be safe. +// really necessary. The code is here (inactivE) in case we need it in the future. // - Firefox requires proxy to avoid DNS lookup, but there is an open issue // that will remove that need at some point: // https://bugzilla.mozilla.org/show_bug.cgi?id=1220810 async function registerSubdomainProxy (getState, runtime, notify) { + // At the moment only firefox requires proxy registration + if (!runtime.isFirefox) return + try { - const { active, useSubdomainProxy, gwURLString } = getState() - const enable = active && useSubdomainProxy + const { active, useSubdomains, gwURLString } = getState() + const enable = active && useSubdomains // HTTP Proxy feature is exposed on the gateway port // Just ensure we use localhost IP to remove any dependency on DNS @@ -44,8 +47,9 @@ async function registerSubdomainProxy (getState, runtime, notify) { return await registerSubdomainProxyFirefox(enable, hostname, port) } - // at this point we asume Chromium - return await registerSubdomainProxyChromium(enable, hostname, port) + // At this point we would asume Chromium, but its not needed atm + // Uncomment below if ever needed (+ add 'proxy' permission to manifest.json) + // return await registerSubdomainProxyChromium(enable, hostname, port) } catch (err) { // registerSubdomainProxy is just a failsafe, not necessary in most cases, // so we should not break init when it fails. @@ -97,6 +101,10 @@ async function registerSubdomainProxyFirefox (enable, hostname, port) { log('disabled HTTP proxy for *.localhost') } +/* + * Chromium 80 does not need proxy, so below is not used. + * Uncomment below if ever needed (+ add 'proxy' permission to manifest.json) + // Helpers for converting callback chrome.* API to promises const cb = (resolve, reject) => (result) => { const err = chrome.runtime.lastError @@ -142,5 +150,6 @@ async function registerSubdomainProxyChromium (enable, hostname, port) { log('disabled HTTP proxy for *.localhost') } } +*/ module.exports.registerSubdomainProxy = registerSubdomainProxy diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 08e7b54df..47ef9fa25 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -637,18 +637,17 @@ module.exports = async function init () { case 'useCustomGateway': state.redirect = change.newValue break - case 'useSubdomainProxy': + case 'useSubdomains': state[key] = change.newValue - // Normalize hostname if enabled - if (state.useSubdomainProxy) { - await browser.storage.local.set({ - // We need to update the hostname in customGatewayUrl because: - // 127.0.0.1 - path gateway - // localhost - subdomain gateway - // and we need to use the latter - customGatewayUrl: guiURLString(state.gwURLString, { useLocalhostName: true }) + await browser.storage.local.set({ + // We need to update the hostname in customGatewayUrl because: + // 127.0.0.1 - path gateway + // localhost - subdomain gateway + // and we need to use the latter + customGatewayUrl: guiURLString(state.gwURLString, { + useLocalhostName: state.useSubdomains }) - } + }) // Finally, update proxy settings based on the state await registerSubdomainProxy(getState, runtime) break diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index 3645ef958..7dca61366 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -148,7 +148,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru // to the local gateway and replace raw IP with 'localhost' hostname to // take advantage of subdomain redirect provided by go-ipfs >= 0.5 if (state.redirect && request.type === 'main_frame' && sameGateway(request.url, state.gwURL)) { - const redirectUrl = safeURL(request.url, { useLocalhostName: state.useSubdomainProxy }).toString() + const redirectUrl = safeURL(request.url, { useLocalhostName: state.useSubdomains }).toString() if (redirectUrl !== request.url) return { redirectUrl } } diff --git a/add-on/src/lib/options.js b/add-on/src/lib/options.js index 8e7be5c7f..64c56f22e 100644 --- a/add-on/src/lib/options.js +++ b/add-on/src/lib/options.js @@ -13,7 +13,7 @@ exports.optionDefaults = Object.freeze({ publicGatewayUrl: 'https://ipfs.io', publicSubdomainGatewayUrl: 'https://dweb.link', useCustomGateway: true, - useSubdomainProxy: true, + useSubdomains: true, noIntegrationsHostnames: [], automaticMode: true, linkify: false, @@ -169,8 +169,8 @@ exports.migrateOptions = async (storage) => { // migrate old default 127.0.0.1 to localhost hostname const { customGatewayUrl: gwUrl } = await storage.get('customGatewayUrl') if (gwUrl && (localhostIpUrl(gwUrl) || localhostNameUrl(gwUrl))) { - const { useSubdomainProxy } = await storage.get('useSubdomainProxy') - const newUrl = guiURLString(gwUrl, { useLocalhostName: useSubdomainProxy }) + const { useSubdomains } = await storage.get('useSubdomains') + const newUrl = guiURLString(gwUrl, { useLocalhostName: useSubdomains }) if (gwUrl !== newUrl) { await storage.set({ customGatewayUrl: newUrl }) } diff --git a/add-on/src/lib/state.js b/add-on/src/lib/state.js index 48523a76b..992271ee4 100644 --- a/add-on/src/lib/state.js +++ b/add-on/src/lib/state.js @@ -25,7 +25,7 @@ function initState (options, overrides) { state.apiURL = safeURL(options.ipfsApiUrl, { useLocalhostName: false }) // go-ipfs returns 403 if IP is beautified to 'localhost' state.apiURLString = state.apiURL.toString() delete state.ipfsApiUrl - state.gwURL = safeURL(options.customGatewayUrl, { useLocalhostName: state.useSubdomainProxy }) + state.gwURL = safeURL(options.customGatewayUrl, { useLocalhostName: state.useSubdomains }) state.gwURLString = state.gwURL.toString() delete state.customGatewayUrl state.dnslinkPolicy = String(options.dnslinkPolicy) === 'false' ? false : options.dnslinkPolicy diff --git a/add-on/src/options/forms/gateways-form.js b/add-on/src/options/forms/gateways-form.js index dbeec8cb1..ab4c2bdc0 100644 --- a/add-on/src/options/forms/gateways-form.js +++ b/add-on/src/options/forms/gateways-form.js @@ -15,15 +15,15 @@ function gatewaysForm ({ ipfsNodeType, customGatewayUrl, useCustomGateway, - useSubdomainProxy, + useSubdomains, noIntegrationsHostnames, publicGatewayUrl, publicSubdomainGatewayUrl, onOptionChange }) { - const onCustomGatewayUrlChange = onOptionChange('customGatewayUrl', (url) => guiURLString(url, { useLocalhostName: useSubdomainProxy })) + const onCustomGatewayUrlChange = onOptionChange('customGatewayUrl', (url) => guiURLString(url, { useLocalhostName: useSubdomains })) const onUseCustomGatewayChange = onOptionChange('useCustomGateway') - const onUseSubdomainProxyChange = onOptionChange('useSubdomainProxy') + const onUseSubdomainProxyChange = onOptionChange('useSubdomains') const onPublicGatewayUrlChange = onOptionChange('publicGatewayUrl', guiURLString) const onPublicSubdomainGatewayUrlChange = onOptionChange('publicSubdomainGatewayUrl', guiURLString) const onNoIntegrationsHostnamesChange = onOptionChange('noIntegrationsHostnames', hostTextToArray) @@ -113,18 +113,18 @@ function gatewaysForm ({ ` : null} ${supportRedirectToCustomGateway ? html`
-
` : null} ${supportRedirectToCustomGateway ? html` diff --git a/add-on/src/options/page.js b/add-on/src/options/page.js index e3173fae0..57a17a71a 100644 --- a/add-on/src/options/page.js +++ b/add-on/src/options/page.js @@ -67,7 +67,7 @@ module.exports = function optionsPage (state, emit) { ipfsNodeType: state.options.ipfsNodeType, customGatewayUrl: state.options.customGatewayUrl, useCustomGateway: state.options.useCustomGateway, - useSubdomainProxy: state.options.useSubdomainProxy, + useSubdomains: state.options.useSubdomains, publicGatewayUrl: state.options.publicGatewayUrl, publicSubdomainGatewayUrl: state.options.publicSubdomainGatewayUrl, noIntegrationsHostnames: state.options.noIntegrationsHostnames, diff --git a/package.json b/package.json index f7c5bb621..7fcb2f71c 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "ipfs-postmsg-proxy": "3.1.1", "ipfsx": "0.17.0", "is-fqdn": "1.0.1", - "is-ipfs": "https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz", + "is-ipfs": "https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz", "is-svg": "4.2.0", "it-to-stream": "0.1.1", "lru-cache": "5.1.1", diff --git a/test/functional/lib/ipfs-request-gateway-redirect.test.js b/test/functional/lib/ipfs-request-gateway-redirect.test.js index 7eb61cdae..81b8ccdeb 100644 --- a/test/functional/lib/ipfs-request-gateway-redirect.test.js +++ b/test/functional/lib/ipfs-request-gateway-redirect.test.js @@ -364,7 +364,7 @@ describe('modifyRequest.onBeforeRequest:', function () { }) it('should be redirected to localhost (subdomain in go-ipfs >0.5) if type=main_frame and 127.0.0.1 (path gw) is used un URL', function () { state.redirect = true - state.useSubdomainProxy = true + state.useSubdomains = true expect(state.gwURL.hostname).to.equal('localhost') const cid = 'QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR' const request = url2request(`http://127.0.0.1:8080/ipfs/${cid}?arg=val#hash`) diff --git a/yarn.lock b/yarn.lock index bdfdbde64..7d3a0b077 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7931,9 +7931,9 @@ is-ip@^3.1.0: dependencies: ip-regex "^4.0.0" -"is-ipfs@https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz": +"is-ipfs@https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz": version "0.6.3" - resolved "https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz#733850d100cb80d08d251706d4b91ab14b58bd56" + resolved "https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz#c3f2f4d5423be1bfff4712488c742eb89d5f7ac0" dependencies: bs58 "^4.0.1" cids "~0.7.0" From 4a81bf1af3a64c2e634d768867b9602ceb69782f Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 4 Apr 2020 01:33:45 +0200 Subject: [PATCH 11/12] refactor: remove code for "blessing" custom webui This restores the proper way of opening webui in version provided by IPFS node. Context: Before subdomain gateway support was added, we loaded webui from gateway port. Why? API port has a hardcoded list of whitelisted webui versions and it is not possible to load non-whitelisted CID when new webui was released. To enable API access from webui loaded via Gateway port, the Companion extension removed Origin header for requests coming from its background page. This let us avoid the need for manual CORS setup, but was seen in the diff, was pretty complex process. Webui is stable now, so to decrease maintenance burden we move away from that complexity and just load version whitelisted on API port. What if someone wants to run newest webui? They can now load it from webui.ipfs.io.ipns.localhost:8080 (whitelist API access from that specific Origin by appending it to API.HTTPHeaders.Access-Control-Allow-Origin in go-ipfs config) Closes #736 --- add-on/src/lib/dnslink.js | 8 +- add-on/src/lib/ipfs-companion.js | 19 +-- add-on/src/lib/ipfs-request.js | 137 +++--------------- add-on/src/lib/precache.js | 5 +- add-on/src/lib/state.js | 20 --- package.json | 5 +- .../lib/ipfs-request-workarounds.test.js | 75 +++------- yarn.lock | 71 ++++++--- 8 files changed, 112 insertions(+), 228 deletions(-) diff --git a/add-on/src/lib/dnslink.js b/add-on/src/lib/dnslink.js index de346476d..1c695e77c 100644 --- a/add-on/src/lib/dnslink.js +++ b/add-on/src/lib/dnslink.js @@ -125,7 +125,13 @@ module.exports = function createDnslinkResolver (getState) { let apiProvider // TODO: fix DNS resolver for ipfsNodeType='embedded:chromesockets', for now use ipfs.io if (!state.ipfsNodeType.startsWith('embedded') && state.peerCount !== offlinePeerCount) { - apiProvider = state.apiURLString + // Use gw port so it can be a GET: + // Chromium does not execute onBeforeSendHeaders for synchronous calls + // made from the same extension context as onBeforeSendHeaders + // which means we are unable to fixup Origin on the fly for this + // This will no longer be needed when we switch + // to async lookup via ipfs.dns everywhere + apiProvider = state.gwURLString } else { // fallback to resolver at public gateway apiProvider = 'https://ipfs.io/' diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 47ef9fa25..7b2b49858 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -6,7 +6,6 @@ const log = debug('ipfs-companion:main') log.error = debug('ipfs-companion:main:error') const browser = require('webextension-polyfill') -const toMultiaddr = require('uri-to-multiaddr') const pMemoize = require('p-memoize') const { optionDefaults, storeMissingOptions, migrateOptions, guiURLString } = require('./options') const { initState, offlinePeerCount } = require('./state') @@ -107,7 +106,8 @@ module.exports = async function init () { function registerListeners () { const onBeforeSendInfoSpec = ['blocking', 'requestHeaders'] if (browser.webRequest.OnBeforeSendHeadersOptions && 'EXTRA_HEADERS' in browser.webRequest.OnBeforeSendHeadersOptions) { - // Chrome 72+ requires 'extraHeaders' for access to Referer header (used in cors whitelisting of webui) + // Chrome 72+ requires 'extraHeaders' for accessing all headers + // Note: we need this for code ensuring ipfs-http-client can talk to API without setting CORS onBeforeSendInfoSpec.push('extraHeaders') } browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, { urls: [''] }, onBeforeSendInfoSpec) @@ -385,18 +385,6 @@ module.exports = async function init () { log.error(`Unable to linkify DOM at '${details.url}' due to`, error) } } - if (details.url.startsWith(state.webuiRootUrl)) { - // Ensure API backend points at one from IPFS Companion - const apiMultiaddr = toMultiaddr(state.apiURLString) - await browser.tabs.executeScript(details.tabId, { - runAt: 'document_start', - code: `if (!localStorage.getItem('ipfsApi')) { - console.log('[ipfs-companion] Setting API to ${apiMultiaddr}'); - localStorage.setItem('ipfsApi', '${apiMultiaddr}'); - window.location.reload(); - }` - }) - } } // API STATUS UPDATES @@ -615,6 +603,7 @@ module.exports = async function init () { case 'ipfsApiUrl': state.apiURL = new URL(change.newValue) state.apiURLString = state.apiURL.toString() + state.webuiRootUrl = `${state.apiURLString}webui/` shouldRestartIpfsClient = true break case 'ipfsApiPollMs': @@ -623,8 +612,6 @@ module.exports = async function init () { case 'customGatewayUrl': state.gwURL = new URL(change.newValue) state.gwURLString = state.gwURL.toString() - // TODO: for now we load webui from API port, should we remove this? - // state.webuiRootUrl = `${state.gwURLString}ipfs/${state.webuiCid}/` break case 'publicGatewayUrl': state.pubGwURL = new URL(change.newValue) diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index 7dca61366..1814078a0 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -43,27 +43,6 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru const isIgnored = (id) => ignoredRequests.get(id) !== undefined const errorInFlight = new LRU({ max: 3, maxAge: 1000 }) - const acrhHeaders = new LRU(requestCacheCfg) // webui cors fix in Chrome - const originUrls = new LRU(requestCacheCfg) // request.originUrl workaround for Chrome - const originUrl = (request) => { - // Firefox and Chrome provide relevant value in different fields: - // (Firefox) request object includes full URL of origin document, return as-is - if (request.originUrl) return request.originUrl - // (Chrome) is lacking: `request.initiator` is just the origin (protocol+hostname+port) - // To reconstruct originUrl we read full URL from Referer header in onBeforeSendHeaders - // and cache it for short time - // TODO: when request.originUrl is available in Chrome the `originUrls` cache can be removed - const cachedUrl = originUrls.get(request.requestId) - if (cachedUrl) return cachedUrl - if (request.requestHeaders) { - const referer = request.requestHeaders.find(h => h.name === 'Referer') - if (referer) { - originUrls.set(request.requestId, referer.value) - return referer.value - } - } - } - // Returns a canonical hostname representing the site from url // Main reason for this is unwrapping DNSLink from local subdomain // .ipns.localhost → @@ -208,63 +187,34 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru // Special handling of requests made to API if (sameGateway(request.url, state.apiURL)) { - // Requests made by 'blessed' Web UI - // -------------------------------------------- - // Goal: Web UI works without setting CORS at go-ipfs - // (Without this snippet go-ipfs will return HTTP 403 due to additional origin check on the backend) - const origin = originUrl(request) - if (origin && origin.startsWith(state.webuiRootUrl)) { - // console.log('onBeforeSendHeaders', request) - // console.log('onBeforeSendHeaders.origin', origin) - // Swap Origin to pass server-side check - // (go-ipfs returns HTTP 403 on origin mismatch if there are no CORS headers) - const swapOrigin = (at) => { - request.requestHeaders[at].value = request.requestHeaders[at].value.replace(state.gwURL.origin, state.apiURL.origin) - } - let foundAt = request.requestHeaders.findIndex(h => h.name === 'Origin') - if (foundAt > -1) swapOrigin(foundAt) - foundAt = request.requestHeaders.findIndex(h => h.name === 'Referer') - if (foundAt > -1) swapOrigin(foundAt) - - // Save access-control-request-headers from preflight - foundAt = request.requestHeaders.findIndex(h => h.name && h.name.toLowerCase() === 'access-control-request-headers') - if (foundAt > -1) { - acrhHeaders.set(request.requestId, request.requestHeaders[foundAt].value) - // console.log('onBeforeSendHeaders FOUND access-control-request-headers', acrhHeaders.get(request.requestId)) - } - // console.log('onBeforeSendHeaders fixed headers', request.requestHeaders) - } - + const { requestHeaders } = request // '403 - Forbidden' fix for Chrome and Firefox // -------------------------------------------- - // We remove Origin header from requests made to API URL and WebUI - // by js-ipfs-http-client running in WebExtension context to remove need - // for manual CORS whitelisting via Access-Control-Allow-Origin at go-ipfs + // We update "Origin: *-extension://" HTTP headers in requests made to API + // by js-ipfs-http-client running in the background page of browser + // extension. Without this, some users would need to do manual CORS + // whitelisting by adding "..extension://" to + // API.HTTPHeaders.Access-Control-Allow-Origin in go-ipfs config. + // With this, API calls made by browser extension look like ones made + // by webui loaded from the API port. // More info: // Firefox: https://github.com/ipfs-shipyard/ipfs-companion/issues/622 // Chromium 71: https://github.com/ipfs-shipyard/ipfs-companion/pull/616 // Chromium 72: https://github.com/ipfs-shipyard/ipfs-companion/issues/630 - const isWebExtensionOrigin = (origin) => { - // console.log(`origin=${origin}, webExtensionOrigin=${webExtensionOrigin}`) - // Chromium <= 71 returns opaque Origin as defined in - // https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin - if (origin == null || origin === 'null') { - return true - } - // Firefox Nightly 65 sets moz-extension://{extension-installation-id} - // Chromium Beta 72 sets chrome-extension://{uid} - if (origin && + + // Firefox Nightly 65 sets moz-extension://{extension-installation-id} + // Chromium Beta 72 sets chrome-extension://{uid} + const isWebExtensionOrigin = (origin) => + origin && (origin.startsWith('moz-extension://') || - origin.startsWith('chrome-extension://')) && - new URL(origin).origin === webExtensionOrigin) { - return true - } - return false - } + origin.startsWith('chrome-extension://')) && + new URL(origin).origin === webExtensionOrigin - // Remove Origin header matching webExtensionOrigin - const foundAt = request.requestHeaders.findIndex(h => h.name === 'Origin' && isWebExtensionOrigin(h.value)) - if (foundAt > -1) request.requestHeaders.splice(foundAt, 1) + // Replace Origin header matching webExtensionOrigin with API one + const foundAt = requestHeaders.findIndex(h => h.name === 'Origin' && isWebExtensionOrigin(h.value)) + if (foundAt > -1) { + requestHeaders[foundAt].value = state.apiURL.origin + } // Fix "http: invalid Read on closed Body" // ---------------------------------- @@ -277,7 +227,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru let addExpectHeader = true const expectHeader = { name: 'Expect', value: '100-continue' } const warningMsg = 'Executing "Expect: 100-continue" workaround for ipfs.add due to https://github.com/ipfs/go-ipfs/issues/5168' - for (const header of request.requestHeaders) { + for (const header of requestHeaders) { // Workaround A: https://github.com/ipfs/go-ipfs/issues/5168#issuecomment-401417420 // (works in Firefox, but Chromium does not expose Connection header) /* (disabled so we use the workaround B in all browsers) @@ -301,12 +251,10 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru } if (addExpectHeader) { log(warningMsg) - request.requestHeaders.push(expectHeader) + requestHeaders.push(expectHeader) } } - } - return { - requestHeaders: request.requestHeaders + return { requestHeaders } } }, @@ -317,41 +265,6 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru const state = getState() if (!state.active) return - // Special handling of requests made to API - if (sameGateway(request.url, state.apiURL)) { - // Special handling of requests made by 'blessed' Web UI from local Gateway - // Goal: Web UI works without setting CORS at go-ipfs - // (This includes 'ignored' requests: CORS needs to be fixed even if no redirect is done) - const origin = originUrl(request) - if (origin && origin.startsWith(state.webuiRootUrl) && request.responseHeaders) { - // console.log('onHeadersReceived', request) - const acaOriginHeader = { name: 'Access-Control-Allow-Origin', value: state.gwURL.origin } - const foundAt = findHeaderIndex(acaOriginHeader.name, request.responseHeaders) - if (foundAt > -1) { - request.responseHeaders[foundAt].value = acaOriginHeader.value - } else { - request.responseHeaders.push(acaOriginHeader) - } - - // Restore access-control-request-headers from preflight - const acrhValue = acrhHeaders.get(request.requestId) - if (acrhValue) { - const acahHeader = { name: 'Access-Control-Allow-Headers', value: acrhValue } - const foundAt = findHeaderIndex(acahHeader.name, request.responseHeaders) - if (foundAt > -1) { - request.responseHeaders[foundAt].value = acahHeader.value - } else { - request.responseHeaders.push(acahHeader) - } - acrhHeaders.del(request.requestId) - // console.log('onHeadersReceived SET Access-Control-Allow-Headers', header) - } - - // console.log('onHeadersReceived fixed headers', request.responseHeaders) - return { responseHeaders: request.responseHeaders } - } - } - // Skip if request is marked as ignored if (isIgnored(request.requestId)) { return @@ -651,10 +564,6 @@ function normalizedUnhandledIpfsProtocol (request, pubGwUrl) { } } -function findHeaderIndex (name, headers) { - return headers.findIndex(x => x.name && x.name.toLowerCase() === name.toLowerCase()) -} - // RECOVERY OF FAILED REQUESTS // =================================================================== diff --git a/add-on/src/lib/precache.js b/add-on/src/lib/precache.js index b300ffcbf..55753fb34 100644 --- a/add-on/src/lib/precache.js +++ b/add-on/src/lib/precache.js @@ -5,12 +5,15 @@ const drain = require('pull-stream/sinks/drain') const toStream = require('it-to-stream') const tar = require('tar-stream') const CID = require('cids') -const { webuiCid } = require('./state') const debug = require('debug') const log = debug('ipfs-companion:precache') log.error = debug('ipfs-companion:precache:error') +// Web UI release that should be precached +// WARNING: do not remove this constant, as its used in package.json +const webuiCid = 'Qmexhq2sBHnXQbvyP2GfUdbnY7HCagH2Mw5vUNSBn2nxip' // v2.7.2 + const PRECACHE_ARCHIVES = [ { tarPath: '/dist/precache/webui.tar', cid: webuiCid } ] diff --git a/add-on/src/lib/state.js b/add-on/src/lib/state.js index 992271ee4..e74ff3825 100644 --- a/add-on/src/lib/state.js +++ b/add-on/src/lib/state.js @@ -4,10 +4,6 @@ const { safeURL } = require('./options') const offlinePeerCount = -1 -// CID of a 'blessed' Web UI release -// which should work without setting CORS headers -const webuiCid = 'Qmexhq2sBHnXQbvyP2GfUdbnY7HCagH2Mw5vUNSBn2nxip' // v2.7.2 - function initState (options, overrides) { // we store options and some pregenerated values to avoid async storage // reads and minimize performance impact on overall browsing experience @@ -29,21 +25,6 @@ function initState (options, overrides) { state.gwURLString = state.gwURL.toString() delete state.customGatewayUrl state.dnslinkPolicy = String(options.dnslinkPolicy) === 'false' ? false : options.dnslinkPolicy - state.webuiCid = webuiCid - - // TODO: unify the way webui is opened - // - https://github.com/ipfs-shipyard/ipfs-companion/pull/737 - // - https://github.com/ipfs-shipyard/ipfs-companion/pull/738 - // Context: previously, we loaded webui from gateway port - // (`${state.gwURLString}ipfs/${state.webuiCid}/`) because API port - // has hardcoded list of whitelisted webui versions. - // To enable API access from webui loaded from Gateway port Companion - // removed Origin header to avoid CORS, now we move away from that - // complexity and for now just load version whitelisted on API port. - // In the future, we want to load webui from $webuiCid.ipfs.localhost - // and whitelist API access from that specific hostname - // by appending it to API.HTTPHeaders.Access-Control-Allow-Origin list - // When that is possible, we can remove Origin manipulation (see PR #737 for PoC) state.webuiRootUrl = `${state.apiURLString}webui/` // attach helper functions @@ -69,4 +50,3 @@ function initState (options, overrides) { exports.initState = initState exports.offlinePeerCount = offlinePeerCount -exports.webuiCid = webuiCid diff --git a/package.json b/package.json index 7fcb2f71c..50358ad27 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "build:bundle-all": "cross-env RELEASE_CHANNEL=${RELEASE_CHANNEL:=dev} run-s bundle:chromium bundle:brave:$RELEASE_CHANNEL bundle:firefox:$RELEASE_CHANNEL", "build:rename-artifacts": "./scripts/rename-artifacts.js", "precache:clean": "shx rm -rf add-on/dist/precache", - "precache:webui:cid": "shx grep 'const webuiCid' add-on/src/lib/state.js | shx sed \"s/^const webuiCid = '//\" | shx sed \"s/'.*$//\"", + "precache:webui:cid": "shx grep 'const webuiCid' add-on/src/lib/precache.js | shx sed \"s/^const webuiCid = '//\" | shx sed \"s/'.*$//\"", "precache:webui": "shx mkdir -p add-on/dist/precache && ipfs-or-gateway -c $(npm run -s precache:webui:cid) -p add-on/dist/precache/webui.tar --archive", "bundle": "run-s bundle:*", "bundle:chromium": "run-s precache:webui && shx cat add-on/manifest.common.json add-on/manifest.chromium.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/chromium && run-s build:rename-artifacts", @@ -140,7 +140,7 @@ "ipfs-postmsg-proxy": "3.1.1", "ipfsx": "0.17.0", "is-fqdn": "1.0.1", - "is-ipfs": "https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz", + "is-ipfs": "1.0.0", "is-svg": "4.2.0", "it-to-stream": "0.1.1", "lru-cache": "5.1.1", @@ -158,7 +158,6 @@ "tachyons": "4.11.1", "tar-stream": "2.1.2", "timers-browserify-full": "0.0.1", - "uri-to-multiaddr": "3.0.1", "webextension-polyfill": "0.6.0", "webrtc-ips": "0.1.4" }, diff --git a/test/functional/lib/ipfs-request-workarounds.test.js b/test/functional/lib/ipfs-request-workarounds.test.js index fb9a74b97..4083aa5af 100644 --- a/test/functional/lib/ipfs-request-workarounds.test.js +++ b/test/functional/lib/ipfs-request-workarounds.test.js @@ -105,8 +105,9 @@ describe('modifyRequest processing', function () { }) }) - describe('a request to /api/v0/ with Origin=moz-extension://{extension-installation-id}', function () { - it('should remove Origin header with moz-extension://', async function () { + describe('a request to /api/v0/ made with extension:// Origin', function () { + it('should have it replaced with API one if Origin: moz-extension://{extension-installation-id}', async function () { + // Context: Firefox 65 started setting this header // set vendor-specific Origin for WebExtension context browser.runtime.getURL.withArgs('/').returns('moz-extension://0f334731-19e3-42f8-85e2-03dbf50026df/') // ensure clean modifyRequest @@ -114,19 +115,22 @@ describe('modifyRequest processing', function () { modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime) // test const bogusOriginHeader = { name: 'Origin', value: 'moz-extension://0f334731-19e3-42f8-85e2-03dbf50026df' } + const apiOriginHeader = { name: 'Origin', value: getState().apiURL.origin } const request = { requestHeaders: [bogusOriginHeader], type: 'xmlhttprequest', url: `${state.apiURLString}api/v0/id` } modifyRequest.onBeforeRequest(request) // executes before onBeforeSendHeaders, may mutate state - expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders).to.not.include(bogusOriginHeader) + expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders) + .to.deep.include(apiOriginHeader) browser.runtime.getURL.flush() }) }) - describe('a request to /api/v0/ with Origin=chrome-extension://{extension-installation-id}', function () { - it('should remove Origin header with chrome-extension://', async function () { + describe('should have it removed if Origin: chrome-extension://{extension-installation-id}', function () { + it('should have it swapped with API one if Origin: with chrome-extension://', async function () { + // Context: Chromium 72 started setting this header // set vendor-specific Origin for WebExtension context browser.runtime.getURL.withArgs('/').returns('chrome-extension://trolrorlrorlrol/') // ensure clean modifyRequest @@ -134,77 +138,38 @@ describe('modifyRequest processing', function () { modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime) // test const bogusOriginHeader = { name: 'Origin', value: 'chrome-extension://trolrorlrorlrol' } + const apiOriginHeader = { name: 'Origin', value: getState().apiURL.origin } const request = { requestHeaders: [bogusOriginHeader], type: 'xmlhttprequest', url: `${state.apiURLString}api/v0/id` } modifyRequest.onBeforeRequest(request) // executes before onBeforeSendHeaders, may mutate state - expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders).to.not.include(bogusOriginHeader) + expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders) + .to.deep.include(apiOriginHeader) browser.runtime.getURL.flush() }) }) describe('a request to /api/v0/ with Origin=null', function () { - it('should remove Origin header ', async function () { - // set vendor-specific Origin for WebExtension context + it('should keep the "Origin: null" header ', async function () { + // Presence of Origin header is important as it protects API from XSS via sandboxed iframe + // NOTE: Chromium <72 was setting this header in requests sent by browser extension, + // but they fixed it since then. browser.runtime.getURL.withArgs('/').returns(undefined) // ensure clean modifyRequest runtime = Object.assign({}, await createRuntimeChecks(browser)) // make it mutable for tests modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime) // test - const bogusOriginHeader = { name: 'Origin', value: 'null' } + const nullOriginHeader = { name: 'Origin', value: 'null' } const request = { - requestHeaders: [bogusOriginHeader], + requestHeaders: [nullOriginHeader], type: 'xmlhttprequest', url: `${state.apiURLString}api/v0/id` } modifyRequest.onBeforeRequest(request) // executes before onBeforeSendHeaders, may mutate state - expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders).to.not.include(bogusOriginHeader) - browser.runtime.getURL.flush() - }) - }) - - // Web UI is loaded from hardcoded 'blessed' CID, which enables us to remove - // CORS limitation. This makes Web UI opened from browser action work without - // the need for any additional configuration of go-ipfs daemon - describe('a request to API from blessed webuiRootUrl', function () { - it('should pass without CORS limitations ', async function () { - // ensure clean modifyRequest - runtime = Object.assign({}, await createRuntimeChecks(browser)) // make it mutable for tests - modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime) - // test - const webuiOriginHeader = { name: 'Origin', value: state.webuiRootUrl } - const webuiRefererHeader = { name: 'Referer', value: state.webuiRootUrl } - // CORS whitelisting does not worh in Chrome 72 without passing/restoring ACRH preflight header - const acrhHeader = { name: 'Access-Control-Request-Headers', value: 'X-Test' } // preflight to store - - // Test request - let request = { - requestHeaders: [webuiOriginHeader, webuiRefererHeader, acrhHeader], - type: 'xmlhttprequest', - originUrl: state.webuiRootUrl, - url: `${state.apiURLString}api/v0/id` - } - request = modifyRequest.onBeforeRequest(request) || request // executes before onBeforeSendHeaders, may mutate state - const requestHeaders = modifyRequest.onBeforeSendHeaders(request).requestHeaders - - // "originUrl" should be swapped to look like it came from the same origin as HTTP API - const expectedOriginUrl = state.webuiRootUrl.replace(state.gwURLString, state.apiURLString) - expect(requestHeaders).to.deep.include({ name: 'Origin', value: expectedOriginUrl }) - expect(requestHeaders).to.deep.include({ name: 'Referer', value: expectedOriginUrl }) - expect(requestHeaders).to.deep.include(acrhHeader) - - // Test response - const response = Object.assign({}, request) - delete response.requestHeaders - response.responseHeaders = [] - const responseHeaders = modifyRequest.onHeadersReceived(response).responseHeaders - const corsHeader = { name: 'Access-Control-Allow-Origin', value: state.gwURL.origin } - const acahHeader = { name: 'Access-Control-Allow-Headers', value: acrhHeader.value } // expect value restored from preflight - expect(responseHeaders).to.deep.include(corsHeader) - expect(responseHeaders).to.deep.include(acahHeader) - + expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders) + .to.deep.include(nullOriginHeader) browser.runtime.getURL.flush() }) }) diff --git a/yarn.lock b/yarn.lock index 7d3a0b077..a93cdf516 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3269,6 +3269,17 @@ cids@^0.7.1, cids@~0.7.0, cids@~0.7.1: multicodec "~0.5.1" multihashes "~0.4.14" +cids@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.8.0.tgz#41bf050bc7669cc8d648e21ca834b747bf6fa673" + integrity sha512-HdKURxtSOnww3H28CJU2TauIklEBsOn+ouGl2EOnSfVCVkH6+sWTj7to2D/BmuWvwzEy2+ZIKdcIwsXHJBQVew== + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.7.0" + multicodec "^1.0.1" + multihashes "~0.4.17" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -7931,16 +7942,18 @@ is-ip@^3.1.0: dependencies: ip-regex "^4.0.0" -"is-ipfs@https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz": - version "0.6.3" - resolved "https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz#c3f2f4d5423be1bfff4712488c742eb89d5f7ac0" +is-ipfs@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-1.0.0.tgz#bb286d9a933eee0189932ca6d762e94ca85996ea" + integrity sha512-5C2sxUZqbXH5oMovtzvM6pog0sBRdScgqMUsqVb5wSj/AdAbY1QRjd7Hpm5IGeKlWpCUTmH5Kpd1JZx0jigB2A== dependencies: bs58 "^4.0.1" - cids "~0.7.0" - mafmt "^7.0.0" - multiaddr "^7.2.1" + cids "~0.8.0" + iso-url "~0.4.7" + mafmt "^7.1.0" + multiaddr "^7.4.3" multibase "~0.7.0" - multihashes "~0.4.13" + multihashes "~0.4.19" is-ipfs@~0.4.2: version "0.4.8" @@ -8198,6 +8211,11 @@ iso-url@^0.4.4, iso-url@~0.4.4, iso-url@~0.4.6: resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-0.4.6.tgz#45005c4af4984cad4f8753da411b41b74cf0a8a6" integrity sha512-YQO7+aIe6l1aSJUKOx+Vrv08DlhZeLFIVfehG2L29KLSEb9RszqPXilxJRVpp57px36BddKR5ZsebacO5qG0tg== +iso-url@~0.4.7: + version "0.4.7" + resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-0.4.7.tgz#de7e48120dae46921079fe78f325ac9e9217a385" + integrity sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog== + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -9746,7 +9764,7 @@ mafmt@^6.0.10: dependencies: multiaddr "^6.1.0" -mafmt@^7.0.0: +mafmt@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/mafmt/-/mafmt-7.1.0.tgz#4126f6d0eded070ace7dbbb6fb04977412d380b5" integrity sha512-vpeo9S+hepT3k2h5iFxzEHvvR0GPBx9uKaErmnRzYNcaKb03DgOArjEMlgG4a9LcuZZ89a3I8xbeto487n26eA== @@ -10364,7 +10382,7 @@ multiaddr-to-uri@^4.0.1: dependencies: multiaddr "^6.0.3" -multiaddr@6.1.0, multiaddr@^4.0.0, multiaddr@^5.0.0, multiaddr@^6.0.3, multiaddr@^6.0.4, multiaddr@^6.0.6, multiaddr@^6.1.0, multiaddr@^6.1.1, multiaddr@^7.2.1, multiaddr@^7.3.0: +multiaddr@6.1.0, multiaddr@^4.0.0, multiaddr@^5.0.0, multiaddr@^6.0.3, multiaddr@^6.0.4, multiaddr@^6.0.6, multiaddr@^6.1.0, multiaddr@^6.1.1, multiaddr@^7.3.0, multiaddr@^7.4.3: version "6.1.0" resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-6.1.0.tgz#1f93afce58a33db5cc32a5917d8a14105d94330e" integrity sha512-+XTP3OzG2m6JVcjxA9QBmGDr0Vk8WwnohC/fCC3puXb5qJqfJwLVJLEtdTc6vK7ri/hw+Nn4wyT4LkZaPnvGfQ== @@ -10389,14 +10407,7 @@ multiaddr@7.2.1: is-ip "^3.1.0" varint "^5.0.0" -multibase@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.0.tgz#0216e350614c7456da5e8e5b20d3fcd4c9104f56" - integrity sha512-R9bNLQhbD7MsitPm1NeY7w9sDgu6d7cuj25snAWH7k5PSNPSwIQQBpcpj8jx1W96dLbdigZqmUWOdQRMnAmgjA== - dependencies: - base-x "3.0.4" - -multibase@~0.7.0: +multibase@^0.7.0, multibase@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== @@ -10404,6 +10415,13 @@ multibase@~0.7.0: base-x "^3.0.8" buffer "^5.5.0" +multibase@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.0.tgz#0216e350614c7456da5e8e5b20d3fcd4c9104f56" + integrity sha512-R9bNLQhbD7MsitPm1NeY7w9sDgu6d7cuj25snAWH7k5PSNPSwIQQBpcpj8jx1W96dLbdigZqmUWOdQRMnAmgjA== + dependencies: + base-x "3.0.4" + multicast-dns@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.0.tgz#7aa49a7efba931a346011aa02e7d1c314a65ac77" @@ -10412,6 +10430,14 @@ multicast-dns@^7.2.0: dns-packet "^4.0.0" thunky "^1.0.2" +multicodec@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.1.tgz#4e2812d726b9f7c7d615d3ebc5787d36a08680f9" + integrity sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw== + dependencies: + buffer "^5.5.0" + varint "^5.0.0" + multicodec@~0.5.0, multicodec@~0.5.1, multicodec@~0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.3.tgz#b1ef71a55d0698c9b2d89585f66e4b081f33c20c" @@ -10434,6 +10460,15 @@ multihashes@~0.4.12, multihashes@~0.4.13, multihashes@~0.4.14, multihashes@~0.4. bs58 "^4.0.1" varint "^5.0.0" +multihashes@~0.4.17, multihashes@~0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.19.tgz#d7493cf028e48747122f350908ea13d12d204813" + integrity sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A== + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + multihashing-async@^0.8.0, multihashing-async@~0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-0.8.0.tgz#a99049160be9bde6681fe93ef15e0e2496341d7d" @@ -14965,7 +15000,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -uri-to-multiaddr@3.0.1, uri-to-multiaddr@^3.0.1: +uri-to-multiaddr@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/uri-to-multiaddr/-/uri-to-multiaddr-3.0.1.tgz#460bd5d78074002c47b60fdc456efd009e7168ae" integrity sha512-77slJiNB/IxM35zgflBEgp8T8ywpyYAbEh8Ezdnq7kAuA6TRg6wfvNTi4Uixfh6CsPv9K2fAkI5+E4C2dw3tXA== From 5bce2a22f9e8879634b874cc636af2f1d1c4d694 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sun, 5 Apr 2020 19:04:05 +0200 Subject: [PATCH 12/12] test: findDNSLinkHostname without match --- test/functional/lib/dnslink.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/functional/lib/dnslink.test.js b/test/functional/lib/dnslink.test.js index f61fe7626..b62f5d768 100644 --- a/test/functional/lib/dnslink.test.js +++ b/test/functional/lib/dnslink.test.js @@ -217,13 +217,11 @@ describe('dnslinkResolver (dnslinkPolicy=enabled)', function () { spoofDnsTxtRecord(fqdn, dnslinkResolver, dnslinkValue) expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(fqdn) }) - /* TODO - it('should return null if no DNSLink record', function () { - const url = new URL(`https://no-dnslink.example.com/some/path?ds=sdads#dfsdf`) + it('should return nothing if no DNSLink record', function () { + const url = new URL('https://no-dnslink.example.com/some/path?ds=sdads#dfsdf') const dnslinkResolver = createDnslinkResolver(getState) expect(dnslinkResolver.findDNSLinkHostname(url)).to.equal(undefined) }) - */ it('should match /ipns/ on path gateway', function () { const fqdn = 'dnslink-site.com' const url = `https://path-gateway.com/ipns/${fqdn}/some/path?ds=sdads#dfsdf`