diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..eaeed682 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto + +*.cmd text eol=crlf +*.bat text eol=crlf +*.sh text eol=lf diff --git a/.gitignore b/.gitignore index fa3c6e08..c685e391 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,13 @@ +/node_modules/ +/lib/ + +/dist/lib/ +/dist/PrivacyPass/ +/dist/PrivacyPass.pem +/dist/PrivacyPass.crx* +/dist/PrivacyPass.xpi +/dist/.bin/**/temp/ + +/public/_locales/debug.en.txt + *.swp -/node_modules -/dist -/lib diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..e07341a9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,26 @@ +Copyright (c) 2017-2020, Privacy Pass Team, Cloudflare, Inc., and other contributors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 6b9d2a82..465eedc0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ $ npm ci $ npm run build ``` -After that, the `dist` folder will contain all files required by the extension. +After that, the `dist/PrivacyPass` folder will contain all files required by the extension. ## Development Installation @@ -47,7 +47,7 @@ After that, the `dist` folder will contain all files required by the extension. - Build by following the [Build Instruction](#build-instruction). - Open Firefox and go to `about:debugging#/runtime/this-firefox`. - Click on 'Load Temporary Add-on' button. -- Select `manifest.json` from `dist` folder. +- Select `manifest.json` from `dist/PrivacyPass` folder. - Check extension logo appears in the top-right corner and 0 passes are stored (by clicking on it). - Go to a web page supporting Privacy Pass where internet challenges @@ -68,7 +68,7 @@ After that, the `dist` folder will contain all files required by the extension. - Open Chrome and go to `chrome://extensions`. - Turn on the Developer mode on the top-right corner. - Click on 'Load unpacked' button. -- Select the `dist` folder. +- Select the `dist/PrivacyPass` folder. - Check extension logo appears in the top-right corner and follow the same instruction as in Firefox. (If you cannot see the extension logo, it's probably just not pinned to the toolbar yest) diff --git a/dist/.bin/.env/7zip.bat b/dist/.bin/.env/7zip.bat new file mode 100755 index 00000000..0840f988 --- /dev/null +++ b/dist/.bin/.env/7zip.bat @@ -0,0 +1,5 @@ +@echo off + +set ZIP7_HOME=C:\PortableApps\7-Zip\16.02\App\7-Zip64 + +set PATH=%ZIP7_HOME%;%PATH% diff --git a/dist/.bin/.env/build.bat b/dist/.bin/.env/build.bat new file mode 100755 index 00000000..7ac1f6bc --- /dev/null +++ b/dist/.bin/.env/build.bat @@ -0,0 +1,6 @@ +@echo off + +set PERL_HOME=C:\PortableApps\perl\5.10.1 +set MAKE_HOME=C:\PortableApps\make + +set PATH=%PERL_HOME%;%MAKE_HOME%;%PATH% diff --git a/dist/.bin/.env/build.sh b/dist/.bin/.env/build.sh new file mode 100755 index 00000000..fb3d1a3b --- /dev/null +++ b/dist/.bin/.env/build.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +PERL_HOME='/c/PortableApps/perl/5.10.1' +MAKE_HOME='/c/PortableApps/make' + +export PATH="${PERL_HOME}:${MAKE_HOME}:${PATH}" diff --git a/dist/.bin/.env/build_development.bat b/dist/.bin/.env/build_development.bat new file mode 100755 index 00000000..c75358d2 --- /dev/null +++ b/dist/.bin/.env/build_development.bat @@ -0,0 +1,3 @@ +@echo off + +set NODE_ENV=development diff --git a/dist/.bin/.env/build_development.sh b/dist/.bin/.env/build_development.sh new file mode 100755 index 00000000..04626cff --- /dev/null +++ b/dist/.bin/.env/build_development.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +export NODE_ENV='development' diff --git a/dist/.bin/.env/build_production.bat b/dist/.bin/.env/build_production.bat new file mode 100755 index 00000000..e36209d5 --- /dev/null +++ b/dist/.bin/.env/build_production.bat @@ -0,0 +1,3 @@ +@echo off + +set NODE_ENV=production diff --git a/dist/.bin/.env/build_production.sh b/dist/.bin/.env/build_production.sh new file mode 100755 index 00000000..a3f80413 --- /dev/null +++ b/dist/.bin/.env/build_production.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +export NODE_ENV='production' diff --git a/dist/.bin/.env/chrome_crx2.bat b/dist/.bin/.env/chrome_crx2.bat new file mode 100755 index 00000000..cdba0449 --- /dev/null +++ b/dist/.bin/.env/chrome_crx2.bat @@ -0,0 +1,10 @@ +@echo off + +rem :: =============================== +rem :: version of Chrome < 64.0.3242.0 +rem :: =============================== +rem :: https://sourceforge.net/projects/portableapps/files/Iron%20Portable/ +rem :: https://sourceforge.net/projects/portableapps/files/Iron%20Portable/IronPortable_61.0.3200.0.paf.exe/download +set CHROME_HOME=C:\PortableApps\SRWare Iron\61.0.3200.0\App\Iron + +set PATH=%CHROME_HOME%;%PATH% diff --git a/dist/.bin/.env/chrome_crx2.sh b/dist/.bin/.env/chrome_crx2.sh new file mode 100755 index 00000000..14a3d46f --- /dev/null +++ b/dist/.bin/.env/chrome_crx2.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# =============================== +# version of Chrome < 64.0.3242.0 +# =============================== +# https://sourceforge.net/projects/portableapps/files/Iron%20Portable/ +# https://sourceforge.net/projects/portableapps/files/Iron%20Portable/IronPortable_61.0.3200.0.paf.exe/download +CHROME_HOME='/c/PortableApps/SRWare Iron/61.0.3200.0/App/Iron' + +export PATH="${CHROME_HOME}:${PATH}" diff --git a/dist/.bin/.env/chrome_crx3.bat b/dist/.bin/.env/chrome_crx3.bat new file mode 100755 index 00000000..b1a8246e --- /dev/null +++ b/dist/.bin/.env/chrome_crx3.bat @@ -0,0 +1,16 @@ +@echo off + +rem :: ================================ +rem :: version of Chrome >= 64.0.3242.0 +rem :: ================================ +rem :: https://sourceforge.net/projects/portableapps/files/Google%20Chrome%20Portable/ +rem :: https://sourceforge.net/projects/portableapps/files/Google%20Chrome%20Portable/GoogleChromePortable64_97.0.4692.71_online.paf.exe/download +set CHROME_HOME=C:\PortableApps\Google Chrome\97.0.4692.71\App\Chrome-bin +rem :: https://sourceforge.net/projects/portableapps/files/Iron%20Portable/ +rem :: https://sourceforge.net/projects/portableapps/files/Iron%20Portable/IronPortable_85.0.4350.0.paf.exe/download +set CHROME_HOME=C:\PortableApps\SRWare Iron\85.0.4350.0\App\Iron +rem :: http://download1.srware.net/old/ +rem :: http://download1.srware.net/old/iron/win/85/IronPortable64.exe +set CHROME_HOME=C:\PortableApps\SRWare Iron\85.0.4350.0\Iron + +set PATH=%CHROME_HOME%;%PATH% diff --git a/dist/.bin/.env/chrome_crx3.sh b/dist/.bin/.env/chrome_crx3.sh new file mode 100755 index 00000000..905215c7 --- /dev/null +++ b/dist/.bin/.env/chrome_crx3.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# ================================ +# version of Chrome >= 64.0.3242.0 +# ================================ +# https://sourceforge.net/projects/portableapps/files/Google%20Chrome%20Portable/ +# https://sourceforge.net/projects/portableapps/files/Google%20Chrome%20Portable/GoogleChromePortable64_97.0.4692.71_online.paf.exe/download +CHROME_HOME='/c/PortableApps/Google Chrome/97.0.4692.71/App/Chrome-bin' +# https://sourceforge.net/projects/portableapps/files/Iron%20Portable/ +# https://sourceforge.net/projects/portableapps/files/Iron%20Portable/IronPortable_85.0.4350.0.paf.exe/download +CHROME_HOME='/c/PortableApps/SRWare Iron/85.0.4350.0/App/Iron' +# http://download1.srware.net/old/ +# http://download1.srware.net/old/iron/win/85/IronPortable64.exe +CHROME_HOME='/c/PortableApps/SRWare Iron/85.0.4350.0/Iron' + +export PATH="${CHROME_HOME}:${PATH}" diff --git a/dist/.bin/.env/constants.bat b/dist/.bin/.env/constants.bat new file mode 100755 index 00000000..1eae8136 --- /dev/null +++ b/dist/.bin/.env/constants.bat @@ -0,0 +1,3 @@ +@echo off + +set ext_name=PrivacyPass diff --git a/dist/.bin/.env/constants.sh b/dist/.bin/.env/constants.sh new file mode 100755 index 00000000..46ad511c --- /dev/null +++ b/dist/.bin/.env/constants.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +export ext_name='PrivacyPass' diff --git a/dist/.bin/.env/openssl.sh b/dist/.bin/.env/openssl.sh new file mode 100755 index 00000000..01ced177 --- /dev/null +++ b/dist/.bin/.env/openssl.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +OPENSSL_HOME='/c/PortableApps/OpenSSL/1.1.0' + +export PATH="${OPENSSL_HOME}:${PATH}" diff --git a/dist/.bin/build/build.bat b/dist/.bin/build/build.bat new file mode 100755 index 00000000..011d236f --- /dev/null +++ b/dist/.bin/build/build.bat @@ -0,0 +1,12 @@ +@echo off + +call "%~dp0..\.env\%~nx0" + +cd /D "%~dp0..\..\.." + +call npm run build + +if not defined BUILD_ALL ( + echo. + pause +) diff --git a/dist/.bin/build/build.sh b/dist/.bin/build/build.sh new file mode 100755 index 00000000..15cc0d49 --- /dev/null +++ b/dist/.bin/build/build.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/../.env/build.sh" + +cd "${DIR}/../../.." + +npm run build diff --git a/dist/.bin/build/build_development.bat b/dist/.bin/build/build_development.bat new file mode 100755 index 00000000..04d8b1ee --- /dev/null +++ b/dist/.bin/build/build_development.bat @@ -0,0 +1,4 @@ +@echo off + +call "%~dp0..\.env\%~nx0" +call "%~dp0.\build.bat" diff --git a/dist/.bin/build/build_development.sh b/dist/.bin/build/build_development.sh new file mode 100755 index 00000000..5e442594 --- /dev/null +++ b/dist/.bin/build/build_development.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/../.env/build_development.sh" +source "${DIR}/build.sh" diff --git a/dist/.bin/build/build_production.bat b/dist/.bin/build/build_production.bat new file mode 100755 index 00000000..04d8b1ee --- /dev/null +++ b/dist/.bin/build/build_production.bat @@ -0,0 +1,4 @@ +@echo off + +call "%~dp0..\.env\%~nx0" +call "%~dp0.\build.bat" diff --git a/dist/.bin/build/build_production.sh b/dist/.bin/build/build_production.sh new file mode 100755 index 00000000..8f43b00c --- /dev/null +++ b/dist/.bin/build/build_production.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/../.env/build_production.sh" +source "${DIR}/build.sh" diff --git a/dist/.bin/build_all.bat b/dist/.bin/build_all.bat new file mode 100755 index 00000000..f9ea539f --- /dev/null +++ b/dist/.bin/build_all.bat @@ -0,0 +1,13 @@ +@echo off + +set BUILD_ALL=1 + +call "%~dp0.\build\build.bat" +call "%~dp0.\pack extensions\chromium\crx3\pack_crx3_with_chrome.bat" +call "%~dp0.\pack extensions\firefox\pack_xpi_with_7zip.bat" + +call "%~dp0.\inject ES6 polyfills\inject_es6_polyfills.bat" +call "%~dp0.\pack extensions\chromium\crx2\pack_crx2_with_chrome.bat" + +echo. +pause diff --git a/dist/.bin/build_all.sh b/dist/.bin/build_all.sh new file mode 100755 index 00000000..9f49190d --- /dev/null +++ b/dist/.bin/build_all.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# configuration + +# 'USE_OPENSSL' determines how CRX2 and CRX3 extensions are built +# - any non-empty value will use: +# OpenSSL +# - an empty value will use: +# 2x different versions of Chrome +# 1x older for CRX2: < 64.0.3242.0 +# 1x newer for CRX3: >= 64.0.3242.0 +USE_OPENSSL='1' + +# ------------------------------------------------------------------------------ + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +"${DIR}/build/build.sh" +if [ -n "$USE_OPENSSL" ];then + "${DIR}/pack extensions/chromium/crx3/pack_crx3_with_openssl.sh" +else + "${DIR}/pack extensions/chromium/crx3/pack_crx3_with_chrome.sh" +fi +"${DIR}/pack extensions/firefox/pack_xpi_with_zip.sh" + +"${DIR}/inject ES6 polyfills/inject_es6_polyfills.sh" +if [ -n "$USE_OPENSSL" ];then + "${DIR}/pack extensions/chromium/crx2/pack_crx2_with_openssl.sh" +else + "${DIR}/pack extensions/chromium/crx2/pack_crx2_with_chrome.sh" +fi diff --git a/dist/.bin/build_all_development.bat b/dist/.bin/build_all_development.bat new file mode 100755 index 00000000..a41ac5dc --- /dev/null +++ b/dist/.bin/build_all_development.bat @@ -0,0 +1,4 @@ +@echo off + +call "%~dp0.\.env\build_development.bat" +call "%~dp0.\build_all.bat" diff --git a/dist/.bin/build_all_development.sh b/dist/.bin/build_all_development.sh new file mode 100755 index 00000000..f6d9b138 --- /dev/null +++ b/dist/.bin/build_all_development.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/.env/build_development.sh" +source "${DIR}/build_all.sh" diff --git a/dist/.bin/build_all_production.bat b/dist/.bin/build_all_production.bat new file mode 100755 index 00000000..d710e869 --- /dev/null +++ b/dist/.bin/build_all_production.bat @@ -0,0 +1,4 @@ +@echo off + +call "%~dp0.\.env\build_production.bat" +call "%~dp0.\build_all.bat" diff --git a/dist/.bin/build_all_production.sh b/dist/.bin/build_all_production.sh new file mode 100755 index 00000000..4197342b --- /dev/null +++ b/dist/.bin/build_all_production.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/.env/build_production.sh" +source "${DIR}/build_all.sh" diff --git a/dist/.bin/inject ES6 polyfills/README.md b/dist/.bin/inject ES6 polyfills/README.md new file mode 100644 index 00000000..49cf612b --- /dev/null +++ b/dist/.bin/inject ES6 polyfills/README.md @@ -0,0 +1,6 @@ +### ES6 Polyfills + +* adds [core-js](https://github.com/zloirock/core-js) to both the [background](../../../public/manifest.json) and [popup](../../../public/popup.html) pages + - using a local copy of a recent browser build, which was saved from [cdnjs](https://cdnjs.com/libraries/core-js) +* only needed to add support for very old browsers, which do not understand features that have since been added to the javascript (aka: ecmascript) scripting language + - for Chrome, this is only recommended for extensions packed in CRX2 format diff --git a/dist/.bin/inject ES6 polyfills/inject_es6_polyfills.bat b/dist/.bin/inject ES6 polyfills/inject_es6_polyfills.bat new file mode 100755 index 00000000..65aa1843 --- /dev/null +++ b/dist/.bin/inject ES6 polyfills/inject_es6_polyfills.bat @@ -0,0 +1,74 @@ +@echo off +setlocal enabledelayedexpansion + +call "%~dp0..\.env\constants.bat" +call "%~dp0..\.env\build.bat" + +if not defined ext_name ( + echo script configuration is invalid: + echo missing name of browser extension + exit /b 1 +) + +set ext_dir="%~dp0..\..\%ext_name%" + +if not exist %ext_dir% ( + echo Extension directory does not exist. + echo Perhaps the Typescript compiler build failed? + echo Quitting without making any changes. + exit /b 1 +) + +cd /D %ext_dir% + +if exist "%cd%\lib" ( + echo "lib" directory already exists in extension directory. + echo Has polyfill has already been injected? + echo Quitting without making any changes. + exit /b 1 +) + +xcopy /E /I /Q "%~dp0.\lib" "lib" + +set filepath=manifest.json +set "old_text="background.js"" +set "new_text="lib/core-js.js", "background.js"" +set flags= +call :perform_file_search_replace "%filepath%" "!old_text!" "!new_text!" "%flags%" + +set filepath=popup.html +set "old_text=o;)a(n,e=r[o++])&&(~c(i,e)||s(i,e));return i}},function(t,r,e){var c=e(11),f=e(57),s=e(59),e=function(u){return function(t,r,e){var n,o=c(t),i=s(o),a=f(e,i);if(u&&r!=r){for(;a"+t+"<\/script>"},g=function(){var t,r;try{i=new ActiveXObject("htmlfile")}catch(t){}for(g="undefined"==typeof document||document.domain&&i?o(i):((t=l("iframe")).style.display="none",s.appendChild(t),t.src=String("javascript:"),(t=t.contentWindow.document).open(),t.write(p("document.F=Object")),t.close(),t.F),r=c.length;r--;)delete g.prototype[c[r]];return g()};f[h]=!0,t.exports=Object.create||function(t,r){var e;return null!==t?(n.prototype=a(t),e=new n,n.prototype=null,e[h]=t):e=g(),r===Bt?e:u.f(e,r)}},function(t,r,e){var n=e(5),o=e(43),u=e(42),c=e(44),f=e(11),s=e(71);r.f=n&&!o?Object.defineProperties:function(t,r){var e,n,o,i,a;for(c(t),e=f(r),o=(n=s(r)).length,i=0;id)throw m(y);for(r=0;r=r.length?{value:t.target=Bt,done:!0}:"keys"==e?{value:n,done:!1}:"values"==e?{value:r[n],done:!1}:{value:[n,r[n]],done:!1}},"values"),i=i.Arguments=i.Array,o("keys"),o("values"),o("entries"),!f&&e&&"values"!==i.name)try{u(i,"name",{value:"values"})}catch(t){}},function(t,r,e){function d(){return this}var y=e(2),m=e(7),b=e(33),n=e(51),x=e(19),w=e(148),E=e(112),A=e(102),S=e(80),R=e(41),I=e(45),o=e(31),T=e(116),e=e(149),O=n.PROPER,M=n.CONFIGURABLE,P=e.IteratorPrototype,j=e.BUGGY_SAFARI_ITERATORS,k=o("iterator"),_="values",N="entries";t.exports=function(t,r,e,n,o,i,a){var u,c,f,s,l,h,p,g,v;if(w(e,r,n),c=r+" Iterator",f=!(u=function(t){if(t===o&&h)return h;if(!j&&t in s)return s[t];switch(t){case"keys":case _:case N:return function(){return new e(this,t)}}return function(){return new e(this)}}),l=(s=t.prototype)[k]||s["@@iterator"]||o&&s[o],h=!j&&l||u(o),(n="Array"==r&&s.entries||l)&&(p=E(n.call(new t)))!==Object.prototype&&p.next&&(b||E(p)===P||(A?A(p,P):x(p[k])||I(p,k,d)),S(p,c,!0,!0),b&&(T[c]=d)),O&&o==_&&l&&l.name!==_&&(!b&&M?R(s,"name",_):(f=!0,h=function(){return m(l,this)})),o)if(g={values:u(_),keys:i?h:u("keys"),entries:u(N)},a)for(v in g)!j&&!f&&v in s||I(s,v,g[v]);else y({target:r,proto:!0,forced:j||f},g);return b&&!a||s[k]===h||I(s,k,h,{name:o}),T[r]=h,g}},function(t,r,e){function o(){return this}var i=e(149).IteratorPrototype,a=e(69),u=e(10),c=e(80),f=e(116);t.exports=function(t,r,e,n){r+=" Iterator";return t.prototype=a(i,{next:u(+!n,e)}),c(t,r,!1,!0),f[r]=o,t}},function(t,r,e){var n,o=e(6),i=e(19),a=e(69),u=e(112),c=e(45),f=e(31),s=e(33),l=f("iterator"),e=!1;[].keys&&("next"in(f=[].keys())?(f=u(u(f)))!==Object.prototype&&(n=f):e=!0),n==Bt||o(function(){var t={};return n[l].call(t)!==t})?n={}:s&&(n=a(n)),i(n[l])||c(n,l,function(){return this}),t.exports={IteratorPrototype:n,BUGGY_SAFARI_ITERATORS:e}},function(t,r,e){var n=e(2),o=e(13),i=e(12),a=e(11),e=e(128),u=o([].join),i=i!=Object,e=e("join",",");n({target:"Array",proto:!0,forced:i||!e},{join:function(t){return u(a(this),t===Bt?",":t)}})},function(t,r,e){var n=e(2),e=e(152);n({target:"Array",proto:!0,forced:e!==[].lastIndexOf},{lastIndexOf:e})},function(t,r,e){var o=e(64),i=e(11),a=e(58),u=e(59),e=e(128),c=Math.min,f=[].lastIndexOf,s=!!f&&1/[1].lastIndexOf(1,-0)<0,e=e("lastIndexOf");t.exports=s||!e?function(t){var r,e,n;if(s)return o(f,this,arguments)||0;for(r=i(this),n=(e=u(r))-1,(n=1s(r)?1:-1})),o=e.length,i=0;i0;)t[n]=t[--n];n!==i++&&(t[n]=e)}return t}(t,r):function(t,r,e,n){for(var o=r.length,i=e.length,a=0,u=0;a>8&255]}function i(t){return[255&t,t>>8&255,t>>16&255,t>>24&255]}function a(t){return t[3]<<24|t[2]<<16|t[1]<<8|t[0]}function u(t){return J(t,23,4)}function c(t){return J(t,52,8)}function f(t,r,e,n){var o=T(e),e=F(t);if(o+r>e.byteLength)throw H(z);return t=F(e.buffer).bytes,r=N(t,e=o+e.byteOffset,e+r),n?r:$(r)}function s(t,r,e,n,o,i){var a,u,c,f,e=T(e),t=F(t);if(e+r>t.byteLength)throw H(z);for(a=F(t.buffer).bytes,u=e+t.byteOffset,c=n(+o),f=0;fp;)(g=h[p++])in Y||w(Y,g,W[g]);V.constructor=Y}P&&M(q)!==D&&P(q,D),D=new x(new Y(2)),v=y(q.setInt8),D.setInt8(0,2147483648),D.setInt8(1,2147483649),!D.getInt8(0)&&D.getInt8(1)||E(q,{setInt8:function(t,r){v(this,t,r<<24>>24)},setUint8:function(t,r){v(this,t,r<<24>>24)}},{unsafe:!0})}else V=(Y=function(t){S(this,V);t=T(t);B(this,{bytes:K(G(t),0),byteLength:t}),m||(this.byteLength=t)}).prototype,q=(x=function(t,r,e){var n;if(S(this,q),S(t,V),n=F(t).byteLength,(r=R(r))<0||nn)throw H("Wrong length");B(this,{buffer:t,byteLength:e,byteOffset:r}),m||(this.buffer=t,this.byteLength=e,this.byteOffset=r)}).prototype,m&&(O(Y,"byteLength"),O(x,"buffer"),O(x,"byteLength"),O(x,"byteOffset")),E(q,{getInt8:function(t){return f(this,1,t)[0]<<24>>24},getUint8:function(t){return f(this,1,t)[0]},getInt16:function(t){t=f(this,2,t,1>16},getUint16:function(t){t=f(this,2,t,1>>0},getFloat32:function(t){return X(f(this,4,t,1>1,f=23===r?g(2,-24)-g(2,-77):0,s=t<0||0===t&&1/t<0?1:0,l=0;for((t=p(t))!=t||t===1/0?(o=t!=t?1:0,n=u):(n=v(d(t)/y),t*(e=g(2,-n))<1&&(n--,e*=2),2<=(t+=1<=n+c?f/e:f*g(2,1-c))*e&&(n++,e/=2),u<=n+c?(o=0,n=u):1<=n+c?(o=(t*e-1)*g(2,r),n+=c):(o=t*g(2,c-1)*g(2,r),n=0));8<=r;)i[l++]=255&o,o/=256,r-=8;for(n=n<>1,u=o-7,c=n-1,n=t[c--],f=127&n;for(n>>=7;0>=-u,u+=r;0r&&(e=f(e,0,r)),o?n+e:e+n)}};t.exports={start:n(!1),end:n(!0)}},function(t,r,e){var n=e(3),o=e(58),i=e(66),a=e(15),u=n.RangeError;t.exports=function(t){var r=i(a(this)),e="",n=o(t);if(n<0||n==1/0)throw u("Wrong number of repetitions");for(;0>>=1)&&(r+=r))1&n&&(e+=r);return e}},function(t,r,e){var n=e(2),o=e(6),i=e(37),a=e(17);n({target:"Date",proto:!0,forced:o(function(){return null!==new Date(NaN).toJSON()||1!==Date.prototype.toJSON.call({toISOString:function(){return 1}})})},{toJSON:function(t){var r=i(this),e=a(r,"number");return"number"!=typeof e||isFinite(e)?r.toISOString():null}})},function(t,r,e){var n=e(36),o=e(45),i=e(195),a=e(31)("toPrimitive"),e=Date.prototype;n(e,a)||o(e,a,i)},function(t,r,e){var n=e(3),o=e(44),i=e(30),a=n.TypeError;t.exports=function(t){if(o(this),"string"===t||"default"===t)t="string";else if("number"!==t)throw a("Incorrect hint");return i(this,t)}},function(t,r,e){var n=e(13),o=e(45),e=Date.prototype,i="Invalid Date",a=n(e.toString),u=n(e.getTime);String(new Date(NaN))!=i&&o(e,"toString",function(){var t=u(this);return t==t?a(this):i})},function(t,r,e){function a(t,r){for(var e=i(t,16);e.length>>=0)?31-n(o(t+.5)*i):32}})},function(t,r,e){var n=e(2),o=e(220),e=Math.cosh,i=Math.abs,a=Math.E;n({target:"Math",stat:!0,forced:!e||e(710)===1/0},{cosh:function(t){t=o(i(t)-1)+1;return(t+1/(t*a*a))*(a/2)}})},function(t,r){var e=Math.expm1,n=Math.exp;t.exports=!e||22025.465794806718u||r!=r?e*(1/0):e*r}},function(t,r,e){var n=e(2),e=Math.hypot,c=Math.abs,f=Math.sqrt;n({target:"Math",stat:!0,forced:!!e&&e(1/0,NaN)!==1/0},{hypot:function(t,r){for(var e,n,o=0,i=0,a=arguments.length,u=0;i>>16)*r+t*(e&o>>>16)<<16>>>0)}})},function(t,r,e){e(2)({target:"Math",stat:!0},{log10:e(227)})},function(t,r){var e=Math.log,n=Math.LOG10E;t.exports=Math.log10||function(t){return e(t)*n}},function(t,r,e){e(2)({target:"Math",stat:!0},{log1p:e(213)})},function(t,r,e){var e=e(2),n=Math.log,o=Math.LN2;e({target:"Math",stat:!0},{log2:function(t){return n(t)/o}})},function(t,r,e){e(2)({target:"Math",stat:!0},{sign:e(217)})},function(t,r,e){var n=e(2),o=e(6),i=e(220),a=Math.abs,u=Math.exp,c=Math.E;n({target:"Math",stat:!0,forced:o(function(){return-2e-17!=Math.sinh(-2e-17)})},{sinh:function(t){return a(t=+t)<1?(i(t)-i(-t))/2:(u(t-1)-u(-t-1))*(c/2)}})},function(t,r,e){var n=e(2),o=e(220),i=Math.exp;n({target:"Math",stat:!0},{tanh:function(t){var r=o(t=+t),e=o(-t);return r==1/0?1:e==1/0?-1:(r-e)/(i(t)+i(-t))}})},function(t,r,e){e(80)(Math,"Math",!0)},function(t,r,e){var e=e(2),n=Math.ceil,o=Math.floor;e({target:"Math",stat:!0},{trunc:function(t){return(0i;i++)h(A,a=o[i])&&!h(n,a)&&x(n,a,b(A,a));l(c,"Number",(n.prototype=S).constructor=n)}},function(t,r,e){e=e(13);t.exports=e(1..valueOf)},function(t,r,e){var n=e(13),o=e(15),i=e(66),e=e(238),a=n("".replace),e="["+e+"]",u=RegExp("^"+e+e+"*"),c=RegExp(e+e+"*$"),e=function(r){return function(t){t=i(o(t));return 1&r&&(t=a(t,u,"")),t=2&r?a(t,c,""):t}};t.exports={start:e(1),end:e(2),trim:e(3)}},function(t,r){t.exports="\t\n\v\f\r                 \u2028\u2029\ufeff"},function(t,r,e){e(2)({target:"Number",stat:!0},{EPSILON:Math.pow(2,-52)})},function(t,r,e){e(2)({target:"Number",stat:!0},{isFinite:e(241)})},function(t,r,e){var n=e(3).isFinite;t.exports=Number.isFinite||function(t){return"number"==typeof t&&n(t)}},function(t,r,e){e(2)({target:"Number",stat:!0},{isInteger:e(243)})},function(t,r,e){var n=e(18),o=Math.floor;t.exports=Number.isInteger||function(t){return!n(t)&&isFinite(t)&&o(t)===t}},function(t,r,e){e(2)({target:"Number",stat:!0},{isNaN:function(t){return t!=t}})},function(t,r,e){var n=e(2),o=e(243),i=Math.abs;n({target:"Number",stat:!0},{isSafeInteger:function(t){return o(t)&&i(t)<=9007199254740991}})},function(t,r,e){e(2)({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991})},function(t,r,e){e(2)({target:"Number",stat:!0},{MIN_SAFE_INTEGER:-9007199254740991})},function(t,r,e){var n=e(2),e=e(249);n({target:"Number",stat:!0,forced:Number.parseFloat!=e},{parseFloat:e})},function(t,r,e){var n=e(3),o=e(6),i=e(13),a=e(66),u=e(237).trim,e=e(238),c=i("".charAt),f=n.parseFloat,n=n.Symbol,s=n&&n.iterator,o=1/f(e+"-0")!=-1/0||s&&!o(function(){f(Object(s))});t.exports=o?function(t){var r=u(a(t)),t=f(r);return 0===t&&"-"==c(r,0)?-0:t}:f},function(t,r,e){var n=e(2),e=e(251);n({target:"Number",stat:!0,forced:Number.parseInt!=e},{parseInt:e})},function(t,r,e){var n=e(3),o=e(6),i=e(13),a=e(66),u=e(237).trim,e=e(238),c=n.parseInt,n=n.Symbol,f=n&&n.iterator,s=/^[+-]?0x/i,l=i(s.exec),o=8!==c(e+"08")||22!==c(e+"0x16")||f&&!o(function(){c(Object(f))});t.exports=o?function(t,r){t=u(a(t));return c(t,r>>>0||(l(s,t)?16:10))}:c},function(t,r,e){var n=e(2),o=e(3),i=e(13),f=e(58),s=e(236),a=e(192),l=e(227),e=e(6),h=o.RangeError,p=o.String,g=o.isFinite,v=Math.abs,d=Math.floor,y=Math.pow,m=Math.round,b=i(1..toExponential),x=i(a),w=i("".slice),E="-6.9000e-11"===b(-69e-12,4)&&"1.25e+0"===b(1.255,2)&&"1.235e+4"===b(12345,3)&&"3e+1"===b(25,0),i=e(function(){b(1,1/0)})&&e(function(){b(1,-1/0)}),e=!e(function(){b(1/0,1/0)})&&!e(function(){b(NaN,1/0)});n({target:"Number",proto:!0,forced:!E||!i||!e},{toExponential:function(t){var r,e,n,o,i,a,u,c=s(this);if(t===Bt)return b(c);if(r=f(t),!g(c))return p(c);if(r<0||20=(2*(t=m(c/u))+1)*u&&(t+=1),t>=y(10,r+1)&&(t/=10,o+=1),p(t)),0!==r&&(n=w(n,0,1)+"."+w(n,1)),a=0===o?(i="+","0"):(i=0u;)(e=o(n,r=i[u++]))!==Bt&&l(a,r,e);return a}})},function(t,r,e){var n=e(2),o=e(6),e=e(73).f;n({target:"Object",stat:!0,forced:o(function(){return!Object.getOwnPropertyNames(1)})},{getOwnPropertyNames:e})},function(t,r,e){var n=e(2),o=e(6),i=e(37),a=e(112),e=e(113);n({target:"Object",stat:!0,forced:o(function(){a(1)}),sham:!e},{getPrototypeOf:function(t){return a(i(t))}})},function(t,r,e){e(2)({target:"Object",stat:!0},{hasOwn:e(36)})},function(t,r,e){e(2)({target:"Object",stat:!0},{is:e(273)})},function(t,r){t.exports=Object.is||function(t,r){return t===r?0!==t||1/t==1/r:t!=t&&r!=r}},function(t,r,e){var n=e(2),e=e(208);n({target:"Object",stat:!0,forced:Object.isExtensible!==e},{isExtensible:e})},function(t,r,e){var n=e(2),o=e(6),i=e(18),a=e(14),u=e(209),c=Object.isFrozen;n({target:"Object",stat:!0,forced:o(function(){c(1)})||u},{isFrozen:function(t){return!i(t)||!(!u||"ArrayBuffer"!=a(t))||!!c&&c(t)}})},function(t,r,e){var n=e(2),o=e(6),i=e(18),a=e(14),u=e(209),c=Object.isSealed;n({target:"Object",stat:!0,forced:o(function(){c(1)})||u},{isSealed:function(t){return!i(t)||!(!u||"ArrayBuffer"!=a(t))||!!c&&c(t)}})},function(t,r,e){var n=e(2),o=e(37),i=e(71);n({target:"Object",stat:!0,forced:e(6)(function(){i(1)})},{keys:function(t){return i(o(t))}})},function(t,r,e){var n=e(2),o=e(5),i=e(259),a=e(37),u=e(16),c=e(112),f=e(4).f;o&&n({target:"Object",proto:!0,forced:i},{__lookupGetter__:function(t){var r,e=a(this),n=u(t);do{if(r=f(e,n))return r.get}while(e=c(e))}})},function(t,r,e){var n=e(2),o=e(5),i=e(259),a=e(37),u=e(16),c=e(112),f=e(4).f;o&&n({target:"Object",proto:!0,forced:i},{__lookupSetter__:function(t){var r,e=a(this),n=u(t);do{if(r=f(e,n))return r.set}while(e=c(e))}})},function(t,r,e){var n=e(2),o=e(18),i=e(207).onFreeze,a=e(210),e=e(6),u=Object.preventExtensions;n({target:"Object",stat:!0,forced:e(function(){u(1)}),sham:!a},{preventExtensions:function(t){return u&&o(t)?u(i(t)):t}})},function(t,r,e){var n=e(2),o=e(18),i=e(207).onFreeze,a=e(210),e=e(6),u=Object.seal;n({target:"Object",stat:!0,forced:e(function(){u(1)}),sham:!a},{seal:function(t){return u&&o(t)?u(i(t)):t}})},function(t,r,e){e(2)({target:"Object",stat:!0},{setPrototypeOf:e(102)})},function(t,r,e){var n=e(68),o=e(45),e=e(284);n||o(Object.prototype,"toString",e,{unsafe:!0})},function(t,r,e){var n=e(68),o=e(67);t.exports=n?{}.toString:function(){return"[object "+o(this)+"]"}},function(t,r,e){var n=e(2),o=e(264).values;n({target:"Object",stat:!0},{values:function(t){return o(t)}})},function(t,r,e){var n=e(2),e=e(249);n({global:!0,forced:parseFloat!=e},{parseFloat:e})},function(t,r,e){var n=e(2),e=e(251);n({global:!0,forced:parseInt!=e},{parseInt:e})},function(t,r,e){function i(t,r){var e,n,o,i,a=r.value,u=1==r.state,c=u?t.ok:t.fail,f=t.resolve,s=t.reject,l=t.domain;try{c?(u||(2===r.rejection&&(i=r,p(T,h,function(){var t=i.facade;L?$.emit("rejectionHandled",t):ot("rejectionhandled",t,i.value)})),r.rejection=1),!0===c?e=a:(l&&l.enter(),e=c(a),l&&(l.exit(),o=!0)),e===t.promise?s(H("Promise-chain cycle")):(n=et(e))?p(n,e,f,s):f(e)):s(a)}catch(t){l&&!o&&l.exit(),s(t)}}var n,o,a,u,c=e(2),f=e(33),h=e(3),s=e(21),p=e(7),l=e(289),g=e(45),v=e(175),d=e(102),y=e(80),m=e(168),b=e(28),x=e(19),w=e(18),E=e(176),A=e(46),S=e(114),R=e(142),I=e(182),T=e(290).set,O=e(292),M=e(295),P=e(297),j=e(296),k=e(298),_=e(299),N=e(47),U=e(63),D=e(31),C=e(300),L=e(157),F=e(25),B=D("species"),z="Promise",W=N.getterFor(z),Y=N.set,V=N.getterFor(z),N=l&&l.prototype,q=l,G=N,H=h.TypeError,K=h.document,$=h.process,J=j.f,X=J,Q=!!(K&&K.createEvent&&h.dispatchEvent),Z=x(h.PromiseRejectionEvent),tt="unhandledrejection",rt=!1,U=U(z,function(){var t,r=A(q),e=r!==String(q);return!e&&66===F||!(!f||G.finally)||!(51<=F&&/native code/.test(r))&&(t=function(t){t(function(){},function(){})},((r=new q(function(t){t(1)})).constructor={})[B]=t,!(rt=r.then(function(){})instanceof t)||!e&&C&&!Z)}),R=U||!R(function(t){q.all(t).catch(function(){})}),et=function(t){var r;return!(!w(t)||!x(r=t.then))&&r},nt=function(e,o){e.notified||(e.notified=!0,O(function(){for(var t,n,r=e.reactions;t=r.get();)i(t,e);e.notified=!1,o&&!e.rejection&&(n=e,p(T,h,function(){var t,r=n.facade,e=n.value;if(it(n)&&(t=k(function(){L?$.emit("unhandledRejection",e,r):ot(tt,r,e)}),n.rejection=L||it(n)?2:1,t.error))throw t.value}))}))},ot=function(t,r,e){var n,o;Q?((n=K.createEvent("Event")).promise=r,n.reason=e,n.initEvent(t,!1,!0),h.dispatchEvent(n)):n={promise:r,reason:e},!Z&&(o=h["on"+t])?o(n):t===tt&&P("Unhandled promise rejection",e)},it=function(t){return 1!==t.rejection&&!t.parent},at=function(r,e,n){return function(t){r(e,t,n)}},ut=function(t,r,e){t.done||(t.done=!0,(t=e?e:t).value=r,t.state=2,nt(t,!0))},ct=function(e,t,r){if(!e.done){e.done=!0,r&&(e=r);try{if(e.facade===t)throw H("Promise can't be resolved itself");var n=et(t);n?O(function(){var r={done:!1};try{p(n,t,at(ct,r,e),at(ut,r,e))}catch(t){ut(r,t,e)}}):(e.value=t,e.state=1,nt(e,!1))}catch(t){ut({done:!1},t,e)}}};if(U&&(q=function(t){E(this,G),b(t),p(n,this);var r=W(this);try{t(at(ct,r),at(ut,r))}catch(t){ut(r,t)}},(n=function(t){Y(this,{type:z,done:!1,notified:!1,parent:!1,reactions:new _,rejection:!1,state:0,value:Bt})}).prototype=v(G=q.prototype,{then:function(t,r){var e=V(this),n=J(I(this,q));return e.parent=!0,n.ok=!x(t)||t,n.fail=x(r)&&r,n.domain=L?$.domain:Bt,0==e.state?e.reactions.add(n):O(function(){i(n,e)}),n.promise},catch:function(t){return this.then(Bt,t)}}),o=function(){var t=new n,r=W(t);this.promise=t,this.resolve=at(ct,r),this.reject=at(ut,r)},j.f=J=function(t){return t===q||t===a?new o:X(t)},!f&&x(l)&&N!==Object.prototype)){u=N.then,rt||(g(N,"then",function(t,r){var e=this;return new q(function(t,r){p(u,e,t,r)}).then(t,r)},{unsafe:!0}),g(N,"catch",G.catch,{unsafe:!0}));try{delete N.constructor}catch(t){}d&&d(N,G)}c({global:!0,wrap:!0,forced:U},{Promise:q}),y(q,z,!1,!0),m(z),a=s(z),c({target:z,stat:!0,forced:U},{reject:function(t){var r=J(this);return p(r.reject,Bt,t),r.promise}}),c({target:z,stat:!0,forced:f||U},{resolve:function(t){return M(f&&this===a?q:this,t)}}),c({target:z,stat:!0,forced:R},{all:function(t){var u=this,r=J(u),c=r.resolve,f=r.reject,e=k(function(){var n=b(u.resolve),o=[],i=0,a=1;S(t,function(t){var r=i++,e=!1;a++,p(n,u,t).then(function(t){e||(e=!0,o[r]=t,--a||c(o))},f)}),--a||c(o)});return e.error&&f(e.value),r.promise},race:function(t){var e=this,n=J(e),o=n.reject,r=k(function(){var r=b(e.resolve);S(t,function(t){p(r,e,t).then(n.resolve,o)})});return r.error&&o(r.value),n.promise}})},function(t,r,e){e=e(3);t.exports=e.Promise},function(t,r,e){var n,o,i,a,u,c=e(3),f=e(64),s=e(82),l=e(19),h=e(36),p=e(6),g=e(72),v=e(76),d=e(40),y=e(291),m=e(157),b=c.setImmediate,x=c.clearImmediate,w=c.process,E=c.Dispatch,A=c.Function,S=c.MessageChannel,R=c.String,I=0,T={};try{n=c.location}catch(t){}i=function(t){var r;h(T,t)&&(r=T[t],delete T[t],r())},a=function(t){return function(){i(t)}},u=function(t){i(t.data)},e=function(t){c.postMessage(R(t),n.protocol+"//"+n.host)},b&&x||(b=function(t){var r=v(arguments,1);return T[++I]=function(){f(l(t)?t:A(t),Bt,r)},o(I),I},x=function(t){delete T[t]},m?o=function(t){w.nextTick(a(t))}:E&&E.now?o=function(t){E.now(a(t))}:S&&!y?(S=(y=new S).port2,y.port1.onmessage=u,o=s(S.postMessage,S)):c.addEventListener&&l(c.postMessage)&&!c.importScripts&&n&&"file:"!==n.protocol&&!p(e)?(o=e,c.addEventListener("message",u,!1)):o="onreadystatechange"in d("script")?function(t){g.appendChild(d("script")).onreadystatechange=function(){g.removeChild(this),i(t)}}:function(t){setTimeout(a(t),0)}),t.exports={set:b,clear:x}},function(t,r,e){e=e(26);t.exports=/(?:ipad|iphone|ipod).*applewebkit/i.test(e)},function(t,r,e){var n,o,i,a,u,c,f,s=e(3),l=e(82),h=e(4).f,p=e(290).set,g=e(291),v=e(293),d=e(294),y=e(157),m=s.MutationObserver||s.WebKitMutationObserver,b=s.document,x=s.process,e=s.Promise,h=h(s,"queueMicrotask"),h=h&&h.value;h||(n=function(){var t,r;for(y&&(t=x.domain)&&t.exit();o;){r=o.fn,o=o.next;try{r()}catch(t){throw o?a():i=Bt,t}}i=Bt,t&&t.enter()},a=g||y||d||!m||!b?!v&&e&&e.resolve?((v=e.resolve(Bt)).constructor=e,f=l(v.then,v),function(){f(n)}):y?function(){x.nextTick(n)}:(p=l(p,s),function(){p(n)}):(u=!0,c=b.createTextNode(""),new m(n).observe(c,{characterData:!0}),function(){c.data=u=!u})),t.exports=h||function(t){t={fn:t,next:Bt};i&&(i.next=t),o||(o=t,a()),i=t}},function(t,r,e){var n=e(26),e=e(3);t.exports=/ipad|iphone|ipod/i.test(n)&&e.Pebble!==Bt},function(t,r,e){e=e(26);t.exports=/web0s(?!.*chrome)/i.test(e)},function(t,r,e){var n=e(44),o=e(18),i=e(296);t.exports=function(t,r){return n(t),o(r)&&r.constructor===t?r:((0,(t=i.f(t)).resolve)(r),t.promise)}},function(t,r,e){function n(t){var e,n;this.promise=new t(function(t,r){if(e!==Bt||n!==Bt)throw TypeError("Bad Promise constructor");e=t,n=r}),this.resolve=o(e),this.reject=o(n)}var o=e(28);t.exports.f=function(t){return new n(t)}},function(t,r,e){var n=e(3);t.exports=function(t,r){var e=n.console;e&&e.error&&(1==arguments.length?e.error(t):e.error(t,r))}},function(t,r){t.exports=function(t){try{return{error:!1,value:t()}}catch(t){return{error:!0,value:t}}}},function(t,r){function e(){this.head=null,this.tail=null}e.prototype={add:function(t){t={item:t,next:null};this.head?this.tail.next=t:this.head=t,this.tail=t},get:function(){var t=this.head;if(t)return this.head=t.next,this.tail===t&&(this.tail=null),t.item}},t.exports=e},function(t,r){t.exports="object"==typeof window},function(t,r,e){var n=e(2),f=e(7),s=e(28),o=e(296),i=e(298),l=e(114);n({target:"Promise",stat:!0},{allSettled:function(t){var u=this,r=o.f(u),c=r.resolve,e=r.reject,n=i(function(){var n=s(u.resolve),o=[],i=0,a=1;l(t,function(t){var r=i++,e=!1;a++,f(n,u,t).then(function(t){e||(e=!0,o[r]={status:"fulfilled",value:t},--a||c(o))},function(t){e||(e=!0,o[r]={status:"rejected",reason:t},--a||c(o))})}),--a||c(o)});return n.error&&e(n.value),r.promise}})},function(t,r,e){var n=e(2),h=e(28),o=e(21),p=e(7),i=e(296),a=e(298),g=e(114),v="No one promise resolved";n({target:"Promise",stat:!0},{any:function(t){var c=this,f=o("AggregateError"),r=i.f(c),s=r.resolve,l=r.reject,e=a(function(){var n=h(c.resolve),o=[],i=0,a=1,u=!1;g(t,function(t){var r=i++,e=!1;a++,p(n,c,t).then(function(t){e||u||(u=!0,s(t))},function(t){e||u||(e=!0,o[r]=t,--a||l(new f(o,v)))})}),--a||l(new f(o,v))});return e.error&&l(e.value),r.promise}})},function(t,r,e){var n=e(2),o=e(33),i=e(289),a=e(6),u=e(21),c=e(19),f=e(182),s=e(295),e=e(45);n({target:"Promise",proto:!0,real:!0,forced:!!i&&a(function(){i.prototype.finally.call({then:function(){}},function(){})})},{finally:function(r){var e=f(this,u("Promise")),t=c(r);return this.then(t?function(t){return s(e,r()).then(function(){return t})}:r,t?function(t){return s(e,r()).then(function(){throw t})}:r)}}),!o&&c(i)&&(o=u("Promise").prototype.finally,i.prototype.finally!==o&&e(i.prototype,"finally",o,{unsafe:!0}))},function(t,r,e){var n=e(2),o=e(64),i=e(28),a=e(44);n({target:"Reflect",stat:!0,forced:!e(6)(function(){Reflect.apply(function(){})})},{apply:function(t,r,e){return o(i(t),r,a(e))}})},function(t,r,e){var n=e(2),o=e(21),i=e(64),a=e(199),u=e(183),c=e(44),f=e(18),s=e(69),e=e(6),l=o("Reflect","construct"),h=Object.prototype,p=[].push,g=e(function(){function t(){}return!(l(function(){},[],t)instanceof t)}),v=!e(function(){l(function(){})}),e=g||v;n({target:"Reflect",stat:!0,forced:e,sham:e},{construct:function(t,r){var e,n;if(u(t),c(r),n=arguments.length<3?t:u(arguments[2]),v&&!g)return l(t,r,n);if(t!=n)return e=s(f(n=n.prototype)?n:h),n=i(t,e,r),f(n)?n:e;switch(r.length){case 0:return new t;case 1:return new t(r[0]);case 2:return new t(r[0],r[1]);case 3:return new t(r[0],r[1],r[2]);case 4:return new t(r[0],r[1],r[2],r[3])}return i(p,e=[null],r),new(i(a,t,e))}})},function(t,r,e){var n=e(2),o=e(5),i=e(44),a=e(16),u=e(42);n({target:"Reflect",stat:!0,forced:e(6)(function(){Reflect.defineProperty(u.f({},1,{value:1}),1,{value:2})}),sham:!o},{defineProperty:function(t,r,e){i(t);r=a(r);i(e);try{return u.f(t,r,e),!0}catch(t){return!1}}})},function(t,r,e){var n=e(2),o=e(44),i=e(4).f;n({target:"Reflect",stat:!0},{deleteProperty:function(t,r){var e=i(o(t),r);return!(e&&!e.configurable)&&delete t[r]}})},function(t,r,e){var n=e(2),i=e(7),a=e(18),u=e(44),c=e(309),f=e(4),s=e(112);n({target:"Reflect",stat:!0},{get:function t(r,e){var n,o=arguments.length<3?r:arguments[2];return u(r)===o?r[e]:(n=f.f(r,e))?c(n)?n.value:n.get===Bt?Bt:i(n.get,o):a(r=s(r))?t(r,e,o):Bt}})},function(t,r,e){var n=e(36);t.exports=function(t){return t!==Bt&&(n(t,"value")||n(t,"writable"))}},function(t,r,e){var n=e(2),o=e(5),i=e(44),a=e(4);n({target:"Reflect",stat:!0,sham:!o},{getOwnPropertyDescriptor:function(t,r){return a.f(i(t),r)}})},function(t,r,e){var n=e(2),o=e(44),i=e(112);n({target:"Reflect",stat:!0,sham:!e(113)},{getPrototypeOf:function(t){return i(o(t))}})},function(t,r,e){e(2)({target:"Reflect",stat:!0},{has:function(t,r){return r in t}})},function(t,r,e){var n=e(2),o=e(44),i=e(208);n({target:"Reflect",stat:!0},{isExtensible:function(t){return o(t),i(t)}})},function(t,r,e){e(2)({target:"Reflect",stat:!0},{ownKeys:e(53)})},function(t,r,e){var n=e(2),o=e(21),i=e(44);n({target:"Reflect",stat:!0,sham:!e(210)},{preventExtensions:function(t){i(t);try{var r=o("Object","preventExtensions");return r&&r(t),!0}catch(t){return!1}}})},function(t,r,e){var n=e(2),u=e(7),c=e(44),f=e(18),s=e(309),o=e(6),l=e(42),h=e(4),p=e(112),g=e(10);n({target:"Reflect",stat:!0,forced:o(function(){function t(){}var r=l.f(new t,"a",{configurable:!0});return!1!==Reflect.set(t.prototype,"a",1,r)})},{set:function t(r,e,n){var o,i=arguments.length<4?r:arguments[3],a=h.f(c(r),e);if(!a){if(f(o=p(r)))return t(o,e,n,i);a=g(0)}if(s(a)){if(!1===a.writable||!f(i))return!1;if(o=h.f(i,e)){if(o.get||o.set||!1===o.writable)return!1;o.value=n,l.f(i,e,o)}else l.f(i,e,g(0,n))}else{if((a=a.set)===Bt)return!1;u(a,i,n)}return!0}})},function(t,r,e){var n=e(2),o=e(44),i=e(103),a=e(102);a&&n({target:"Reflect",stat:!0},{setPrototypeOf:function(t,r){o(t),i(r);try{return a(t,r),!0}catch(t){return!1}}})},function(t,r,e){var n=e(2),o=e(3),e=e(80);n({global:!0},{Reflect:{}}),e(o.Reflect,"Reflect",!0)},function(t,r,e){var f,n,o,i,a=e(5),u=e(3),c=e(13),s=e(63),l=e(104),h=e(41),p=e(42).f,g=e(54).f,v=e(22),d=e(320),y=e(66),m=e(321),b=e(322),x=e(45),w=e(6),E=e(36),A=e(47).enforce,S=e(168),R=e(31),I=e(323),T=e(324),O=R("match"),M=u.RegExp,P=M.prototype,j=u.SyntaxError,k=c(m),_=c(P.exec),N=c("".charAt),U=c("".replace),D=c("".indexOf),C=c("".slice),L=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,F=/a/g,B=/a/g,c=new M(F)!==F,z=b.MISSED_STICKY,W=b.UNSUPPORTED_Y;if(s("RegExp",a&&(!c||z||I||T||w(function(){return B[O]=!1,M(F)!=F||M(B)==B||"/a/i"!=M(F,"i")})))){for(f=function(t,r){var e,n,o=v(P,this),i=d(t),a=r===Bt,u=[],c=t;if(!o&&i&&a&&t.constructor===f)return t;if((i||v(P,t))&&(t=t.source,a&&(r="flags"in c?c.flags:k(c))),t=t===Bt?"":y(t),r=r===Bt?"":y(r),c=t,i=r=I&&"dotAll"in F&&(e=!!r&&-1"===r&&c:if(""===s||E(a,s))throw new j("Invalid capture group name");a[s]=!0,c=!(i[i.length]=[s,f]),s="";continue}c?s+=r:o+=r}return[o,i]}(t))[0],u=a[1]),r=l(M(t,r),o?this:P,f),(e||n||u.length)&&(o=A(r),e&&(o.dotAll=!0,o.raw=f(function(t){for(var r,e=t.length,n=0,o="",i=!1;n<=e;n++)"\\"!==(r=N(t,n))?i||"."!==r?("["===r?i=!0:"]"===r&&(i=!1),o+=r):o+="[\\s\\S]":o+=r+N(t,++n);return o}(t),i)),n&&(o.sticky=!0),u.length&&(o.groups=u)),t!==c)try{h(r,"source",""===c?"(?:)":c)}catch(t){}return r},n=function(r){r in f||p(f,r,{configurable:!0,get:function(){return M[r]},set:function(t){M[r]=t}})},o=g(M),i=0;o.length>i;)n(o[i++]);(P.constructor=f).prototype=P,x(u,"RegExp",f)}S("RegExp")},function(t,r,e){var n=e(18),o=e(14),i=e(31)("match");t.exports=function(t){var r;return n(t)&&((r=t[i])!==Bt?!!r:"RegExp"==o(t))}},function(t,r,e){var n=e(44);t.exports=function(){var t=n(this),r="";return t.global&&(r+="g"),t.ignoreCase&&(r+="i"),t.multiline&&(r+="m"),t.dotAll&&(r+="s"),t.unicode&&(r+="u"),t.sticky&&(r+="y"),r}},function(t,r,e){var n=e(6),o=e(3).RegExp,i=n(function(){var t=o("a","y");return t.lastIndex=2,null!=t.exec("abcd")}),e=i||n(function(){return!o("a","y").sticky}),n=i||n(function(){var t=o("^r","gy");return t.lastIndex=2,null!=t.exec("str")});t.exports={BROKEN_CARET:n,MISSED_STICKY:e,UNSUPPORTED_Y:i}},function(t,r,e){var n=e(6),o=e(3).RegExp;t.exports=n(function(){var t=o(".","s");return!(t.dotAll&&t.exec("\n")&&"s"===t.flags)})},function(t,r,e){var n=e(6),o=e(3).RegExp;t.exports=n(function(){var t=o("(?b)","g");return"b"!==t.exec("b").groups.a||"bc"!=="b".replace(t,"$c")})},function(t,r,e){var n=e(3),o=e(5),i=e(323),a=e(14),u=e(42).f,c=e(47).get,f=RegExp.prototype,s=n.TypeError;o&&i&&u(f,"dotAll",{configurable:!0,get:function(){if(this===f)return Bt;if("RegExp"===a(this))return!!c(this).dotAll;throw s("Incompatible receiver, RegExp required")}})},function(t,r,e){var n=e(2),e=e(327);n({target:"RegExp",proto:!0,forced:/./.exec!==e},{exec:e})},function(t,r,e){var g=e(7),n=e(13),v=e(66),d=e(321),o=e(322),i=e(32),y=e(69),m=e(47).get,a=e(323),e=e(324),b=i("native-string-replace","".replace),x=/t/.exec,w=x,E=n("".charAt),A=n("".indexOf),S=n("".replace),R=n("".slice),I=(i=/b*/g,g(x,n=/a/,"a"),g(x,i,"a"),0!==n.lastIndex||0!==i.lastIndex),T=o.BROKEN_CARET,O=/()??/.exec("")[1]!==Bt;(I||O||T||a||e)&&(w=function(t){var r,e,n,o,i,a,u,c,f,s=this,l=m(s),h=v(t),p=l.raw;if(p)return p.lastIndex=s.lastIndex,f=g(w,p,h),s.lastIndex=p.lastIndex,f;if(u=l.groups,c=T&&s.sticky,t=g(d,s),p=s.source,f=0,l=h,c&&(t=S(t,"y",""),-1===A(t,"g")&&(t+="g"),l=R(h,s.lastIndex),0>10),r%1024+56320)}return f(e,"")}})},function(t,r,e){var n=e(2),o=e(13),i=e(337),a=e(15),u=e(66),e=e(338),c=o("".indexOf);n({target:"String",proto:!0,forced:!e("includes")},{includes:function(t){return!!~c(u(a(this)),u(i(t)),1=r.length?{value:Bt,done:!0}:(e=n(r,e),t.index+=e.length,{value:e,done:!1})})},function(t,r,e){var o=e(7),n=e(343),f=e(44),s=e(60),l=e(66),i=e(15),a=e(27),h=e(344),p=e(345);n("match",function(n,u,c){return[function(t){var r=i(this),e=t==Bt?Bt:a(t,n);return e?o(e,t,r):new RegExp(t)[n](l(r))},function(t){var r,e,n,o,i=f(this),a=l(t),t=c(u,i,a);if(t.done)return t.value;if(!i.global)return p(i,a);for(r=i.unicode,e=[],n=i.lastIndex=0;null!==(o=p(i,a));)o=l(o[0]),""===(e[n]=o)&&(i.lastIndex=h(a,s(i.lastIndex),r)),n++;return 0===n?null:e}]})},function(t,r,e){var c,f,s,l,h,p,g,v;e(326),c=e(13),f=e(45),s=e(327),l=e(6),h=e(31),p=e(41),g=h("species"),v=RegExp.prototype,t.exports=function(e,t,r,n){var a,o=h(e),u=!l(function(){var t={};return t[o]=function(){return 7},7!=""[e](t)}),i=u&&!l(function(){var t=!1,r=/a/;return"split"===e&&((r={}).constructor={},r.constructor[g]=function(){return r},r.flags="",r[o]=/./[o]),r.exec=function(){return t=!0,null},r[o](""),!t});u&&i&&!r||(a=c(/./[o]),t=t(o,""[e],function(t,r,e,n,o){var i=c(t),t=r.exec;return t===s||t===v.exec?u&&!o?{done:!0,value:a(r,e,n)}:{done:!0,value:i(e,r,n)}:{done:!1}}),f(String.prototype,e,t[0]),f(v,o,t[1])),n&&p(v[o],"sham",!0)}},function(t,r,e){var n=e(335).charAt;t.exports=function(t,r,e){return r+(e?n(t,r).length:1)}},function(t,r,e){var n=e(3),o=e(7),i=e(44),a=e(19),u=e(14),c=e(327),f=n.TypeError;t.exports=function(t,r){var e=t.exec;if(a(e))return null!==(e=o(e,t,r))&&i(e),e;if("RegExp"===u(t))return o(c,t,r);throw f("RegExp#exec called on incompatible receiver")}},function(t,r,e){function n(t){var r=h(this),e=l(t),n=w(r,RegExp),t=(o=(o=r.flags)===Bt&&g(P,r)&&!("flags"in P)?k(r):o)===Bt?"":l(o),o=new n(n===RegExp?r.source:r,t),n=!!~_(t,"g"),t=!!~_(t,"u");return o.lastIndex=s(r.lastIndex),new D(o,e,n,t)}var o=e(2),i=e(3),a=e(7),u=e(13),c=e(148),f=e(15),s=e(60),l=e(66),h=e(44),p=e(14),g=e(22),v=e(320),d=e(321),y=e(27),m=e(45),b=e(6),x=e(31),w=e(182),E=e(344),A=e(345),S=e(47),R=e(33),I=x("matchAll"),T="RegExp String Iterator",O=S.set,M=S.getterFor(T),P=RegExp.prototype,j=i.TypeError,k=u(d),_=u("".indexOf),N=u("".matchAll),U=!!N&&!b(function(){N("a",/./)}),D=c(function(t,r,e,n){O(this,{type:T,regexp:t,string:r,global:e,unicode:n,done:!1})},"RegExp String",function(){var t,r,e,n=M(this);return n.done?{value:Bt,done:!0}:null===(e=A(t=n.regexp,r=n.string))?{value:Bt,done:n.done=!0}:(n.global?""===l(e[0])&&(t.lastIndex=E(r,s(t.lastIndex),n.unicode)):n.done=!0,{value:e,done:!1})});o({target:"String",proto:!0,forced:U},{matchAll:function(t){var r,e=f(this);if(null!=t){if(v(t)&&(r=l(f("flags"in P?t.flags:k(t))),!~_(r,"g")))throw j("`.matchAll` does not allow non-global regexes");if(U)return N(e,t);if(r=(r=y(t,I))===Bt&&R&&"RegExp"==p(t)?n:r)return a(r,t,e)}else if(U)return N(e,t);return e=l(e),t=new RegExp(t,"g"),R?a(n,t,e):t[I](e)}}),R||I in P||m(P,I,n)},function(t,r,e){var n=e(2),o=e(191).end;n({target:"String",proto:!0,forced:e(348)},{padEnd:function(t){return o(this,t,1")})||!n||s)},function(t,r,e){var n=e(13),o=e(37),h=Math.floor,p=n("".charAt),g=n("".replace),v=n("".slice),d=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,y=/\$([$&'`]|\d{1,2})/g;t.exports=function(i,a,u,c,f,t){var s=u+i.length,l=c.length,r=y;return f!==Bt&&(f=o(f),r=d),g(t,r,function(t,r){var e,n,o;switch(p(r,0)){case"$":return"$";case"&":return i;case"`":return v(a,0,u);case"'":return v(a,s);case"<":e=f[v(r,1,-1)];break;default:if(0==(n=+r))return t;if(lt.length?-1:""===r?e:T(t,r,e)}var n=e(2),o=e(3),v=e(7),i=e(13),d=e(15),y=e(19),m=e(320),b=e(66),x=e(27),a=e(321),w=e(353),u=e(31),E=e(33),A=u("replace"),S=RegExp.prototype,R=o.TypeError,I=i(a),T=i("".indexOf),O=i("".replace),M=i("".slice),P=Math.max;n({target:"String",proto:!0},{replaceAll:function(t,r){var e,n,o,i,a,u,c,f,s=d(this),l=0,h=0,p="";if(null!=t){if((e=m(t))&&(n=b(d("flags"in S?t.flags:I(t))),!~T(n,"g")))throw R("`.replaceAll` does not allow non-global regexes");if(n=x(t,A))return v(n,t,s,r);if(E&&e)return O(b(s),t,r)}for(o=b(s),i=b(t),(a=y(r))||(r=b(r)),c=P(1,u=i.length),l=g(o,i,0);-1!==l;)f=a?b(r(i,l,o)):w(i,o,l,[],Bt,r),p+=M(o,h,l)+f,h=l+u,l=g(o,i,l+c);return h>>0;if(0==f)return[];if(t===Bt)return[c];if(!h(t))return l(p,c,t,f);for(e=[],n=0,o=new RegExp(t.source,(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":"")+"g");(i=l(S,o,c))&&!((a=o.lastIndex)>n&&(M(e,P(c,n,i.index)),1>>0))return[];if(0===h.length)return null===A(n,h)?[h]:[];for(a=i=0,u=[];a=(e=s(t+r,o))?"":c(n,t,e)}})},function(t,r,e){var n=e(2),o=e(237).trim;n({target:"String",proto:!0,forced:e(360)("trim")},{trim:function(){return o(this)}})},function(t,r,e){var n=e(51).PROPER,o=e(6),i=e(238);t.exports=function(t){return o(function(){return!!i[t]()||"​…᠎"!=="​…᠎"[t]()||n&&i[t].name!==t})}},function(t,r,e){var n=e(2),o=e(237).end,i=e(360)("trimEnd"),e=i?function(){return o(this)}:"".trimEnd;n({target:"String",proto:!0,name:"trimEnd",forced:i},{trimEnd:e,trimRight:e})},function(t,r,e){var n=e(2),o=e(237).start,i=e(360)("trimStart"),e=i?function(){return o(this)}:"".trimStart;n({target:"String",proto:!0,name:"trimStart",forced:i},{trimStart:e,trimLeft:e})},function(t,r,e){var n=e(2),o=e(364);n({target:"String",proto:!0,forced:e(365)("anchor")},{anchor:function(t){return o(this,"a","name",t)}})},function(t,r,e){var n=e(13),i=e(15),a=e(66),u=/"/g,c=n("".replace);t.exports=function(t,r,e,n){var o=a(i(t)),t="<"+r;return""!==e&&(t+=" "+e+'="'+c(a(n),u,""")+'"'),t+">"+o+""}},function(t,r,e){var n=e(6);t.exports=function(r){return n(function(){var t=""[r]('"');return t!==t.toLowerCase()||3e)throw z(Z);c=u/s}else c=w(r),a=new W(u=c*s);for(C(t,{buffer:a,byteOffset:i,byteLength:u,length:c,view:new V(a)});ot)throw f("Wrong length");for(;o>>=0,e>>>=0;return(r>>>0)+(n>>>0)+((t&e|(t|e)&~(t+e>>>0))>>>31)|0}})},function(t,r,e){e(2)({target:"Math",stat:!0},{imulh:function(t,r){var e=+t,n=+r,t=65535&e,r=65535&n,e=e>>16,n=n>>16,r=(e*r>>>0)+(t*r>>>16);return e*n+(r>>16)+((t*n>>>0)+(65535&r)>>16)}})},function(t,r,e){e(2)({target:"Math",stat:!0},{isubh:function(t,r,e,n){t>>>=0,e>>>=0;return(r>>>0)-(n>>>0)-((~t&e|~(t^e)&t-e>>>0)>>>31)|0}})},function(t,r,e){e(2)({target:"Math",stat:!0},{RAD_PER_DEG:180/Math.PI})},function(t,r,e){var e=e(2),n=Math.PI/180;e({target:"Math",stat:!0},{radians:function(t){return t*n}})},function(t,r,e){e(2)({target:"Math",stat:!0},{scale:e(525)})},function(t,r,e){var n=e(2),o=e(3),i=e(44),a=e(241),u=e(148),e=e(47),c="Seeded Random Generator",f=e.set,s=e.getterFor(c),l=o.TypeError,h=u(function(t){f(this,{type:c,seed:t%2147483647})},"Seeded Random",function(){var t=s(this);return{value:(1073741823&(t.seed=(1103515245*t.seed+12345)%2147483647))/1073741823,done:!1}});n({target:"Math",stat:!0,forced:!0},{seededPRNG:function(t){t=i(t).seed;if(!a(t))throw l('Math.seededPRNG() argument should have a "seed" field with a finite value.');return new h(t)}})},function(t,r,e){e(2)({target:"Math",stat:!0},{signbit:function(t){return(t=+t)==t&&0==t?1/t==-1/0:t<0}})},function(t,r,e){e(2)({target:"Math",stat:!0},{umulh:function(t,r){var e=+t,n=+r,t=65535&e,r=65535&n,e=e>>>16,n=n>>>16,r=(e*r>>>0)+(t*r>>>16);return e*n+(r>>>16)+((t*n>>>0)+(65535&r)>>>16)}})},function(t,r,e){var n=e(2),o=e(3),i=e(13),a=e(58),u=e(251),c="Invalid number representation",f=o.RangeError,s=o.SyntaxError,l=o.TypeError,h=/^[\da-z]+$/,p=i("".charAt),g=i(h.exec),v=i(1..toString),d=i("".slice);n({target:"Number",stat:!0},{fromString:function(t,r){var e,n=1;if("string"!=typeof t)throw l(c);if(!t.length)throw s(c);if("-"==p(t,0)&&(n=-1,!(t=d(t,1)).length))throw s(c);if((r=r===Bt?10:a(r))<2||36=n.length)return e.object=e.keys=null,{value:Bt,done:!0};if(t=n[e.index++],i(r=e.object,t)){switch(e.mode){case"keys":return{value:t,done:!1};case"values":return{value:r[t],done:!1}}return{value:[t,r[t]],done:!1}}}})},function(t,r,e){var n=e(2),o=e(539);n({target:"Object",stat:!0},{iterateKeys:function(t){return new o(t,"keys")}})},function(t,r,e){var n=e(2),o=e(539);n({target:"Object",stat:!0},{iterateValues:function(t){return new o(t,"values")}})},function(t,r,e){function a(t){this.observer=d(t),this.cleanup=Bt,this.subscriptionObserver=Bt}var n,u,i,o,c=e(2),f=e(3),s=e(7),l=e(5),h=e(168),p=e(28),g=e(19),v=e(85),d=e(44),y=e(18),m=e(176),b=e(42).f,x=e(45),w=e(175),E=e(117),A=e(27),S=e(114),R=e(297),I=e(31),T=e(47),O=I("observable"),M="Observable",e="Subscription",P="SubscriptionObserver",I=T.getterFor,j=T.set,k=I(M),_=I(e),N=I(P),U=f.Array;a.prototype={type:e,clean:function(){var t=this.cleanup;if(t){this.cleanup=Bt;try{t()}catch(t){R(t)}}},close:function(){var t;l||(t=this.subscriptionObserver,this.facade.closed=!0,t&&(t.closed=!0)),this.observer=Bt},isClosed:function(){return this.observer===Bt}},(n=function(r,t){var e,n,o,i=j(this,new a(r));l||(this.closed=!1);try{(e=A(r,"start"))&&s(e,r,this)}catch(t){R(t)}if(!i.isClosed()){r=i.subscriptionObserver=new u(i);try{n=t(r),null!=(o=n)&&(i.cleanup=g(n.unsubscribe)?function(){o.unsubscribe()}:p(n))}catch(t){return void r.error(t)}i.isClosed()&&i.clean()}}).prototype=w({},{unsubscribe:function(){var t=_(this);t.isClosed()||(t.close(),t.clean())}}),l&&b(n.prototype,"closed",{configurable:!0,get:function(){return _(this).isClosed()}}),(u=function(t){j(this,{type:P,subscriptionState:t}),l||(this.closed=!1)}).prototype=w({},{next:function(t){var r,e=N(this).subscriptionState;if(!e.isClosed()){e=e.observer;try{(r=A(e,"next"))&&s(r,e,t)}catch(t){R(t)}}},error:function(t){var r,e,n=N(this).subscriptionState;if(!n.isClosed()){r=n.observer,n.close();try{(e=A(r,"error"))?s(e,r,t):R(t)}catch(t){R(t)}n.clean()}},complete:function(){var t,r,e=N(this).subscriptionState;if(!e.isClosed()){t=e.observer,e.close();try{(r=A(t,"complete"))&&s(r,t)}catch(t){R(t)}e.clean()}}}),l&&b(u.prototype,"closed",{configurable:!0,get:function(){return N(this).subscriptionState.isClosed()}}),w(o=(i=function(t){m(this,o),j(this,{type:M,subscriber:p(t)})}).prototype,{subscribe:function(t){var r=arguments.length;return new n(g(t)?{next:t,error:1=r.length?{value:Bt,done:!0}:(r=f(r,e),t.index+=r.length,{value:{codePoint:c(r,0),position:e},done:!1})});n({target:"String",proto:!0},{codePoints:function(){return new p(a(i(this)))}})},function(t,r,e){e(346)},function(t,r,e){e(354)},function(t,r,e){e(78)("asyncDispose")},function(t,r,e){e(78)("dispose")},function(t,r,e){e(78)("matcher")},function(t,r,e){e(78)("metadata")},function(t,r,e){e(78)("observable")},function(t,r,e){e(78)("patternMatch")},function(t,r,e){e(78)("replaceAll")},function(t,r,e){var i=e(21),a=e(183),u=e(427),n=e(380),o=e(180),c=e(398),f=o.aTypedArrayConstructor;(0,o.exportTypedArrayStaticMethod)("fromAsync",function(r){var e=this,t=arguments.length,n=1?@[\\\]^|]/,J=/[\0\t\n\r #/:<>?@[\\\]^|]/,X=/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g,Q=/[\t\n\r]/g,tt=function(t){var r,e,n,o,i,a,u,c=U(t,".");if(c.length&&""==c[c.length-1]&&c.length--,4<(r=c.length))return t;for(e=[],n=0;n=I(256,5-r))return null}else if(255":1,"`":1}),at=Lt({},it,{"#":1,"?":1,"{":1,"}":1}),ut=Lt({},at,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),ct=function(t,r){var e=l(t,0);return 32=h&&rx((y-p)/(i=n+1)))throw b(m);for(p+=(o-h)*i,h=o,v=0;vy)throw b(m);if(r==h){for(a=p,u=36;!(a<(f=u<=g?1:g+26<=u?26:u-g));)S(s,w(d(f+(c=a-f)%(f=36-f)))),a=x(c/f),u+=36;S(s,w(d(a))),g=function(t,r,e){var n=0;for(t=e?x(t/700):t>>1,t+=x(t/r);455r.key?1:-1}),t.updateURL()},forEach:function(t){for(var r,e=M(this).entries,n=g(t,1 " + exit 1 + fi + + ext_dir=$1 + ext_key=$2 + crx="${ext_dir}.crx2.crx" + name=$(basename "$ext_dir") + pub="${name}.pub" + sig="${name}.sig" + zip="${name}.zip" + + if [ ! -d "$ext_dir" ];then + echo 'error: extension directory path does not exist' + exit 1 + fi + + if [ ! -f "$ext_key" ];then + echo 'error: pem file path does not exist' + exit 1 + fi + + echo "writing ${name}.crx2.crx" + + # preparation: remove previous crx + rm -f "$crx" + + # preparation: remove all previous temporary files in the cwd + rm -f "$pub" "$sig" "$zip" + + # cleanup: remove all temporary files in the cwd + trap 'rm -f "$pub" "$sig" "$zip"' EXIT + + # zip up the crx dir + cwd=$(pwd -P) + (cd "$ext_dir" && zip -qr -9 -X "${cwd}/${zip}" .) + + # signature + openssl sha1 -sha1 -binary -sign "$ext_key" < "$zip" > "$sig" + + # public key + openssl rsa -pubout -outform DER < "$ext_key" > "$pub" 2>/dev/null + + crmagic_hex='4372 3234' # Cr24 + version_hex='0200 0000' # 2 + pub_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$pub" | awk '{print $5}'))) + sig_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$sig" | awk '{print $5}'))) + ( + echo "${crmagic_hex} ${version_hex} ${pub_len_hex} ${sig_len_hex}" | xxd -r -p + cat "$pub" "$sig" "$zip" + ) > "$crx" + + echo 'success: crx2 Chrome extension has been packed' +} + +# ------------------------------------------------------------------------------ +# bootstrap + +function main { + cd "${DIR}/../../../.." + cwd=$(pwd -P) + ext_dir="${cwd}/${ext_name}" + ext_key="${cwd}/${ext_name}.pem" + + TMP="${DIR}/temp" + [ -d "$TMP" ] && rm -rf "$TMP" + mkdir "$TMP" + + cd "$TMP" + pack_crx2 "$ext_dir" "$ext_key" + + # cleanup: remove temporary directory + cd "$DIR" + rm -rf "$TMP" +} + +main diff --git a/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_chrome.bat b/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_chrome.bat new file mode 100755 index 00000000..80e9ed97 --- /dev/null +++ b/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_chrome.bat @@ -0,0 +1,16 @@ +@echo off + +call "%~dp0..\..\..\.env\constants.bat" +call "%~dp0..\..\..\.env\chrome_crx3.bat" +call "%~dp0..\.common\pack_crx_with_chrome.bat" + +set crx_path=%~dp0..\..\..\..\%ext_name% + +if exist "%crx_path%.crx" ( + ren "%crx_path%.crx" "%ext_name%.crx3.crx" +) + +if not defined BUILD_ALL ( + echo. + pause +) diff --git a/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_chrome.sh b/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_chrome.sh new file mode 100755 index 00000000..40c0710a --- /dev/null +++ b/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_chrome.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/../../../.env/constants.sh" +source "${DIR}/../../../.env/chrome_crx3.sh" +source "${DIR}/../.common/pack_crx_with_chrome.sh" + +crx_path="${DIR}/../../../../${ext_name}" + +if [ -f "${crx_path}.crx" ];then + mv "${crx_path}.crx" "${crx_path}.crx3.crx" +fi diff --git a/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_openssl.sh b/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_openssl.sh new file mode 100755 index 00000000..92f32fd8 --- /dev/null +++ b/dist/.bin/pack extensions/chromium/crx3/pack_crx3_with_openssl.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/../../../.env/constants.sh" +source "${DIR}/../../../.env/openssl.sh" + +if [ -z "$ext_name" ];then + echo 'script configuration is invalid:' + echo 'missing name of browser extension' + exit 1 +fi + +# ------------------------------------------------------------------------------ +# Source: https://stackoverflow.com/a/18709204 +# Purpose: Pack a Chromium extension directory into crx3 format +# notes: all temporary files are created in the cwd. +# the final crx is created adjacent to the input extension directory. + +function pack_crx3 { + if test $# -ne 2; then + echo "Usage: crxmake.sh " + exit 1 + fi + + ext_dir=$1 + ext_key=$2 + crx="${ext_dir}.crx3.crx" + name=$(basename "$ext_dir") + pub="${name}.pub" + sig="${name}.sig" + zip="${name}.zip" + tosign="${name}.presig" + binary_crx_id="${name}.crxid" + + if [ ! -d "$ext_dir" ];then + echo 'error: extension directory path does not exist' + exit 1 + fi + + if [ ! -f "$ext_key" ];then + echo 'error: pem file path does not exist' + exit 1 + fi + + echo "writing ${name}.crx3.crx" + + # preparation: remove previous crx + rm -f "$crx" + + # preparation: remove all previous temporary files in the cwd + rm -f "$pub" "$sig" "$zip" "$tosign" "$binary_crx_id" + + # cleanup: remove all temporary files in the cwd + trap 'rm -f "$pub" "$sig" "$zip" "$tosign" "$binary_crx_id"' EXIT + + # zip up the crx dir + cwd=$(pwd -P) + (cd "$ext_dir" && zip -qr -9 -X "${cwd}/${zip}" .) + + #extract crx id + openssl rsa -in "$ext_key" -pubout -outform der | openssl dgst -sha256 -binary -out "$binary_crx_id" + truncate -s 16 "$binary_crx_id" + + #generate file to sign + ( + # echo "$crmagic_hex $version_hex $header_length $pub_len_hex $sig_len_hex" + printf "CRX3 SignedData" + echo "00 12 00 00 00 0A 10" | xxd -r -p + cat "$binary_crx_id" "$zip" + ) > "$tosign" + + # signature + openssl dgst -sha256 -binary -sign "$ext_key" < "$tosign" > "$sig" + + # public key + openssl rsa -pubout -outform DER < "$ext_key" > "$pub" 2>/dev/null + + crmagic_hex='43 72 32 34' # Cr24 + version_hex='03 00 00 00' # 3 + header_length='45 02 00 00' + header_chunk_1='12 AC 04 0A A6 02' + header_chunk_2='12 80 02' + header_chunk_3='82 F1 04 12 0A 10' + ( + echo "${crmagic_hex} ${version_hex} ${header_length} ${header_chunk_1}" | xxd -r -p + cat "$pub" + echo "$header_chunk_2" | xxd -r -p + cat "$sig" + echo "$header_chunk_3" | xxd -r -p + cat "$binary_crx_id" "$zip" + ) > "$crx" + + echo 'success: crx3 Chrome extension has been packed' +} + +# ------------------------------------------------------------------------------ +# bootstrap + +function main { + cd "${DIR}/../../../.." + cwd=$(pwd -P) + ext_dir="${cwd}/${ext_name}" + ext_key="${cwd}/${ext_name}.pem" + + TMP="${DIR}/temp" + [ -d "$TMP" ] && rm -rf "$TMP" + mkdir "$TMP" + + cd "$TMP" + pack_crx3 "$ext_dir" "$ext_key" + + # cleanup: remove temporary directory + cd "$DIR" + rm -rf "$TMP" +} + +main diff --git a/dist/.bin/pack extensions/firefox/docs/installing-unsigned-extensions-permanently-to-firefox.md b/dist/.bin/pack extensions/firefox/docs/installing-unsigned-extensions-permanently-to-firefox.md new file mode 100644 index 00000000..46a5d4bd --- /dev/null +++ b/dist/.bin/pack extensions/firefox/docs/installing-unsigned-extensions-permanently-to-firefox.md @@ -0,0 +1,62 @@ +- - - - + +# Add-on signing in Firefox + +### What are my options if I want to use an unsigned add-on? + +Firefox [Extended Support Release (ESR)](https://www.mozilla.org/firefox/organizations/), Firefox [Developer Edition](https://www.mozilla.org/firefox/developer/) and [Nightly](https://nightly.mozilla.org/) versions of Firefox will allow you to override the setting to enforce the extension signing requirement, by changing the preference `xpinstall.signatures.required` to __false__ in the [Firefox Configuration Editor](https://support.mozilla.org/en-US/kb/about-config-editor-firefox) (`about:config` page). To override the language pack signing requirement, you would set the preference `extensions.langpacks.signatures.required` to __false__. There are also special unbranded versions of Firefox that allow this override. See the MozillaWiki article, [Add-ons/Extension Signing](https://wiki.mozilla.org/Add-ons/Extension_Signing) for more information. + +> The source of this post can be found: +> * [here](https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox?#w_what-are-my-options-if-i-want-to-use-an-unsigned-add-on-advanced-users) in HTML format + +- - - - + +# Installing unsigned extensions permanently to Firefox + +2020-11-26 + +If you have worked with browser extension on Firefox, you likely go to `about:debugging` for installing the extensions temporary, while useful for development, the extension gets removed once Firefox restarts. + +Sometimes you may need to test how the extension behaves when Firefox starts, or, just want to leave your extension installed without signing it with the Developer Hub. + + +## Summary + +Gladly, there is a simple solution: +1. Update your extension manifest to include custom `browser_specific_settings`. +2. Disable signature checks while installing extensions. +3. Package your extension as a zip file. +4. Install the extension. +5. Enable signature checks while installing extensions. + + +### Step 1 +Update your `manifest.json` to include a new key, the `id` could be any email: + +```json +"browser_specific_settings": { + "gecko": { + "id": "test@gmail.com" + } +} +``` + +### Step 2 +Go to `about:config`, change `xpinstall.signatures.required` to `false`. + +### Step 3 +Simply run `zip -r -FS ../my-extension.zip * --exclude '*.git*'`. + +### Step 4 +Go to `about:addons`, and choose the `Install Add-on from file` option, choose the zip file created in the previous step. + +### Step 5 +Go to `about:config`, change `xpinstall.signatures.required` to `true`. + +That's it, you have installed an unsigned extension permanently. + +> The source of this post can be found: +> * [here](https://wiringbits.net/browser-extensions/2020/11/27/installing-unsigned-extensions-permanently-to-firefox.html) in HTML format +> * [here](https://github.com/wiringbits/wiringbits.github.io/blob/4f08ae14f53df32809420675d36b21deca081401/_posts/2020-11-26-installing-unsigned-extensions-permanently-to-firefox.md) in Markdown format + +- - - - diff --git a/dist/.bin/pack extensions/firefox/pack_xpi_with_7zip.bat b/dist/.bin/pack extensions/firefox/pack_xpi_with_7zip.bat new file mode 100755 index 00000000..3a367686 --- /dev/null +++ b/dist/.bin/pack extensions/firefox/pack_xpi_with_7zip.bat @@ -0,0 +1,32 @@ +@echo off + +call "%~dp0..\..\.env\constants.bat" +call "%~dp0..\..\.env\7zip.bat" + +if not defined ext_name ( + echo script configuration is invalid: + echo missing name of browser extension + exit /b 1 +) + +cd /D "%~dp0..\..\.." + +set ext_dir="%cd%\%ext_name%" +set ext_xpi="%cd%\%ext_name%.xpi" + +if not exist %ext_dir% ( + echo Extension directory does not exist. + echo Perhaps the Typescript compiler build failed? + exit /b 1 +) + +cd %ext_dir% + +rem :: https://sevenzip.osdn.jp/chm/cmdline/index.htm +rem :: https://sevenzip.osdn.jp/chm/cmdline/commands/add.htm +7z a -tzip %ext_xpi% -r . + +if not defined BUILD_ALL ( + echo. + pause +) diff --git a/dist/.bin/pack extensions/firefox/pack_xpi_with_zip.sh b/dist/.bin/pack extensions/firefox/pack_xpi_with_zip.sh new file mode 100755 index 00000000..a5811826 --- /dev/null +++ b/dist/.bin/pack extensions/firefox/pack_xpi_with_zip.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/../../.env/constants.sh" + +if [ -z "$ext_name" ];then + echo 'script configuration is invalid:' + echo 'missing name of browser extension' + exit 1 +fi + +# ------------------------------------------------------------------------------ +# bootstrap + +function main { + cd "${DIR}/../../.." + cwd=$(pwd -P) + + ext_dir="${cwd}/${ext_name}" + ext_xpi="${cwd}/${ext_name}.xpi" + + if [ ! -d "$ext_dir" ];then + echo 'Extension directory does not exist.' + echo 'Perhaps the Typescript compiler build failed?' + exit 1 + fi + + cd "$ext_dir" + + # https://extensionworkshop.com/documentation/publish/package-your-extension/#package-linux + zip -r -FS "$ext_xpi" * +} + +main diff --git a/dist/.bin/run_tests.bat b/dist/.bin/run_tests.bat new file mode 100644 index 00000000..c56759ed --- /dev/null +++ b/dist/.bin/run_tests.bat @@ -0,0 +1,12 @@ +@echo off + +call "%~dp0.\.env\build.bat" + +cd /D "%~dp0..\.." + +call npm run test + +if not defined BUILD_ALL ( + echo. + pause +) diff --git a/dist/.bin/run_tests.sh b/dist/.bin/run_tests.sh new file mode 100644 index 00000000..5c8f8c9e --- /dev/null +++ b/dist/.bin/run_tests.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source "${DIR}/.env/build.sh" + +cd "${DIR}/../.." + +npm run test diff --git a/jest.setup.ts b/jest.setup.ts index 5e0b2c0f..3b373b7d 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -1,6 +1,10 @@ // Mocking crypto with Node webcrypto API. + +// Requires Node v15.0+ +// https://nodejs.org/api/crypto.html#cryptowebcrypto + import { webcrypto } from 'crypto'; if (typeof crypto === 'undefined') { - global.crypto = (webcrypto as unknown) as Crypto + global.crypto = (webcrypto as unknown) as Crypto; } diff --git a/package-lock.json b/package-lock.json index c1a870e7..3945f93f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,34 +1,35 @@ { "name": "privacy-pass", - "version": "3.0.0", + "version": "3.7.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "privacy-pass", - "version": "3.0.0", + "version": "3.7.0", "license": "BSD-3-Clause", "dependencies": { "asn1-parser": "^1.1.8", "axios": "^0.23.0", "buffer": "^6.0.3", - "keccak": "^3.0.1", + "keccak": "^3.0.2", "qs": "^6.10.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.5", "redux": "^4.1.1", - "sjcl": "^1.0.8", - "stream-browserify": "^3.0.0" + "sjcl": "^1.0.8" }, "devDependencies": { "@types/chrome": "^0.0.159", "@types/jest": "^27.0.2", + "@types/keccak": "^3.0.1", "@types/qs": "^6.9.6", "@types/react": "^17.0.5", "@types/react-dom": "^17.0.5", "@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/parser": "^5.1.0", + "@warren-bank/translate-webextension-strings": "^1.0.0", "copy-webpack-plugin": "^8.1.1", "css-loader": "^5.2.4", "eslint": "^7.32.0", @@ -51,6 +52,18 @@ "webpack-cli": "^4.7.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -61,35 +74,35 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", - "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.15.8", - "@babel/generator": "^7.15.8", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.8", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.8", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6", + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" @@ -100,12 +113,12 @@ } }, "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -120,22 +133,13 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@babel/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", "dev": true, "dependencies": { - "@babel/types": "^7.15.6", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -153,14 +157,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", "semver": "^6.3.0" }, "engines": { @@ -179,186 +183,159 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", - "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", + "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "dev": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", "dev": true, "dependencies": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -438,9 +415,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -597,12 +574,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", - "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -612,9 +589,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", + "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -623,44 +600,45 @@ } }, "node_modules/@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -669,12 +647,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -690,12 +668,12 @@ } }, "node_modules/@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -709,9 +687,9 @@ "dev": true }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz", - "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", + "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", "dev": true, "engines": { "node": ">=10.0.0" @@ -761,9 +739,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -801,16 +779,16 @@ } }, "node_modules/@jest/console": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz", - "integrity": "sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.3.1", - "jest-util": "^27.3.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" }, "engines": { @@ -818,35 +796,35 @@ } }, "node_modules/@jest/core": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz", - "integrity": "sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "dependencies": { - "@jest/console": "^27.3.1", - "@jest/reporters": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.3.0", - "jest-config": "^27.3.1", - "jest-haste-map": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.3.1", - "jest-resolve-dependencies": "^27.3.1", - "jest-runner": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", - "jest-watcher": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", @@ -865,77 +843,77 @@ } }, "node_modules/@jest/environment": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz", - "integrity": "sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.3.0" + "jest-mock": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz", - "integrity": "sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.3.1", - "jest-mock": "^27.3.0", - "jest-util": "^27.3.1" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/globals": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz", - "integrity": "sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "dependencies": { - "@jest/environment": "^27.3.1", - "@jest/types": "^27.2.5", - "expect": "^27.3.1" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz", - "integrity": "sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.3.1", - "jest-resolve": "^27.3.1", - "jest-util": "^27.3.1", - "jest-worker": "^27.3.1", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -955,13 +933,13 @@ } }, "node_modules/@jest/source-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", - "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "dependencies": { "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "source-map": "^0.6.0" }, "engines": { @@ -969,13 +947,13 @@ } }, "node_modules/@jest/test-result": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz", - "integrity": "sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "dependencies": { - "@jest/console": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -984,38 +962,38 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz", - "integrity": "sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "dependencies": { - "@jest/test-result": "^27.3.1", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", - "jest-runtime": "^27.3.1" + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/transform": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz", - "integrity": "sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/types": "^27.2.5", - "babel-plugin-istanbul": "^6.0.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", - "jest-regex-util": "^27.0.6", - "jest-util": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", "micromatch": "^4.0.4", - "pirates": "^4.0.1", + "pirates": "^4.0.4", "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" @@ -1025,9 +1003,9 @@ } }, "node_modules/@jest/types": { - "version": "27.2.5", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", - "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -1040,6 +1018,31 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1085,9 +1088,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", - "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" @@ -1103,9 +1106,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1116,9 +1119,9 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" @@ -1154,9 +1157,9 @@ } }, "node_modules/@types/eslint": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.1.tgz", - "integrity": "sha512-XhZKznR3i/W5dXqUhgU9fFdJekufbeBd5DALmkuXoeFcjbQcPk+2cL+WLHf6Q81HWAnM2vrslIHpGVyCAviRwg==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", "dev": true, "dependencies": { "@types/estree": "*", @@ -1164,9 +1167,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -1174,9 +1177,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "node_modules/@types/filesystem": { @@ -1204,9 +1207,9 @@ } }, "node_modules/@types/har-format": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.7.tgz", - "integrity": "sha512-/TPzUG0tJn5x1TUcVLlDx2LqbE58hyOzDVAc9kf8SpOEmguHjU6bKUyfqb211AdqLOmU/SNyXvLKPNP5qTlfRw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.8.tgz", + "integrity": "sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ==", "dev": true }, "node_modules/@types/hoist-non-react-statics": { @@ -1219,15 +1222,15 @@ } }, "node_modules/@types/html-minifier-terser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz", - "integrity": "sha512-NZwaaynfs1oIoLAV1vg18e7QMVDvw+6SQrdJc8w3BwUaoroVSf6EBj/Sk4PBWGxsq0dzhA2drbsuMC1/6C6KgQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", "dev": true }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "node_modules/@types/istanbul-lib-report": { @@ -1249,12 +1252,12 @@ } }, "node_modules/@types/jest": { - "version": "27.0.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz", - "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==", + "version": "27.4.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", + "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", "dev": true, "dependencies": { - "jest-diff": "^27.0.0", + "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" } }, @@ -1270,16 +1273,25 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/keccak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-/MxAVmtyyeOvZ6dGf3ciLwFRuV5M8DRIyYNFGHYI6UyBW4/XqyO0LZw+JFMvaeY3cHItQAkELclBU1x5ank6mg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { - "version": "16.11.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz", - "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==", + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", "dev": true }, "node_modules/@types/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", "dev": true }, "node_modules/@types/prop-types": { @@ -1294,9 +1306,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "17.0.30", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.30.tgz", - "integrity": "sha512-3Dt/A8gd3TCXi2aRe84y7cK1K8G+N9CZRDG8kDGguOKa0kf/ZkSwTmVIDPsm/KbQOVMaDJXwhBtuOXxqwdpWVg==", + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", + "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1304,18 +1316,18 @@ } }, "node_modules/@types/react-dom": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", - "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", + "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", "dev": true, "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-redux": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.19.tgz", - "integrity": "sha512-L37dSCT0aoJnCgpR8Iuginlbxoh7qhWOXiaDqEsxVMrER1CmVhFD+63NxgJeT4pkmEM28oX0NH4S4f+sXHTZjA==", + "version": "7.1.22", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", + "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -1350,13 +1362,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.1.0.tgz", - "integrity": "sha512-bekODL3Tqf36Yz8u+ilha4zGxL9mdB6LIsIoMAvvC5FAuWo4NpZYXtCbv7B2CeR1LhI/lLtLk+q4tbtxuoVuCg==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", + "integrity": "sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "5.1.0", - "@typescript-eslint/scope-manager": "5.1.0", + "@typescript-eslint/scope-manager": "5.12.1", + "@typescript-eslint/type-utils": "5.12.1", + "@typescript-eslint/utils": "5.12.1", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -1381,18 +1394,16 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.1.0.tgz", - "integrity": "sha512-ovE9qUiZMOMgxQAESZsdBT+EXIfx/YUYAbwGUI6V03amFdOOxI9c6kitkgRvLkJaLusgMZ2xBhss+tQ0Y1HWxA==", + "node_modules/@typescript-eslint/parser": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.12.1.tgz", + "integrity": "sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.1.0", - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/typescript-estree": "5.1.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/scope-manager": "5.12.1", + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/typescript-estree": "5.12.1", + "debug": "^4.3.2" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1402,37 +1413,40 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz", + "integrity": "sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/visitor-keys": "5.12.1" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.1.0.tgz", - "integrity": "sha512-vx1P+mhCtYw3+bRHmbalq/VKP2Y3gnzNgxGxfEWc6OFpuEL7iQdAeq11Ke3Rhy8NjgB+AHsIWEwni3e+Y7djKA==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz", + "integrity": "sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.1.0", - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/typescript-estree": "5.1.0", - "debug": "^4.3.2" + "@typescript-eslint/utils": "5.12.1", + "debug": "^4.3.2", + "tsutils": "^3.21.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1442,7 +1456,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "*" }, "peerDependenciesMeta": { "typescript": { @@ -1450,27 +1464,10 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.1.0.tgz", - "integrity": "sha512-yYlyVjvn5lvwCL37i4hPsa1s0ORsjkauhTqbb8MnpvUs7xykmcjGqwlNZ2Q5QpoqkJ1odlM2bqHqJwa28qV6Tw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/visitor-keys": "5.1.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/types": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.1.0.tgz", - "integrity": "sha512-sEwNINVxcB4ZgC6Fe6rUyMlvsB2jvVdgxjZEjQUQVlaSPMNamDOwO6/TB98kFt4sYYfNhdhTPBEQqNQZjMMswA==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.12.1.tgz", + "integrity": "sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1481,13 +1478,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.1.0.tgz", - "integrity": "sha512-SSz+l9YrIIsW4s0ZqaEfnjl156XQ4VRmJsbA0ZE1XkXrD3cRpzuZSVCyqeCMR3EBjF27IisWakbBDGhGNIOvfQ==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz", + "integrity": "sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/visitor-keys": "5.1.0", + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/visitor-keys": "5.12.1", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -1507,14 +1504,18 @@ } } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.1.0.tgz", - "integrity": "sha512-uqNXepKBg81JVwjuqAxYrXa1Ql/YDzM+8g/pS+TCPxba0wZttl8m5DkrasbfnmJGHs4lQ2jTbcZ5azGhI7kK+w==", + "node_modules/@typescript-eslint/utils": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.12.1.tgz", + "integrity": "sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.1.0", - "eslint-visitor-keys": "^3.0.0" + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.12.1", + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/typescript-estree": "5.12.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1522,15 +1523,57 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", - "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz", + "integrity": "sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A==", "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.12.1", + "eslint-visitor-keys": "^3.0.0" + }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@warren-bank/ibm-watson-language-translator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@warren-bank/ibm-watson-language-translator/-/ibm-watson-language-translator-1.0.0.tgz", + "integrity": "sha512-K4KJorAm4K6YKljBIrmE2j7wP72z7nlfrppC0OKTs7tP+iMInZ6lYhhPIzp7MlsX/K0lt1sYZ2EsuWy+R0ffiA==", + "dev": true, + "dependencies": { + "@warren-bank/node-process-argv": "^1.1.0" + }, + "bin": { + "ibm-translate": "bin/ibm-translate.js" + } + }, + "node_modules/@warren-bank/node-process-argv": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@warren-bank/node-process-argv/-/node-process-argv-1.1.0.tgz", + "integrity": "sha512-81pXPEVDhM+HQNlXgj/Aa4ZQSXQfX79tvd8nPuHXTEMJ6pnvahiTh/4jkNwQrIznecIDZM+MFt6i2IZmeiYrvA==", + "dev": true + }, + "node_modules/@warren-bank/translate-webextension-strings": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@warren-bank/translate-webextension-strings/-/translate-webextension-strings-1.0.0.tgz", + "integrity": "sha512-QTefZz4fVv9tJ3xEkKELHsoak+GaSgEL1qx3oRcfOFbhYbc1+WDVsZNM7liSBkjt6sU4JzApNRqc83T0AwRALw==", + "dev": true, + "dependencies": { + "@warren-bank/ibm-watson-language-translator": "^1.0.0", + "@warren-bank/node-process-argv": "^1.1.0" + }, + "bin": { + "translate-webextension-strings": "bin/translate-webextension-strings.js" } }, "node_modules/@webassemblyjs/ast": { @@ -1680,9 +1723,9 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "dev": true, "peerDependencies": { "webpack": "4.x.x || 5.x.x", @@ -1690,9 +1733,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "dev": true, "dependencies": { "envinfo": "^7.7.3" @@ -1702,9 +1745,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "dev": true, "peerDependencies": { "webpack-cli": "4.x.x" @@ -1930,18 +1973,18 @@ } }, "node_modules/babel-jest": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz", - "integrity": "sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", "dev": true, "dependencies": { - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.2.0", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "engines": { @@ -1967,35 +2010,10 @@ "node": ">=8" } }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", - "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", - "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -2031,12 +2049,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", - "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.2.0", + "babel-plugin-jest-hoist": "^27.5.1", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -2124,15 +2142,15 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", + "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", + "caniuse-lite": "^1.0.30001312", + "electron-to-chromium": "^1.4.71", "escalade": "^3.1.1", - "node-releases": "^2.0.0", + "node-releases": "^2.0.2", "picocolors": "^1.0.0" }, "bin": { @@ -2237,9 +2255,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001269", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz", - "integrity": "sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==", + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", "dev": true, "funding": { "type": "opencollective", @@ -2272,10 +2290,16 @@ } }, "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2302,9 +2326,9 @@ } }, "node_modules/ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", "dev": true }, "node_modules/cjs-module-lexer": { @@ -2314,9 +2338,9 @@ "dev": true }, "node_modules/clean-css": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.1.tgz", - "integrity": "sha512-ooQCa1/70oRfVdUUGjKpbHuxgMgm8BsDT5EBqBGvPxMoRoGXf4PNx5mMnkjzJ9Ptx4vvmDdha0QVh86QtYIk1g==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", + "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", "dev": true, "dependencies": { "source-map": "~0.6.0" @@ -2403,9 +2427,9 @@ } }, "node_modules/commander": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.2.0.tgz", - "integrity": "sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, "engines": { "node": ">= 12" @@ -2494,16 +2518,16 @@ } }, "node_modules/css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", "dev": true, "dependencies": { "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" }, "funding": { "url": "https://github.com/sponsors/fb55" @@ -2558,9 +2582,9 @@ "dev": true }, "node_modules/csstype": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" }, "node_modules/data-urls": { "version": "2.0.0", @@ -2577,9 +2601,9 @@ } }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2639,9 +2663,9 @@ } }, "node_modules/diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "dev": true, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -2728,9 +2752,9 @@ } }, "node_modules/domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", "dev": true, "dependencies": { "domelementtype": "^2.2.0" @@ -2767,9 +2791,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.871", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz", - "integrity": "sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==", + "version": "1.4.71", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz", + "integrity": "sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw==", "dev": true }, "node_modules/emittery": { @@ -2800,9 +2824,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz", + "integrity": "sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -2845,6 +2869,15 @@ "node": ">=4" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -2895,9 +2928,9 @@ } }, "node_modules/escodegen/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -3012,9 +3045,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.4.0.tgz", + "integrity": "sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -3067,6 +3100,42 @@ } }, "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", @@ -3081,7 +3150,7 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", @@ -3090,7 +3159,7 @@ "node": ">=4" } }, - "node_modules/eslint-visitor-keys": { + "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", @@ -3157,9 +3226,9 @@ } }, "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -3178,9 +3247,9 @@ } }, "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -3246,34 +3315,20 @@ } }, "node_modules/expect": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz", - "integrity": "sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-regex-util": "^27.0.6" + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3287,9 +3342,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3299,7 +3354,7 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-json-stable-stringify": { @@ -3409,15 +3464,15 @@ } }, "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "node_modules/follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", "funding": [ { "type": "individual", @@ -3569,9 +3624,9 @@ "dev": true }, "node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3584,16 +3639,16 @@ } }, "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -3604,9 +3659,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, "node_modules/has": { @@ -3681,18 +3736,18 @@ "dev": true }, "node_modules/html-minifier-terser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.0.2.tgz", - "integrity": "sha512-AgYO3UGhMYQx2S/FBJT3EM0ZYcKmH6m9XL9c1v77BeK/tYJxGPxT1/AtsdUi4FcP8kZGmqqnItCcjFPcX9hk6A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "dev": true, "dependencies": { "camel-case": "^4.1.2", - "clean-css": "^5.1.5", - "commander": "^8.1.0", + "clean-css": "^5.2.2", + "commander": "^8.3.0", "he": "^1.2.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", - "terser": "^5.7.2" + "terser": "^5.10.0" }, "bin": { "html-minifier-terser": "cli.js" @@ -3702,15 +3757,15 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.4.0.tgz", - "integrity": "sha512-cSUdckNOIqKc0nOrCJG7zkvzEIUcXjzEiVbKdEdIzW3BD5T4xPK6boV1mrTrPDZiL+aAr/j45eqbNL1akU2ZRA==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", "dev": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", "lodash": "^4.17.21", - "pretty-error": "^3.0.4", + "pretty-error": "^4.0.0", "tapable": "^2.0.0" }, "engines": { @@ -3823,14 +3878,20 @@ ] }, "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3848,9 +3909,9 @@ } }, "node_modules/import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -3861,6 +3922,9 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { @@ -3896,6 +3960,12 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3909,9 +3979,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -4029,14 +4099,15 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" }, "engines": { @@ -4081,9 +4152,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", - "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -4094,14 +4165,14 @@ } }, "node_modules/jest": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz", - "integrity": "sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "dependencies": { - "@jest/core": "^27.3.1", + "@jest/core": "^27.5.1", "import-local": "^3.0.2", - "jest-cli": "^27.3.1" + "jest-cli": "^27.5.1" }, "bin": { "jest": "bin/jest.js" @@ -4119,12 +4190,12 @@ } }, "node_modules/jest-changed-files": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", - "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "execa": "^5.0.0", "throat": "^6.0.1" }, @@ -4133,27 +4204,27 @@ } }, "node_modules/jest-circus": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz", - "integrity": "sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "dependencies": { - "@jest/environment": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.3.1", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "pretty-format": "^27.3.1", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" @@ -4163,21 +4234,21 @@ } }, "node_modules/jest-cli": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz", - "integrity": "sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "dependencies": { - "@jest/core": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "prompts": "^2.0.1", "yargs": "^16.2.0" }, @@ -4197,32 +4268,35 @@ } }, "node_modules/jest-config": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", - "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.3.1", - "@jest/types": "^27.2.5", - "babel-jest": "^27.3.1", + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.3.1", - "jest-environment-jsdom": "^27.3.1", - "jest-environment-node": "^27.3.1", - "jest-get-type": "^27.3.1", - "jest-jasmine2": "^27.3.1", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.3.1", - "jest-runner": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "micromatch": "^4.0.4", - "pretty-format": "^27.3.1" + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -4237,24 +4311,24 @@ } }, "node_modules/jest-diff": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", - "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-docblock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", - "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -4264,33 +4338,33 @@ } }, "node_modules/jest-each": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz", - "integrity": "sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "jest-get-type": "^27.3.1", - "jest-util": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-environment-jsdom": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz", - "integrity": "sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", "dev": true, "dependencies": { - "@jest/environment": "^27.3.1", - "@jest/fake-timers": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.3.0", - "jest-util": "^27.3.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", "jsdom": "^16.6.0" }, "engines": { @@ -4298,47 +4372,47 @@ } }, "node_modules/jest-environment-node": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz", - "integrity": "sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "dependencies": { - "@jest/environment": "^27.3.1", - "@jest/fake-timers": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.3.0", - "jest-util": "^27.3.1" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-get-type": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", - "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-haste-map": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz", - "integrity": "sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.0.6", - "jest-serializer": "^27.0.6", - "jest-util": "^27.3.1", - "jest-worker": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "micromatch": "^4.0.4", "walker": "^1.0.7" }, @@ -4350,28 +4424,27 @@ } }, "node_modules/jest-jasmine2": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz", - "integrity": "sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.3.1", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.3.1", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "pretty-format": "^27.3.1", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", "throat": "^6.0.1" }, "engines": { @@ -4379,46 +4452,46 @@ } }, "node_modules/jest-leak-detector": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz", - "integrity": "sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, "dependencies": { - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", - "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.3.1", - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-message-util": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz", - "integrity": "sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^27.3.1", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -4427,24 +4500,24 @@ } }, "node_modules/jest-message-util/node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/jest-mock": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", - "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/node": "*" }, "engines": { @@ -4469,27 +4542,27 @@ } }, "node_modules/jest-regex-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", - "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-resolve": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz", - "integrity": "sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" @@ -4499,45 +4572,44 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz", - "integrity": "sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", - "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.3.1" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-runner": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz", - "integrity": "sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "dependencies": { - "@jest/console": "^27.3.1", - "@jest/environment": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.3.1", - "jest-environment-node": "^27.3.1", - "jest-haste-map": "^27.3.1", - "jest-leak-detector": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-resolve": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-util": "^27.3.1", - "jest-worker": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, @@ -4546,84 +4618,78 @@ } }, "node_modules/jest-runtime": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz", - "integrity": "sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg==", - "dev": true, - "dependencies": { - "@jest/console": "^27.3.1", - "@jest/environment": "^27.3.1", - "@jest/globals": "^27.3.1", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", - "@types/yargs": "^16.0.0", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", - "exit": "^0.1.2", "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-mock": "^27.3.0", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.2.0" + "strip-bom": "^4.0.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-serializer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", - "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dev": true, "dependencies": { "@types/node": "*", - "graceful-fs": "^4.2.4" + "graceful-fs": "^4.2.9" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-snapshot": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz", - "integrity": "sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, "dependencies": { "@babel/core": "^7.7.2", "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.3.1", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.3.1", - "jest-get-type": "^27.3.1", - "jest-haste-map": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-resolve": "^27.3.1", - "jest-util": "^27.3.1", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^27.3.1", + "pretty-format": "^27.5.1", "semver": "^7.3.2" }, "engines": { @@ -4631,16 +4697,16 @@ } }, "node_modules/jest-util": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", - "integrity": "sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" }, "engines": { @@ -4648,26 +4714,26 @@ } }, "node_modules/jest-validate": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz", - "integrity": "sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.3.1", + "jest-get-type": "^27.5.1", "leven": "^3.1.0", - "pretty-format": "^27.3.1" + "pretty-format": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { "node": ">=10" @@ -4677,17 +4743,17 @@ } }, "node_modules/jest-watcher": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz", - "integrity": "sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, "dependencies": { - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.3.1", + "jest-util": "^27.5.1", "string-length": "^4.0.1" }, "engines": { @@ -4695,9 +4761,9 @@ } }, "node_modules/jest-worker": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", - "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "dependencies": { "@types/node": "*", @@ -4788,9 +4854,9 @@ } }, "node_modules/jsdom/node_modules/acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4817,6 +4883,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4877,9 +4949,9 @@ } }, "node_modules/klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true, "engines": { "node": ">= 8" @@ -4907,6 +4979,12 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -4917,9 +4995,9 @@ } }, "node_modules/loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -4948,12 +5026,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -5035,12 +5107,12 @@ "dev": true }, "node_modules/makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "dependencies": { - "tmpl": "1.0.x" + "tmpl": "1.0.5" } }, "node_modules/merge-stream": { @@ -5072,21 +5144,21 @@ } }, "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "dev": true, "dependencies": { - "mime-db": "1.50.0" + "mime-db": "1.51.0" }, "engines": { "node": ">= 0.6" @@ -5123,9 +5195,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -5147,9 +5219,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -5201,19 +5273,10 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", "dev": true }, "node_modules/normalize-path": { @@ -5264,9 +5327,9 @@ } }, "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5385,6 +5448,24 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -5450,9 +5531,9 @@ "dev": true }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -5462,13 +5543,10 @@ } }, "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "dependencies": { - "node-modules-regexp": "^1.0.0" - }, "engines": { "node": ">= 6" } @@ -5486,14 +5564,14 @@ } }, "node_modules/postcss": { - "version": "8.3.9", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.9.tgz", - "integrity": "sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dev": true, "dependencies": { - "nanoid": "^3.1.28", - "picocolors": "^0.2.1", - "source-map-js": "^0.6.2" + "nanoid": "^3.2.0", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -5563,9 +5641,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -5576,15 +5654,9 @@ } }, "node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "node_modules/postcss/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, "node_modules/prelude-ls": { @@ -5597,9 +5669,9 @@ } }, "node_modules/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -5621,22 +5693,21 @@ } }, "node_modules/pretty-error": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-3.0.4.tgz", - "integrity": "sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", "dev": true, "dependencies": { "lodash": "^4.17.20", - "renderkid": "^2.0.6" + "renderkid": "^3.0.0" } }, "node_modules/pretty-format": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", - "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "dependencies": { - "@jest/types": "^27.2.5", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" @@ -5680,13 +5751,13 @@ } }, "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "node_modules/prop-types/node_modules/react-is": { @@ -5710,9 +5781,9 @@ } }, "node_modules/qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "dependencies": { "side-channel": "^1.0.4" }, @@ -5780,20 +5851,19 @@ "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-redux": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.5.tgz", - "integrity": "sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/react-redux": "^7.1.16", + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", "hoist-non-react-statics": "^3.3.2", "loose-envify": "^1.4.0", "prop-types": "^15.7.2", - "react-is": "^16.13.1" + "react-is": "^17.0.2" }, "peerDependencies": { "react": "^16.8.3 || ^17" @@ -5807,11 +5877,6 @@ } } }, - "node_modules/react-redux/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -5850,9 +5915,9 @@ } }, "node_modules/redux": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz", - "integrity": "sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", "dependencies": { "@babel/runtime": "^7.9.2" } @@ -5884,37 +5949,16 @@ } }, "node_modules/renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", "dev": true, "dependencies": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", "htmlparser2": "^6.1.0", "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - } - }, - "node_modules/renderkid/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/renderkid/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "strip-ansi": "^6.0.1" } }, "node_modules/require-directory": { @@ -5936,13 +5980,17 @@ } }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6066,18 +6114,20 @@ "dev": true }, "node_modules/sass": { - "version": "1.43.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.43.2.tgz", - "integrity": "sha512-DncYhjl3wBaPMMJR0kIUaH3sF536rVrOcqqVGmTZHQRRzj7LQlyGV7Mb8aCKFyILMr5VsPHwRYtyKpnKYlmQSQ==", + "version": "1.49.8", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.8.tgz", + "integrity": "sha512-NoGOjvDDOU9og9oAxhRnap71QaTjjlzrvLnKecUJ3GxhaQBrV6e7gPuSPF28u1OcVAArVojPAe4ZhOXwwC4tGw==", "dev": true, "dependencies": { - "chokidar": ">=3.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.0.0" } }, "node_modules/sass-loader": { @@ -6224,9 +6274,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "node_modules/sisteransi": { @@ -6285,18 +6335,18 @@ } }, "node_modules/source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -6330,15 +6380,6 @@ "node": ">=8" } }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6460,6 +6501,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -6467,13 +6520,12 @@ "dev": true }, "node_modules/table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", "dev": true, "dependencies": { "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.3", @@ -6484,9 +6536,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -6531,11 +6583,12 @@ } }, "node_modules/terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", + "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", "dev": true, "dependencies": { + "acorn": "^8.5.0", "commander": "^2.20.0", "source-map": "~0.7.2", "source-map-support": "~0.5.20" @@ -6548,13 +6601,12 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", "dev": true, "dependencies": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", + "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", "source-map": "^0.6.1", @@ -6591,6 +6643,18 @@ "randombytes": "^2.1.0" } }, + "node_modules/terser/node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -6686,9 +6750,9 @@ } }, "node_modules/ts-jest": { - "version": "27.0.7", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.7.tgz", - "integrity": "sha512-O41shibMqzdafpuP+CkrOL7ykbmLh+FqQrXEmV9CydQ5JBk0Sj0uAEF5TNNe94fZWKm3yYvWa/IbyV4Yg1zK2Q==", + "version": "27.1.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", + "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -6710,6 +6774,7 @@ "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", "babel-jest": ">=27.0.0 <28", + "esbuild": "~0.14.0", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" }, @@ -6722,6 +6787,9 @@ }, "babel-jest": { "optional": true + }, + "esbuild": { + "optional": true } } }, @@ -6745,9 +6813,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -6757,9 +6825,9 @@ } }, "node_modules/tsconfig-paths-webpack-plugin": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.1.tgz", - "integrity": "sha512-n5CMlUUj+N5pjBhBACLq4jdr9cPTitySCjIosoQm0zwK99gmrcTGAfY9CwxRFT9+9OleNWXPRUcxsKP4AYExxQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz", + "integrity": "sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -6858,9 +6926,9 @@ } }, "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6906,9 +6974,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -6950,18 +7018,18 @@ } }, "node_modules/walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "dependencies": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "node_modules/watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -6981,13 +7049,13 @@ } }, "node_modules/webpack": { - "version": "5.59.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.59.0.tgz", - "integrity": "sha512-2HiFHKnWIb/cBfOfgssQn8XIRvntISXiz//F1q1+hKMs+uzC1zlVCJZEP7XqI1wzrDyc/ZdB4G+MYtz5biJxCA==", + "version": "5.69.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.1.tgz", + "integrity": "sha512-+VyvOSJXZMT2V5vLzOnDuMz5GxEqLk7hKWQ56YxPW/PQRUuKimPqmEIJOx8jHYeyo65pKbapbW464mvsKbaj4A==", "dev": true, "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -7000,7 +7068,7 @@ "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "json-parse-better-errors": "^1.0.2", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", @@ -7008,8 +7076,8 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.2.0", - "webpack-sources": "^3.2.0" + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" }, "bin": { "webpack": "bin/webpack.js" @@ -7028,15 +7096,15 @@ } }, "node_modules/webpack-cli": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz", - "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.0", - "@webpack-cli/info": "^1.4.0", - "@webpack-cli/serve": "^1.6.0", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", "colorette": "^2.0.14", "commander": "^7.0.0", "execa": "^5.0.0", @@ -7103,9 +7171,9 @@ } }, "node_modules/webpack/node_modules/acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -7124,9 +7192,9 @@ } }, "node_modules/webpack/node_modules/webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, "engines": { "node": ">=10.13.0" @@ -7227,9 +7295,9 @@ } }, "node_modules/ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true, "engines": { "node": ">=8.3.0" @@ -7315,6 +7383,15 @@ } }, "dependencies": { + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -7325,41 +7402,41 @@ } }, "@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", "dev": true }, "@babel/core": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", - "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.15.8", - "@babel/generator": "^7.15.8", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.8", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.8", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6", + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "semver": "^6.3.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } }, "semver": { @@ -7367,22 +7444,16 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true } } }, "@babel/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", "dev": true, "requires": { - "@babel/types": "^7.15.6", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -7396,14 +7467,14 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "dev": true, "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", "semver": "^6.3.0" }, "dependencies": { @@ -7415,144 +7486,123 @@ } } }, - "@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, - "@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" } }, - "@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, - "@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", - "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", + "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", - "dev": true, - "requires": { - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" } }, "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "dev": true }, - "@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - } - }, "@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true }, "@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", "dev": true, "requires": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -7616,9 +7666,9 @@ } }, "@babel/parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -7730,68 +7780,69 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", - "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", + "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" }, "dependencies": { "@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } } } }, "@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } }, "globals": { @@ -7803,12 +7854,12 @@ } }, "@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, @@ -7819,9 +7870,9 @@ "dev": true }, "@discoveryjs/json-ext": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz", - "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", + "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", "dev": true }, "@eslint/eslintrc": { @@ -7861,9 +7912,9 @@ } }, "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -7894,49 +7945,49 @@ "dev": true }, "@jest/console": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz", - "integrity": "sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.3.1", - "jest-util": "^27.3.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" } }, "@jest/core": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz", - "integrity": "sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "requires": { - "@jest/console": "^27.3.1", - "@jest/reporters": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.3.0", - "jest-config": "^27.3.1", - "jest-haste-map": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.3.1", - "jest-resolve-dependencies": "^27.3.1", - "jest-runner": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", - "jest-watcher": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", @@ -7944,68 +7995,68 @@ } }, "@jest/environment": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz", - "integrity": "sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, "requires": { - "@jest/fake-timers": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.3.0" + "jest-mock": "^27.5.1" } }, "@jest/fake-timers": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz", - "integrity": "sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.3.1", - "jest-mock": "^27.3.0", - "jest-util": "^27.3.1" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "@jest/globals": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz", - "integrity": "sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "requires": { - "@jest/environment": "^27.3.1", - "@jest/types": "^27.2.5", - "expect": "^27.3.1" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" } }, "@jest/reporters": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz", - "integrity": "sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.3.1", - "jest-resolve": "^27.3.1", - "jest-util": "^27.3.1", - "jest-worker": "^27.3.1", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -8014,67 +8065,67 @@ } }, "@jest/source-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", - "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "requires": { "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "source-map": "^0.6.0" } }, "@jest/test-result": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz", - "integrity": "sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "requires": { - "@jest/console": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz", - "integrity": "sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "requires": { - "@jest/test-result": "^27.3.1", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", - "jest-runtime": "^27.3.1" + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" } }, "@jest/transform": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz", - "integrity": "sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^27.2.5", - "babel-plugin-istanbul": "^6.0.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", - "jest-regex-util": "^27.0.6", - "jest-util": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", "micromatch": "^4.0.4", - "pirates": "^4.0.1", + "pirates": "^4.0.4", "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" } }, "@jest/types": { - "version": "27.2.5", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", - "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -8084,6 +8135,28 @@ "chalk": "^4.0.0" } }, + "@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -8120,9 +8193,9 @@ } }, "@sinonjs/fake-timers": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", - "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -8135,9 +8208,9 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -8148,9 +8221,9 @@ } }, "@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "requires": { "@babel/types": "^7.0.0" @@ -8186,9 +8259,9 @@ } }, "@types/eslint": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.1.tgz", - "integrity": "sha512-XhZKznR3i/W5dXqUhgU9fFdJekufbeBd5DALmkuXoeFcjbQcPk+2cL+WLHf6Q81HWAnM2vrslIHpGVyCAviRwg==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", "dev": true, "requires": { "@types/estree": "*", @@ -8196,9 +8269,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "dev": true, "requires": { "@types/eslint": "*", @@ -8206,9 +8279,9 @@ } }, "@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "@types/filesystem": { @@ -8236,9 +8309,9 @@ } }, "@types/har-format": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.7.tgz", - "integrity": "sha512-/TPzUG0tJn5x1TUcVLlDx2LqbE58hyOzDVAc9kf8SpOEmguHjU6bKUyfqb211AdqLOmU/SNyXvLKPNP5qTlfRw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.8.tgz", + "integrity": "sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ==", "dev": true }, "@types/hoist-non-react-statics": { @@ -8251,15 +8324,15 @@ } }, "@types/html-minifier-terser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz", - "integrity": "sha512-NZwaaynfs1oIoLAV1vg18e7QMVDvw+6SQrdJc8w3BwUaoroVSf6EBj/Sk4PBWGxsq0dzhA2drbsuMC1/6C6KgQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", "dev": true }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "@types/istanbul-lib-report": { @@ -8281,12 +8354,12 @@ } }, "@types/jest": { - "version": "27.0.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz", - "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==", + "version": "27.4.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", + "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", "dev": true, "requires": { - "jest-diff": "^27.0.0", + "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" } }, @@ -8302,16 +8375,25 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/keccak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-/MxAVmtyyeOvZ6dGf3ciLwFRuV5M8DRIyYNFGHYI6UyBW4/XqyO0LZw+JFMvaeY3cHItQAkELclBU1x5ank6mg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/node": { - "version": "16.11.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz", - "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==", + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", "dev": true }, "@types/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", "dev": true }, "@types/prop-types": { @@ -8326,9 +8408,9 @@ "dev": true }, "@types/react": { - "version": "17.0.30", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.30.tgz", - "integrity": "sha512-3Dt/A8gd3TCXi2aRe84y7cK1K8G+N9CZRDG8kDGguOKa0kf/ZkSwTmVIDPsm/KbQOVMaDJXwhBtuOXxqwdpWVg==", + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", + "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -8336,18 +8418,18 @@ } }, "@types/react-dom": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", - "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", + "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", "dev": true, "requires": { "@types/react": "*" } }, "@types/react-redux": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.19.tgz", - "integrity": "sha512-L37dSCT0aoJnCgpR8Iuginlbxoh7qhWOXiaDqEsxVMrER1CmVhFD+63NxgJeT4pkmEM28oX0NH4S4f+sXHTZjA==", + "version": "7.1.22", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", + "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -8382,84 +8464,69 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.1.0.tgz", - "integrity": "sha512-bekODL3Tqf36Yz8u+ilha4zGxL9mdB6LIsIoMAvvC5FAuWo4NpZYXtCbv7B2CeR1LhI/lLtLk+q4tbtxuoVuCg==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", + "integrity": "sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "5.1.0", - "@typescript-eslint/scope-manager": "5.1.0", + "@typescript-eslint/scope-manager": "5.12.1", + "@typescript-eslint/type-utils": "5.12.1", + "@typescript-eslint/utils": "5.12.1", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", "regexpp": "^3.2.0", "semver": "^7.3.5", "tsutils": "^3.21.0" - }, - "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.1.0.tgz", - "integrity": "sha512-ovE9qUiZMOMgxQAESZsdBT+EXIfx/YUYAbwGUI6V03amFdOOxI9c6kitkgRvLkJaLusgMZ2xBhss+tQ0Y1HWxA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.1.0", - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/typescript-estree": "5.1.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - } - } - } } }, "@typescript-eslint/parser": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.1.0.tgz", - "integrity": "sha512-vx1P+mhCtYw3+bRHmbalq/VKP2Y3gnzNgxGxfEWc6OFpuEL7iQdAeq11Ke3Rhy8NjgB+AHsIWEwni3e+Y7djKA==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.12.1.tgz", + "integrity": "sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.1.0", - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/typescript-estree": "5.1.0", + "@typescript-eslint/scope-manager": "5.12.1", + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/typescript-estree": "5.12.1", "debug": "^4.3.2" } }, "@typescript-eslint/scope-manager": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.1.0.tgz", - "integrity": "sha512-yYlyVjvn5lvwCL37i4hPsa1s0ORsjkauhTqbb8MnpvUs7xykmcjGqwlNZ2Q5QpoqkJ1odlM2bqHqJwa28qV6Tw==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz", + "integrity": "sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/visitor-keys": "5.12.1" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz", + "integrity": "sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/visitor-keys": "5.1.0" + "@typescript-eslint/utils": "5.12.1", + "debug": "^4.3.2", + "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.1.0.tgz", - "integrity": "sha512-sEwNINVxcB4ZgC6Fe6rUyMlvsB2jvVdgxjZEjQUQVlaSPMNamDOwO6/TB98kFt4sYYfNhdhTPBEQqNQZjMMswA==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.12.1.tgz", + "integrity": "sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.1.0.tgz", - "integrity": "sha512-SSz+l9YrIIsW4s0ZqaEfnjl156XQ4VRmJsbA0ZE1XkXrD3cRpzuZSVCyqeCMR3EBjF27IisWakbBDGhGNIOvfQ==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz", + "integrity": "sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.1.0", - "@typescript-eslint/visitor-keys": "5.1.0", + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/visitor-keys": "5.12.1", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -8467,22 +8534,53 @@ "tsutils": "^3.21.0" } }, + "@typescript-eslint/utils": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.12.1.tgz", + "integrity": "sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.12.1", + "@typescript-eslint/types": "5.12.1", + "@typescript-eslint/typescript-estree": "5.12.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, "@typescript-eslint/visitor-keys": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.1.0.tgz", - "integrity": "sha512-uqNXepKBg81JVwjuqAxYrXa1Ql/YDzM+8g/pS+TCPxba0wZttl8m5DkrasbfnmJGHs4lQ2jTbcZ5azGhI7kK+w==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz", + "integrity": "sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A==", "dev": true, "requires": { - "@typescript-eslint/types": "5.1.0", + "@typescript-eslint/types": "5.12.1", "eslint-visitor-keys": "^3.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", - "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", - "dev": true - } + } + }, + "@warren-bank/ibm-watson-language-translator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@warren-bank/ibm-watson-language-translator/-/ibm-watson-language-translator-1.0.0.tgz", + "integrity": "sha512-K4KJorAm4K6YKljBIrmE2j7wP72z7nlfrppC0OKTs7tP+iMInZ6lYhhPIzp7MlsX/K0lt1sYZ2EsuWy+R0ffiA==", + "dev": true, + "requires": { + "@warren-bank/node-process-argv": "^1.1.0" + } + }, + "@warren-bank/node-process-argv": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@warren-bank/node-process-argv/-/node-process-argv-1.1.0.tgz", + "integrity": "sha512-81pXPEVDhM+HQNlXgj/Aa4ZQSXQfX79tvd8nPuHXTEMJ6pnvahiTh/4jkNwQrIznecIDZM+MFt6i2IZmeiYrvA==", + "dev": true + }, + "@warren-bank/translate-webextension-strings": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@warren-bank/translate-webextension-strings/-/translate-webextension-strings-1.0.0.tgz", + "integrity": "sha512-QTefZz4fVv9tJ3xEkKELHsoak+GaSgEL1qx3oRcfOFbhYbc1+WDVsZNM7liSBkjt6sU4JzApNRqc83T0AwRALw==", + "dev": true, + "requires": { + "@warren-bank/ibm-watson-language-translator": "^1.0.0", + "@warren-bank/node-process-argv": "^1.1.0" } }, "@webassemblyjs/ast": { @@ -8632,25 +8730,25 @@ } }, "@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "dev": true, "requires": {} }, "@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "dev": true, "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "dev": true, "requires": {} }, @@ -8818,18 +8916,18 @@ } }, "babel-jest": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz", - "integrity": "sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", "dev": true, "requires": { - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.2.0", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "slash": "^3.0.0" } }, @@ -8844,33 +8942,12 @@ "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", - "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "babel-plugin-jest-hoist": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", - "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -8900,12 +8977,12 @@ } }, "babel-preset-jest": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", - "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.2.0", + "babel-plugin-jest-hoist": "^27.5.1", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -8964,15 +9041,15 @@ "dev": true }, "browserslist": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", + "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", + "caniuse-lite": "^1.0.30001312", + "electron-to-chromium": "^1.4.71", "escalade": "^3.1.1", - "node-releases": "^2.0.0", + "node-releases": "^2.0.2", "picocolors": "^1.0.0" } }, @@ -9041,9 +9118,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001269", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz", - "integrity": "sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==", + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", "dev": true }, "chalk": { @@ -9063,9 +9140,9 @@ "dev": true }, "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { "anymatch": "~3.1.2", @@ -9085,9 +9162,9 @@ "dev": true }, "ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", "dev": true }, "cjs-module-lexer": { @@ -9097,9 +9174,9 @@ "dev": true }, "clean-css": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.1.tgz", - "integrity": "sha512-ooQCa1/70oRfVdUUGjKpbHuxgMgm8BsDT5EBqBGvPxMoRoGXf4PNx5mMnkjzJ9Ptx4vvmDdha0QVh86QtYIk1g==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", + "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", "dev": true, "requires": { "source-map": "~0.6.0" @@ -9170,9 +9247,9 @@ } }, "commander": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.2.0.tgz", - "integrity": "sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true }, "concat-map": { @@ -9235,16 +9312,16 @@ } }, "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" } }, "css-what": { @@ -9283,9 +9360,9 @@ } }, "csstype": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" }, "data-urls": { "version": "2.0.0", @@ -9299,9 +9376,9 @@ } }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" @@ -9344,9 +9421,9 @@ "dev": true }, "diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "dev": true }, "dir-glob": { @@ -9411,9 +9488,9 @@ } }, "domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -9441,9 +9518,9 @@ } }, "electron-to-chromium": { - "version": "1.3.871", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz", - "integrity": "sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==", + "version": "1.4.71", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz", + "integrity": "sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw==", "dev": true }, "emittery": { @@ -9465,9 +9542,9 @@ "dev": true }, "enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz", + "integrity": "sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -9495,6 +9572,15 @@ "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -9527,9 +9613,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "levn": { @@ -9621,6 +9707,29 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -9630,9 +9739,9 @@ } }, "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.4.0.tgz", + "integrity": "sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw==", "dev": true, "requires": {} }, @@ -9665,26 +9774,26 @@ } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "espree": { @@ -9722,9 +9831,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -9739,9 +9848,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -9788,25 +9897,15 @@ "dev": true }, "expect": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz", - "integrity": "sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, "requires": { - "@jest/types": "^27.2.5", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-regex-util": "^27.0.6" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" } }, "fast-deep-equal": { @@ -9822,9 +9921,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -9919,15 +10018,15 @@ } }, "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" }, "form-data": { "version": "3.0.1", @@ -10028,32 +10127,32 @@ "dev": true }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" } }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, "has": { @@ -10112,30 +10211,30 @@ "dev": true }, "html-minifier-terser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.0.2.tgz", - "integrity": "sha512-AgYO3UGhMYQx2S/FBJT3EM0ZYcKmH6m9XL9c1v77BeK/tYJxGPxT1/AtsdUi4FcP8kZGmqqnItCcjFPcX9hk6A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "dev": true, "requires": { "camel-case": "^4.1.2", - "clean-css": "^5.1.5", - "commander": "^8.1.0", + "clean-css": "^5.2.2", + "commander": "^8.3.0", "he": "^1.2.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", - "terser": "^5.7.2" + "terser": "^5.10.0" } }, "html-webpack-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.4.0.tgz", - "integrity": "sha512-cSUdckNOIqKc0nOrCJG7zkvzEIUcXjzEiVbKdEdIzW3BD5T4xPK6boV1mrTrPDZiL+aAr/j45eqbNL1akU2ZRA==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", "dev": true, "requires": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", "lodash": "^4.17.21", - "pretty-error": "^3.0.4", + "pretty-error": "^4.0.0", "tapable": "^2.0.0" } }, @@ -10200,9 +10299,15 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", "dev": true }, "import-fresh": { @@ -10216,9 +10321,9 @@ } }, "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -10252,6 +10357,12 @@ "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -10262,9 +10373,9 @@ } }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "requires": { "has": "^1.0.3" @@ -10349,14 +10460,15 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", "dev": true, "requires": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" }, "dependencies": { @@ -10391,9 +10503,9 @@ } }, "istanbul-reports": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", - "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -10401,276 +10513,278 @@ } }, "jest": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz", - "integrity": "sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "requires": { - "@jest/core": "^27.3.1", + "@jest/core": "^27.5.1", "import-local": "^3.0.2", - "jest-cli": "^27.3.1" + "jest-cli": "^27.5.1" } }, "jest-changed-files": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", - "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "execa": "^5.0.0", "throat": "^6.0.1" } }, "jest-circus": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz", - "integrity": "sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "requires": { - "@jest/environment": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.3.1", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "pretty-format": "^27.3.1", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" } }, "jest-cli": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz", - "integrity": "sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "requires": { - "@jest/core": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "prompts": "^2.0.1", "yargs": "^16.2.0" } }, "jest-config": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", - "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.3.1", - "@jest/types": "^27.2.5", - "babel-jest": "^27.3.1", + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.3.1", - "jest-environment-jsdom": "^27.3.1", - "jest-environment-node": "^27.3.1", - "jest-get-type": "^27.3.1", - "jest-jasmine2": "^27.3.1", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.3.1", - "jest-runner": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "micromatch": "^4.0.4", - "pretty-format": "^27.3.1" + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" } }, "jest-diff": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", - "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-docblock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", - "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz", - "integrity": "sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "jest-get-type": "^27.3.1", - "jest-util": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-environment-jsdom": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz", - "integrity": "sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", "dev": true, "requires": { - "@jest/environment": "^27.3.1", - "@jest/fake-timers": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.3.0", - "jest-util": "^27.3.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz", - "integrity": "sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "requires": { - "@jest/environment": "^27.3.1", - "@jest/fake-timers": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.3.0", - "jest-util": "^27.3.1" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "jest-get-type": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", - "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true }, "jest-haste-map": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz", - "integrity": "sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.0.6", - "jest-serializer": "^27.0.6", - "jest-util": "^27.3.1", - "jest-worker": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "micromatch": "^4.0.4", "walker": "^1.0.7" } }, "jest-jasmine2": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz", - "integrity": "sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.3.1", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.3.1", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "pretty-format": "^27.3.1", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", "throat": "^6.0.1" } }, "jest-leak-detector": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz", - "integrity": "sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, "requires": { - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-matcher-utils": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", - "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.3.1", - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-message-util": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz", - "integrity": "sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^27.3.1", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "dependencies": { "@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } } } }, "jest-mock": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", - "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/node": "*" } }, @@ -10682,201 +10796,194 @@ "requires": {} }, "jest-regex-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", - "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true }, "jest-resolve": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz", - "integrity": "sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" } }, "jest-resolve-dependencies": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz", - "integrity": "sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, "requires": { - "@jest/types": "^27.2.5", - "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.3.1" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" } }, "jest-runner": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz", - "integrity": "sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "requires": { - "@jest/console": "^27.3.1", - "@jest/environment": "^27.3.1", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.3.1", - "jest-environment-node": "^27.3.1", - "jest-haste-map": "^27.3.1", - "jest-leak-detector": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-resolve": "^27.3.1", - "jest-runtime": "^27.3.1", - "jest-util": "^27.3.1", - "jest-worker": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "source-map-support": "^0.5.6", "throat": "^6.0.1" } }, "jest-runtime": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz", - "integrity": "sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg==", - "dev": true, - "requires": { - "@jest/console": "^27.3.1", - "@jest/environment": "^27.3.1", - "@jest/globals": "^27.3.1", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.3.1", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", - "@types/yargs": "^16.0.0", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", - "exit": "^0.1.2", "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-mock": "^27.3.0", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.3.1", - "jest-snapshot": "^27.3.1", - "jest-util": "^27.3.1", - "jest-validate": "^27.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.2.0" + "strip-bom": "^4.0.0" } }, "jest-serializer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", - "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dev": true, "requires": { "@types/node": "*", - "graceful-fs": "^4.2.4" + "graceful-fs": "^4.2.9" } }, "jest-snapshot": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz", - "integrity": "sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, "requires": { "@babel/core": "^7.7.2", "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.3.1", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.3.1", - "jest-get-type": "^27.3.1", - "jest-haste-map": "^27.3.1", - "jest-matcher-utils": "^27.3.1", - "jest-message-util": "^27.3.1", - "jest-resolve": "^27.3.1", - "jest-util": "^27.3.1", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^27.3.1", + "pretty-format": "^27.5.1", "semver": "^7.3.2" } }, "jest-util": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", - "integrity": "sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "jest-validate": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz", - "integrity": "sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.5.1", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.3.1", + "jest-get-type": "^27.5.1", "leven": "^3.1.0", - "pretty-format": "^27.3.1" + "pretty-format": "^27.5.1" }, "dependencies": { "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true } } }, "jest-watcher": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz", - "integrity": "sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, "requires": { - "@jest/test-result": "^27.3.1", - "@jest/types": "^27.2.5", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.3.1", + "jest-util": "^27.5.1", "string-length": "^4.0.1" } }, "jest-worker": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", - "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { "@types/node": "*", @@ -10946,9 +11053,9 @@ }, "dependencies": { "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true } } @@ -10965,6 +11072,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -11009,9 +11122,9 @@ "dev": true }, "klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true }, "leven": { @@ -11030,6 +11143,12 @@ "type-check": "~0.4.0" } }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -11037,9 +11156,9 @@ "dev": true }, "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -11062,12 +11181,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -11136,12 +11249,12 @@ "dev": true }, "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "requires": { - "tmpl": "1.0.x" + "tmpl": "1.0.5" } }, "merge-stream": { @@ -11167,18 +11280,18 @@ } }, "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", "dev": true }, "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "dev": true, "requires": { - "mime-db": "1.50.0" + "mime-db": "1.51.0" } }, "mimic-fn": { @@ -11199,9 +11312,9 @@ } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -11220,9 +11333,9 @@ "dev": true }, "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, "natural-compare": { @@ -11263,16 +11376,10 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, "node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", "dev": true }, "normalize-path": { @@ -11311,9 +11418,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "once": { "version": "1.4.0", @@ -11401,6 +11508,18 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, "parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -11454,19 +11573,16 @@ "dev": true }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true }, "pkg-dir": { "version": "4.2.0", @@ -11478,22 +11594,14 @@ } }, "postcss": { - "version": "8.3.9", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.9.tgz", - "integrity": "sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dev": true, "requires": { - "nanoid": "^3.1.28", - "picocolors": "^0.2.1", - "source-map-js": "^0.6.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - } + "nanoid": "^3.2.0", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" } }, "postcss-modules-extract-imports": { @@ -11533,9 +11641,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -11543,9 +11651,9 @@ } }, "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, "prelude-ls": { @@ -11555,9 +11663,9 @@ "dev": true }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true }, "prettier-linter-helpers": { @@ -11570,22 +11678,21 @@ } }, "pretty-error": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-3.0.4.tgz", - "integrity": "sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", "dev": true, "requires": { "lodash": "^4.17.20", - "renderkid": "^2.0.6" + "renderkid": "^3.0.0" } }, "pretty-format": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", - "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "requires": { - "@jest/types": "^27.2.5", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" @@ -11616,13 +11723,13 @@ } }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" }, "dependencies": { "react-is": { @@ -11645,9 +11752,9 @@ "dev": true }, "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "requires": { "side-channel": "^1.0.4" } @@ -11689,27 +11796,19 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-redux": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.5.tgz", - "integrity": "sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", "requires": { - "@babel/runtime": "^7.12.1", - "@types/react-redux": "^7.1.16", + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", "hoist-non-react-statics": "^3.3.2", "loose-envify": "^1.4.0", "prop-types": "^15.7.2", - "react-is": "^16.13.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } + "react-is": "^17.0.2" } }, "readable-stream": { @@ -11741,9 +11840,9 @@ } }, "redux": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz", - "integrity": "sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", "requires": { "@babel/runtime": "^7.9.2" } @@ -11766,33 +11865,16 @@ "dev": true }, "renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", "dev": true, "requires": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", "htmlparser2": "^6.1.0", "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "strip-ansi": "^6.0.1" } }, "require-directory": { @@ -11808,13 +11890,14 @@ "dev": true }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -11898,12 +11981,14 @@ "dev": true }, "sass": { - "version": "1.43.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.43.2.tgz", - "integrity": "sha512-DncYhjl3wBaPMMJR0kIUaH3sF536rVrOcqqVGmTZHQRRzj7LQlyGV7Mb8aCKFyILMr5VsPHwRYtyKpnKYlmQSQ==", + "version": "1.49.8", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.8.tgz", + "integrity": "sha512-NoGOjvDDOU9og9oAxhRnap71QaTjjlzrvLnKecUJ3GxhaQBrV6e7gPuSPF28u1OcVAArVojPAe4ZhOXwwC4tGw==", "dev": true, "requires": { - "chokidar": ">=3.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" } }, "sass-loader": { @@ -11998,9 +12083,9 @@ } }, "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "sisteransi": { @@ -12044,15 +12129,15 @@ "dev": true }, "source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -12082,15 +12167,6 @@ } } }, - "stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "requires": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -12173,6 +12249,12 @@ "supports-color": "^7.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -12180,13 +12262,12 @@ "dev": true }, "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", "dev": true, "requires": { "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.3", @@ -12194,9 +12275,9 @@ }, "dependencies": { "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -12230,16 +12311,23 @@ } }, "terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", + "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", "dev": true, "requires": { + "acorn": "^8.5.0", "commander": "^2.20.0", "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -12255,13 +12343,12 @@ } }, "terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", "dev": true, "requires": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", + "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", "source-map": "^0.6.1", @@ -12344,9 +12431,9 @@ } }, "ts-jest": { - "version": "27.0.7", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.7.tgz", - "integrity": "sha512-O41shibMqzdafpuP+CkrOL7ykbmLh+FqQrXEmV9CydQ5JBk0Sj0uAEF5TNNe94fZWKm3yYvWa/IbyV4Yg1zK2Q==", + "version": "27.1.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", + "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", "dev": true, "requires": { "bs-logger": "0.x", @@ -12372,9 +12459,9 @@ } }, "tsconfig-paths": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", "dev": true, "requires": { "@types/json5": "^0.0.29", @@ -12401,9 +12488,9 @@ } }, "tsconfig-paths-webpack-plugin": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.1.tgz", - "integrity": "sha512-n5CMlUUj+N5pjBhBACLq4jdr9cPTitySCjIosoQm0zwK99gmrcTGAfY9CwxRFT9+9OleNWXPRUcxsKP4AYExxQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz", + "integrity": "sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -12465,9 +12552,9 @@ } }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "dev": true }, "universalify": { @@ -12503,9 +12590,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -12540,18 +12627,18 @@ } }, "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "requires": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -12565,13 +12652,13 @@ "dev": true }, "webpack": { - "version": "5.59.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.59.0.tgz", - "integrity": "sha512-2HiFHKnWIb/cBfOfgssQn8XIRvntISXiz//F1q1+hKMs+uzC1zlVCJZEP7XqI1wzrDyc/ZdB4G+MYtz5biJxCA==", + "version": "5.69.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.1.tgz", + "integrity": "sha512-+VyvOSJXZMT2V5vLzOnDuMz5GxEqLk7hKWQ56YxPW/PQRUuKimPqmEIJOx8jHYeyo65pKbapbW464mvsKbaj4A==", "dev": true, "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -12584,7 +12671,7 @@ "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "json-parse-better-errors": "^1.0.2", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", @@ -12592,14 +12679,14 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.2.0", - "webpack-sources": "^3.2.0" + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" }, "dependencies": { "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, "acorn-import-assertions": { @@ -12610,23 +12697,23 @@ "requires": {} }, "webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true } } }, "webpack-cli": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz", - "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.0", - "@webpack-cli/info": "^1.4.0", - "@webpack-cli/serve": "^1.6.0", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", "colorette": "^2.0.14", "commander": "^7.0.0", "execa": "^5.0.0", @@ -12742,9 +12829,9 @@ } }, "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index fb4fe06e..ffa4b039 100644 --- a/package.json +++ b/package.json @@ -1,43 +1,48 @@ { "name": "privacy-pass", - "version": "3.0.0", + "version": "3.7.2", + "private": true, "contributors": [ "Suphanat Chunhapanya ", - "Armando Faz " + "Armando Faz ", + "Warren Bank " ], - "main": "index.js", + "browser": "index.js", "license": "BSD-3-Clause", "type": "module", "scripts": { - "sjcl": "cd node_modules/sjcl && ./configure --without-all --with-ecc --with-convenience --with-codecBytes --with-codecHex --compress=none && make sjcl.js", - "prebuild": "npm run sjcl", + "prebuild": "npm run clean && npm run sjcl", "build": "webpack", "pretest": "npm run sjcl", - "test": "node --experimental-vm-modules node_modules/.bin/jest", + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", "lint": "eslint ./src/**/*.{ts,tsx}", - "clean": "rimraf dist" + "clean": "rimraf lib && rimraf dist/PrivacyPass && rimraf dist/PrivacyPass.crx* && rimraf dist/PrivacyPass.xpi", + "sjcl": "cd node_modules/sjcl && perl configure --without-all --with-ecc --with-convenience --with-codecBytes --with-codecHex --compress=none && make sjcl.js", + "translate": "translate-webextension-strings -i \"en\" -f \"public/_locales/en/messages.json\" -d \"public/_locales\" -m -b \"Privacy Pass\" -b \"'manifest.json'\" -b \"'@popup[^']+'\" -b \"JSON\" -b \"Cloudflare\" -b \"hCaptcha\" -b \"Github\"", + "translate:debug": "translate-webextension-strings -i \"en\" -o \"en\" -f \"public/_locales/en/messages.json\" -d \"public/_locales\" --debug -b \"Privacy Pass\" -b \"'manifest.json'\" -b \"'@popup[^']+'\" -b \"JSON\" -b \"Cloudflare\" -b \"hCaptcha\" -b \"Github\"" }, "dependencies": { "asn1-parser": "^1.1.8", "axios": "^0.23.0", "buffer": "^6.0.3", - "keccak": "^3.0.1", + "keccak": "^3.0.2", "qs": "^6.10.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.5", "redux": "^4.1.1", - "sjcl": "^1.0.8", - "stream-browserify": "^3.0.0" + "sjcl": "^1.0.8" }, "devDependencies": { "@types/chrome": "^0.0.159", "@types/jest": "^27.0.2", + "@types/keccak": "^3.0.1", "@types/qs": "^6.9.6", "@types/react": "^17.0.5", "@types/react-dom": "^17.0.5", "@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/parser": "^5.1.0", + "@warren-bank/translate-webextension-strings": "^1.0.0", "copy-webpack-plugin": "^8.1.1", "css-loader": "^5.2.4", "eslint": "^7.32.0", diff --git a/public/_locales/ar/messages.json b/public/_locales/ar/messages.json new file mode 100644 index 00000000..068b16f4 --- /dev/null +++ b/public/_locales/ar/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "اسم الامتداد المتضمن بواسطة 'manifest.json', وعرضه بواسطة '@popup/components/Header'." + }, + "appDescription": { + "message": "دعم Client ل ـ Privacy Pass بروتوكول التفويض غير المعروف.", + "description": "وصف اللاحقة المتضمنة بواسطة 'manifest.json'." + }, + "labelFileBackup": { + "message": "نسخة احتياطية", + "description": "العلامة المميزة المتضمنة في اسم الملف المفترض JSON عمل نسخ احتياطية بواسطة '@popup/store'." + }, + "labelAppVersion": { + "message": "النسخة", + "description": "التسمية الخاصة بنسخة الامتداد الحالية التي يتم عرضها بواسطة '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "اسم Cloudflare عرض جهة الاتاحة بواسطة '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "اسم hCaptcha عرض جهة الاتاحة بواسطة '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "الحصول على المزيد من التصاريح!", + "description": "يتم عرض نص mouseover بواسطة '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "عمل نسخة احتياطية لكل المؤخرات", + "description": "معروض بواسطة '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "استعادة P من النسخة الاحتياطية", + "description": "معروض بواسطة '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "محو كل الحمير", + "description": "معروض بواسطة '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "مشاهدة على Github", + "description": "معروض بواسطة '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/bg/messages.json b/public/_locales/bg/messages.json new file mode 100644 index 00000000..1e70021b --- /dev/null +++ b/public/_locales/bg/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "име на разширението, включено в 'manifest.json', и се показва от '@popup/components/Header'." + }, + "appDescription": { + "message": "Клиентска поддръжка за Privacy Pass Анонимно разрешение протокол.", + "description": "описание на разширението, включено в 'manifest.json'." + }, + "labelFileBackup": { + "message": "архивиране.", + "description": "етикет, включен в името на файла по подразбиране на JSON резервни копия, генерирани от '@popup/store'." + }, + "labelAppVersion": { + "message": "Версия:", + "description": "етикет на текущата версия на разширение, показвана от '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Име: Cloudflare доставчик, показан от '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Име: hCaptcha доставчик, показан от '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Още пасове.!", + "description": "mouseover текст, показан от '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Архивиране на всички пропуски", + "description": "се показва от '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Възстановяване на пропуски от архив", + "description": "се показва от '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Изчистете всички.", + "description": "се показва от '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Преглед на: Github", + "description": "се показва от '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/bn/messages.json b/public/_locales/bn/messages.json new file mode 100644 index 00000000..9c4a8728 --- /dev/null +++ b/public/_locales/bn/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "এর মধ্যে অন্তর্ভুক্ত এক্সটেনশনের নাম 'manifest.json', এবং প্রদর্শিত '@popup/components/Header'." + }, + "appDescription": { + "message": "ক্লায়েন্ট সমর্থন Privacy Pass অজ্ঞাতনামা অনুমোদনের প্রোটোকল.", + "description": "এক্সটেনশন এর বর্ণনা 'manifest.json'." + }, + "labelFileBackup": { + "message": "ব্যাকআপ", + "description": "লেবেল অন্তর্ভুক্ত ছিল ডিফল্ট ফাইলের নাম JSON @ info: status '@popup/store'." + }, + "labelAppVersion": { + "message": "সংস্করণ", + "description": "দ্বারা প্রদর্শিত বর্তমান এক্সটেনশন সংস্করণের লেবেল '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "নাম: Cloudflare প্রদানকারী দ্বারা প্রদর্শিত '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "নাম: hCaptcha প্রদানকারী দ্বারা প্রদর্শিত '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "আরো পাশ নিয়ে যাও!", + "description": "দ্বারা প্রদর্শিত মুখ্য লেখা '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "সমস্ত পাসওয়ার্ড ব্যাকআপ করো", + "description": "দ্বারা প্রদর্শিত '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "ব্যাকআপ থেকে পাসওয়ার্ড পুনরুদ্ধার করুন", + "description": "দ্বারা প্রদর্শিত '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "সমস্ত পাসওয়ার্ড মুছে ফেলুন", + "description": "দ্বারা প্রদর্শিত '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "ভিউ Github", + "description": "দ্বারা প্রদর্শিত '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/bs/messages.json b/public/_locales/bs/messages.json new file mode 100644 index 00000000..d2b4540e --- /dev/null +++ b/public/_locales/bs/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "ime produžetka uključeno u 'manifest.json', i prikazuje ih '@popup/components/Header'." + }, + "appDescription": { + "message": "Podrška klijentu za Privacy Pass anonimni autorizacijski protokol.", + "description": "opis produženja uključenog u 'manifest.json'." + }, + "labelFileBackup": { + "message": "sigurnosna kopija", + "description": "oznaka uključena u default ime datoteke JSON sigurnosne kopije generirane '@popup/store'." + }, + "labelAppVersion": { + "message": "Verzija", + "description": "oznaka trenutne verzije proširenja prikazanu '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ime od Cloudflare davatelj je prikazan '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ime od hCaptcha davatelj je prikazan '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Donesi još propusnica.!", + "description": "Tekst koji prikazuje tekst koji se prikazuje '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Napravite sigurnosnu kopiju.", + "description": "Prikazano u '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Vrati Propusnice Iz Backup-a", + "description": "Prikazano u '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Očisti Sve Propusnice", + "description": "Prikazano u '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Pogled na Github", + "description": "Prikazano u '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/cnr/messages.json b/public/_locales/cnr/messages.json new file mode 100644 index 00000000..8b9a0c0c --- /dev/null +++ b/public/_locales/cnr/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Ime produžetka uključeno u 'manifest.json', I prikazala ga je '@popup/components/Header'." + }, + "appDescription": { + "message": "Podrška klijentima za Privacy Pass Anonimni autorizacijski protokol..", + "description": "Prevod i adaptacija: Opis: 'manifest.json'." + }, + "labelFileBackup": { + "message": "Hvala.", + "description": "Oznaka je uključena u zadano ime. JSON Kopije koje su generirale '@popup/store'." + }, + "labelAppVersion": { + "message": "Verzija.", + "description": "Oznaka za trenutnu verziju produženja. '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "I ... Cloudflare Danilo Leksi '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "I ... hCaptcha Danilo Leksi '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Daj mi još propusnice.!", + "description": "Izgovarajući tekst koji se prikazuje '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sve propusnice.", + "description": "Prikazao je '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Povrati propusnice od pojačanja.", + "description": "Prikazao je '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Očistite sve propusnice.", + "description": "Prikazao je '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Pogled na Github", + "description": "Prikazao je '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/cs/messages.json b/public/_locales/cs/messages.json new file mode 100644 index 00000000..ad266353 --- /dev/null +++ b/public/_locales/cs/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "název rozšíření zahrnutého 'manifest.json', a zobrazí se '@popup/components/Header'." + }, + "appDescription": { + "message": "Podpora klienta pro Privacy Pass anonymní autorizační protokol.", + "description": "popis rozšíření zahrnutou 'manifest.json'." + }, + "labelFileBackup": { + "message": "zálohování", + "description": "popisek je obsažen ve výchozím názvu souboru JSON zálohy generované '@popup/store'." + }, + "labelAppVersion": { + "message": "Verze", + "description": "jmenovka aktuální verze rozšíření zobrazená pomocí '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "název Cloudflare poskytovatel zobrazený dle '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "název hCaptcha poskytovatel zobrazený dle '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Získat více průchodů!", + "description": "mouseover text zobrazený pomocí '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Zálohovat všechny pasy", + "description": "zobrazit podle '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Obnovit pasy ze zálohy", + "description": "zobrazit podle '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Vymazat všechny pasy", + "description": "zobrazit podle '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Pohled na Github", + "description": "zobrazit podle '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/cy/messages.json b/public/_locales/cy/messages.json new file mode 100644 index 00000000..721f4891 --- /dev/null +++ b/public/_locales/cy/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "enw estyniad wedi ei gynnwys gan 'manifest.json', ac fe'i dangosir gan '@popup/components/Header'." + }, + "appDescription": { + "message": "Cymorth cleient i Privacy Pass protocol awdurdodi anhysbys.", + "description": "disgrifiad o'r estyniad a gynhwysir ynddo 'manifest.json'." + }, + "labelFileBackup": { + "message": "wrth gefn", + "description": "label wedi ei gynnwys yn enw ffeil rhagosodedig JSON llif gefn a gynhyrchir gan '@popup/store'." + }, + "labelAppVersion": { + "message": "Fersiwn", + "description": "label y fersiwn estyniad cyfredol a ddangosir gan '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "enw Cloudflare darparwr a ddangosir gan '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "enw hCaptcha darparwr a ddangosir gan '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Estyn rhagor o docynnau!", + "description": "Dangos y llygoden dros destun a ddangosir gan '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Cadw Copi Wrth Gefn", + "description": "a ddangosir gan '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Adfer Y Cardiau Wrth Gefn", + "description": "a ddangosir gan '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Clirio'r Holl Docynnau", + "description": "a ddangosir gan '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Golwg ar Github", + "description": "a ddangosir gan '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/da/messages.json b/public/_locales/da/messages.json new file mode 100644 index 00000000..96a62abe --- /dev/null +++ b/public/_locales/da/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Navn på udvidelse inkluderet af 'manifest.json', og vises af '@popup/components/Header'." + }, + "appDescription": { + "message": "Kundesupport til Privacy Pass anonym godkendelsesprotokol.", + "description": "Beskrivelse af udvidelse inkluderet af 'manifest.json'." + }, + "labelFileBackup": { + "message": "sikkerhedskopi", + "description": "etiket, der er inkluderet i standardfilnavn på JSON backups genereret af '@popup/store'." + }, + "labelAppVersion": { + "message": "Version", + "description": "etiket for den aktuelle udvidelsesversion, der vises af '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "navn på Cloudflare Udbyder vist af '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "navn på hCaptcha Udbyder vist af '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Hent flere adgangskort!", + "description": "overtalens tekst, der vises af '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sikkerhedskopiér alle passager", + "description": "vises af '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Genindlæs adgangskoder fra backup", + "description": "vises af '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Ryd alle adgangskoder", + "description": "vises af '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Vis på Github", + "description": "vises af '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/de/messages.json b/public/_locales/de/messages.json new file mode 100644 index 00000000..a213f3d9 --- /dev/null +++ b/public/_locales/de/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Name der Erweiterung, die 'manifest.json', und angezeigt von '@popup/components/Header'." + }, + "appDescription": { + "message": "Clientunterstützung für Privacy Pass anonymes Berechtigungsprotokoll.", + "description": "Beschreibung der Erweiterung, die von 'manifest.json'." + }, + "labelFileBackup": { + "message": "Sicherung", + "description": "Bezeichnung im Standarddateinamen von JSON Sicherungen generiert von '@popup/store'." + }, + "labelAppVersion": { + "message": "Version", + "description": "Bezeichnung der aktuellen Erweiterungsversion angezeigt von '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Name Cloudflare Provider angezeigt von '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Name hCaptcha Provider angezeigt von '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Weitere Arbeitsgänge abrufen!", + "description": "Mouseover-Text angezeigt von '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Alle Arbeitsgänge sichern", + "description": "angezeigt von '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Zurückspeichern von Sicherung aus Sicherung", + "description": "angezeigt von '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Alle Durchgänge löschen", + "description": "angezeigt von '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Anzeigen auf Github", + "description": "angezeigt von '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/el/messages.json b/public/_locales/el/messages.json new file mode 100644 index 00000000..03cdb65c --- /dev/null +++ b/public/_locales/el/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "όνομα της επέκτασης που περιλαμβάνεται από: 'manifest.json', και εμφανίζεται από: '@popup/components/Header'." + }, + "appDescription": { + "message": "Υποστήριξη πελατών για: Privacy Pass ανώνυμο πρωτόκολλο εξουσιοδότησης.", + "description": "περιγραφή της επέκτασης που περιλαμβάνεται: 'manifest.json'." + }, + "labelFileBackup": { + "message": "-backup", + "description": "ετικέτα που περιλαμβάνεται στο προεπιλεγμένο όνομα αρχείου JSON αντίγραφα ασφαλείας που δημιουργήθηκαν από: '@popup/store'." + }, + "labelAppVersion": { + "message": "Έκδοση:", + "description": "ετικέτα της τρέχουσας εκδοχής επέκτασης που εμφανίζεται από '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ονομασια: Cloudflare Ο παροχέας εμφανίζεται από '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ονομασια: hCaptcha Ο παροχέας εμφανίζεται από '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Πάρτε περισσότερα περάσματα!!", + "description": "κείμενο του mouseover που εμφανίζεται '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Εφεδρικά Όλα Τα Passes", + "description": "εμφανίζεται από: '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Επαναφορά Passes Από Εφεδρικά", + "description": "εμφανίζεται από: '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Εκκαθάριση όλων των Passes", + "description": "εμφανίζεται από: '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Προβολή σε: Github", + "description": "εμφανίζεται από: '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json new file mode 100644 index 00000000..60a7a4fd --- /dev/null +++ b/public/_locales/en/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "name of extension included by 'manifest.json', and displayed by '@popup/components/Header'." + }, + "appDescription": { + "message": "Client support for Privacy Pass anonymous authorization protocol.", + "description": "description of extension included by 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "label included in default filename of JSON backups generated by '@popup/store'." + }, + "labelAppVersion": { + "message": "Version", + "description": "label of current extension version displayed by '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "name of Cloudflare provider displayed by '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "name of hCaptcha provider displayed by '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Get more passes!", + "description": "mouseover text displayed by '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup All Passes", + "description": "displayed by '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Restore Passes From Backup", + "description": "displayed by '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Clear All Passes", + "description": "displayed by '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "View on Github", + "description": "displayed by '@popup/components/GithubButton'." + } +} diff --git a/public/_locales/es/messages.json b/public/_locales/es/messages.json new file mode 100644 index 00000000..e1e680c3 --- /dev/null +++ b/public/_locales/es/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "nombre de la extensión incluida en 'manifest.json', y mostrado por '@popup/components/Header'." + }, + "appDescription": { + "message": "Soporte de cliente para Privacy Pass protocolo de autorización anónimo.", + "description": "descripción de la extensión incluida en 'manifest.json'." + }, + "labelFileBackup": { + "message": "copia de seguridad", + "description": "etiqueta incluida en el nombre de archivo predeterminado de JSON copias de seguridad generadas '@popup/store'." + }, + "labelAppVersion": { + "message": "Versión", + "description": "etiqueta de la versión de extensión actual visualizada por '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nombre del Cloudflare proveedor visualizado por '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nombre del hCaptcha proveedor visualizado por '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Obtener más pases!", + "description": "texto de Mouseover visualizado por '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Realizar copia de seguridad de todos", + "description": "visualizada por '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "La restauración pasa de la copia de seguridad", + "description": "visualizada por '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Borrar todos los pases", + "description": "visualizada por '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Ver el Github", + "description": "visualizada por '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/et/messages.json b/public/_locales/et/messages.json new file mode 100644 index 00000000..ddeb0a25 --- /dev/null +++ b/public/_locales/et/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "pikendamise nimi, mis on esitatud 'manifest.json', ja kuvatakse '@popup/components/Header'." + }, + "appDescription": { + "message": "Klienditugi Privacy Pass anonüümne autentimise.", + "description": "laiendamise kirjeldus, mis on esitatud 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "pealdis sisaldub vaikimisi failinimi JSON Varukoopiate genereerimisest '@popup/store'." + }, + "labelAppVersion": { + "message": "Versioon", + "description": "label of cure extension version kuvatakse '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Ravimi nimetus Cloudflare pakkuja kuvamine '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Ravimi nimetus hCaptcha pakkuja kuvamine '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Tooge rohkem läbipääsuload!", + "description": "mouseover tekst kuvatakse '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Varundamine", + "description": "kuvatav '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Taasta Varukoopia Varukoopia", + "description": "kuvatav '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Tühjendage kõik läbipääsuload", + "description": "kuvatav '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Vaade Github", + "description": "kuvatav '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/fi/messages.json b/public/_locales/fi/messages.json new file mode 100644 index 00000000..b0a10860 --- /dev/null +++ b/public/_locales/fi/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Laajennuksen nimi, mukaan lukien 'manifest.json', Ja jotka tulevat näkyviin '@popup/components/Header'." + }, + "appDescription": { + "message": "Asiakkaan tuki Privacy Pass Nimetön valtuutuspöytäkirja.", + "description": "Kuvaus laajennuksesta, johon 'manifest.json'." + }, + "labelFileBackup": { + "message": "Tuki", + "description": "Nimiön oletustiedostonimi JSON Varmuuskopiot, '@popup/store'." + }, + "labelAppVersion": { + "message": "Versio", + "description": "Nykyisen laajennusversion nimiö '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Nimi: Cloudflare Toimittajan osoittama '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Nimi: hCaptcha Toimittajan osoittama '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Ota lisää passeja!", + "description": "Hiirulainen teksti näkyy '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Apujoukot Kaikki Passat", + "description": "On oltava '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Palauta Passar-varmistuskopio", + "description": "On oltava '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Tyhjennä kaikki", + "description": "On oltava '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Näytä Github", + "description": "On oltava '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/fr/messages.json b/public/_locales/fr/messages.json new file mode 100644 index 00000000..63cfccb5 --- /dev/null +++ b/public/_locales/fr/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Nom de l'extension incluse par 'manifest.json', Et affichés par '@popup/components/Header'." + }, + "appDescription": { + "message": "Prise en charge du client pour Privacy Pass Protocole d'autorisation anonyme.", + "description": "Description de l'extension incluse par 'manifest.json'." + }, + "labelFileBackup": { + "message": "Sauvegarde", + "description": "étiquette incluse dans le nom de fichier par défaut de JSON Sauvegardes générées par '@popup/store'." + }, + "labelAppVersion": { + "message": "Version", + "description": "Libellé de la version d'extension en cours affichée par '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Nom de Cloudflare Fournisseur affiché par '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Nom de hCaptcha Fournisseur affiché par '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Obtenir plus de passes!", + "description": "Texte mouseover affiché par '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sauvegarde de tous les passages", + "description": "Affiché par '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Restaurer les passages à partir de la sauvegarde", + "description": "Affiché par '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Effacer toutes les passes", + "description": "Affiché par '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Afficher le Github", + "description": "Affiché par '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/fr_CA/messages.json b/public/_locales/fr_CA/messages.json new file mode 100644 index 00000000..f0e880a4 --- /dev/null +++ b/public/_locales/fr_CA/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "nom de l'extension inclus par 'manifest.json', et affiché par '@popup/components/Header'." + }, + "appDescription": { + "message": "Support client pour Privacy Pass protocole d'autorisation anonyme.", + "description": "description de l'extension incluse par 'manifest.json'." + }, + "labelFileBackup": { + "message": "sauvegarde", + "description": "label inclus dans le nom de fichier par défaut JSON sauvegardes générées par '@popup/store'." + }, + "labelAppVersion": { + "message": "Version", + "description": "libellé de la version d'extension en cours affichée par '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nom de Cloudflare Fournisseur affiché par '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nom de hCaptcha Fournisseur affiché par '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Obtenir plus de passes!", + "description": "texte mouseover affiché par '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sauvegarde de toutes les passes", + "description": "affiché par '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Restaurer les passes à partir de la sauvegarde", + "description": "affiché par '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Effacer toutes les passes", + "description": "affiché par '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Afficher sur Github", + "description": "affiché par '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ga/messages.json b/public/_locales/ga/messages.json new file mode 100644 index 00000000..2ee001a0 --- /dev/null +++ b/public/_locales/ga/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "ainm an fhadaithe atá san áireamh 'manifest.json', agus ar taispeáint ag '@popup/components/Header'." + }, + "appDescription": { + "message": "Tacaíocht cliaint le haghaidh Privacy Pass @ info: inonyName.", + "description": "cur síos ar an síneadh san áireamh 'manifest.json'." + }, + "labelFileBackup": { + "message": "cúltaca", + "description": "lipéad ar áireamh i réamhainm réamhshocraithe JSON Gineadh an t-inneall '@popup/store'." + }, + "labelAppVersion": { + "message": "Leagan", + "description": "lipéid le leagan amach reatha a thaispeánfar ag '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ainm na Cloudflare soláthraí ar taispeáint ag '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ainm na hCaptcha soláthraí ar taispeáint ag '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Faigh pasanna níos mó!", + "description": "@ info: textnot need a translation '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Cúltaca Gach Pasanna", + "description": "taispeáint ag '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Athchóirigh Pasanna Ó Chúltaca", + "description": "taispeáint ag '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Glan Gach Pasanna", + "description": "taispeáint ag '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Amharc ar Github", + "description": "taispeáint ag '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/gu/messages.json b/public/_locales/gu/messages.json new file mode 100644 index 00000000..d5cf0e09 --- /dev/null +++ b/public/_locales/gu/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "એક્સટેન્સનો નામ દ્વારા સમાવેશ થાય છે 'manifest.json', અને પ્રદર્શિત '@popup/components/Header'." + }, + "appDescription": { + "message": "માટે ક્લાયન્ટ આધાર Privacy Pass અનામિક સત્તાધિકરણ પ્રોટોકોલ.", + "description": "એક્સટેન્સનો વર્ણન 'manifest.json'." + }, + "labelFileBackup": { + "message": "બેકઅપ", + "description": "લેબલ મૂળભૂત ફાઈલનામને સમાવેલ છે JSON દ્વારા પેદા થયેલ બેકઅપ '@popup/store'." + }, + "labelAppVersion": { + "message": "આવૃત્તિ", + "description": "વર્તમાન એક્સટેન્સન આવૃત્તિનું લેબલ પ્રદર્શિત '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "નું નામ Cloudflare પ્રદર્શિત પ્રદર્શિત '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "નું નામ hCaptcha પ્રદર્શિત પ્રદર્શિત '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "વધારે પાસ મેળવો!", + "description": "માઉસવેર લખાણ દ્વારા દર્શાવેલ છે '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "બધા પાસા બેકઅપ કરો", + "description": "પ્રદર્શિત '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "બેકઅપ માંથી પાસ પુનઃસંગ્રહો", + "description": "પ્રદર્શિત '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "બધા પાસા સાફ કરો", + "description": "પ્રદર્શિત '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "પર જુઓ Github", + "description": "પ્રદર્શિત '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/he/messages.json b/public/_locales/he/messages.json new file mode 100644 index 00000000..ff2f68a2 --- /dev/null +++ b/public/_locales/he/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "שם הרחבה הנכלל על ידי 'manifest.json', ומוצג על-ידי '@popup/components/Header'." + }, + "appDescription": { + "message": "תמיכת לקוח עבור Privacy Pass פרוטוקול אישור אנונימי.", + "description": "תיאור הרחבה שנכלל על ידי 'manifest.json'." + }, + "labelFileBackup": { + "message": "גיבוי", + "description": "התווית הכלול בשם ברירת המחדל של JSON גיבויים שנוצרו על-ידי '@popup/store'." + }, + "labelAppVersion": { + "message": "גרסה", + "description": "תווית של גרסת ההרחבה הנוכחית המוצגת על ידי '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "שם של Cloudflare ספק המוצג על ידי '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "שם של hCaptcha ספק המוצג על ידי '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "קבלת אישורים נוספים!", + "description": "תמליל mouseover המוצג על ידי '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "גיבוי כל הסיסמאות", + "description": "המוצג על ידי '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "שחזור סיסמאות מתוך גיבוי", + "description": "המוצג על ידי '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "ניקוי כל המעבר", + "description": "המוצג על ידי '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "הצגה ב - Github", + "description": "המוצג על ידי '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/hi/messages.json b/public/_locales/hi/messages.json new file mode 100644 index 00000000..aef4099c --- /dev/null +++ b/public/_locales/hi/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "द्वारा शामिल विस्तार का नाम 'manifest.json', द्वारा प्रदर्शित '@popup/components/Header'." + }, + "appDescription": { + "message": "क्लाइंट समर्थन के लिए Privacy Pass अनाम प्राधिकरण प्रोटोकॉल.", + "description": "द्वारा शामिल विस्तार का विवरण 'manifest.json'." + }, + "labelFileBackup": { + "message": "बैकअप", + "description": "के डिफ़ॉल्ट फ़ाइलनाम में लेबल शामिल है JSON द्वारा उत्पन्न बैकअप '@popup/store'." + }, + "labelAppVersion": { + "message": "संस्करण", + "description": "के द्वारा प्रदर्शित वर्तमान एक्सटेंशन संस्करण का लेबल '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "का नाम Cloudflare द्वारा प्रदर्शित '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "का नाम hCaptcha द्वारा प्रदर्शित '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "अधिक पास प्राप्त करें!", + "description": "द्वारा प्रदर्शित किया जा रहा है '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "सभी बैकअप को बैकअप करें", + "description": "द्वारा प्रदर्शित '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "बैकअप से फिर भंडारित करें (R)", + "description": "द्वारा प्रदर्शित '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "सभी पास साफ करें", + "description": "द्वारा प्रदर्शित '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "पर देखें Github", + "description": "द्वारा प्रदर्शित '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/hr/messages.json b/public/_locales/hr/messages.json new file mode 100644 index 00000000..8df35775 --- /dev/null +++ b/public/_locales/hr/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "ime ekstenzije uključeno u 'manifest.json', i prikazuje '@popup/components/Header'." + }, + "appDescription": { + "message": "Podrška klijenta za Privacy Pass anonimni protokol autorizacije.", + "description": "opis proširenja uključenih u 'manifest.json'." + }, + "labelFileBackup": { + "message": "sigurnosno kopiranje", + "description": "oznaka uključena u default ime datoteke JSON sigurnosne kopije generirane po '@popup/store'." + }, + "labelAppVersion": { + "message": "Inačica", + "description": "oznaka trenutne verzije proširenja koja je prikazana '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ime Cloudflare pružatelj usluge prikazan '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ime hCaptcha pružatelj usluge prikazan '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Dobiti više prolaza!", + "description": "tekst za mouseover prikazan s '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sigurnosno Kopiranje Svih Propusnica", + "description": "prikazan po '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Vraćanje Prolaza Iz Sigurnosne Kopije", + "description": "prikazan po '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Očisti Sve Propusnice", + "description": "prikazan po '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Pogled na Github", + "description": "prikazan po '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/hu/messages.json b/public/_locales/hu/messages.json new file mode 100644 index 00000000..a75241dd --- /dev/null +++ b/public/_locales/hu/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "A által tartalmazott kiterjesztés neve 'manifest.json', és megjelenítve '@popup/components/Header'." + }, + "appDescription": { + "message": "Ügyfél támogatás Privacy Pass Anonim jogosultsági protokoll.", + "description": "A által tartalmazott kiterjesztés leírása 'manifest.json'." + }, + "labelFileBackup": { + "message": "Mentés", + "description": "Az alapértelmezett fájlnévben szereplő címke JSON által előállított mentések '@popup/store'." + }, + "labelAppVersion": { + "message": "Változat", + "description": "Az által megjelenített aktuális kiterjesztési változat címkéje '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "A neve Cloudflare Szolgáltató által megjelenített '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "A neve hCaptcha Szolgáltató által megjelenített '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Szerezz több belépőt!", + "description": "Szöveg által megjelenített szöveg '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Összes tartalék mentése", + "description": "Megjelenítve: '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Mentési osztályok visszaállítása", + "description": "Megjelenítve: '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Összes tábla törlése", + "description": "Megjelenítve: '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Nézet be Github", + "description": "Megjelenítve: '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/id/messages.json b/public/_locales/id/messages.json new file mode 100644 index 00000000..c6c62198 --- /dev/null +++ b/public/_locales/id/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "nama dari ekstensi yang dimasukkan oleh 'manifest.json', dan ditampilkan oleh '@popup/components/Header'." + }, + "appDescription": { + "message": "Dukungan Klien untuk Privacy Pass protokol otorisasi anonim.", + "description": "deskripsi dari ekstensi yang disertakan oleh 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "label termasuk dalam nama berkas baku dari JSON Backup yang dihasilkan oleh '@popup/store'." + }, + "labelAppVersion": { + "message": "Versi", + "description": "label dari versi ekstensi saat ini ditampilkan oleh '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nama dari Cloudflare penyedia yang ditampilkan oleh '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nama dari hCaptcha penyedia yang ditampilkan oleh '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Dapatkan lebih banyak berlalu!", + "description": "teks mouseover yang ditampilkan oleh '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup Semua Melewati", + "description": "Ditampilkan oleh '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Pulihkan Operan Dari Backup", + "description": "Ditampilkan oleh '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Bersihkan Semua Lewat", + "description": "Ditampilkan oleh '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Tampilkan pada Github", + "description": "Ditampilkan oleh '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/it/messages.json b/public/_locales/it/messages.json new file mode 100644 index 00000000..29d8e368 --- /dev/null +++ b/public/_locales/it/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "nome di estensione incluso da 'manifest.json', e visualizzati da '@popup/components/Header'." + }, + "appDescription": { + "message": "Supporto client per Privacy Pass protocollo di autorizzazione anonimo.", + "description": "descrizione dell'estensione inclusa da 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "etichetta inclusa nel nome file predefinito di JSON backup generati da '@popup/store'." + }, + "labelAppVersion": { + "message": "Versione", + "description": "etichetta della versione di estensione corrente visualizzata da '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nome di Cloudflare provider visualizzato da '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nome di hCaptcha provider visualizzato da '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Ricevi più passaggi!", + "description": "mouseover testo visualizzato da '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup Tutti I Passaggi", + "description": "visualizzato da '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Restore Passa Da Backup", + "description": "visualizzato da '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Chiara Tutti I Passaggi", + "description": "visualizzato da '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Vista su Github", + "description": "visualizzato da '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ja/messages.json b/public/_locales/ja/messages.json new file mode 100644 index 00000000..e7ff8251 --- /dev/null +++ b/public/_locales/ja/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "含まれる拡張の名前 'manifest.json', で表示される '@popup/components/Header'." + }, + "appDescription": { + "message": "クライアント・サポート Privacy Pass 匿名許可プロトコル.", + "description": "含まれる拡張の説明 'manifest.json'." + }, + "labelFileBackup": { + "message": "バックアップ", + "description": "デフォルトのファイル名に含まれるラベル JSON バックアップの生成者 '@popup/store'." + }, + "labelAppVersion": { + "message": "バージョン", + "description": "表示される現行拡張バージョンのラベル '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "の名前 Cloudflare 表示されるプロバイダー '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "の名前 hCaptcha 表示されるプロバイダー '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "パスをさらに取得!", + "description": "表示されるムーズオーバー・テキスト '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "すべてのパスのバックアップ", + "description": "表示者 '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "バックアップからのパスの復元", + "description": "表示者 '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "すべてのパスをクリア", + "description": "表示者 '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "表示 Github", + "description": "表示者 '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ko/messages.json b/public/_locales/ko/messages.json new file mode 100644 index 00000000..1875342d --- /dev/null +++ b/public/_locales/ko/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "포함된 확장자의 이름 'manifest.json', 로 표시되고 '@popup/components/Header'." + }, + "appDescription": { + "message": "클라이언트 지원 Privacy Pass 익명의 권한 부여 프로토콜.", + "description": "에 의해 포함된 확장에 대한 설명 'manifest.json'." + }, + "labelFileBackup": { + "message": "백업", + "description": "기본 파일 이름에 레이블이 포함되어 있습니다. JSON 백업에 의해 생성된 백업 '@popup/store'." + }, + "labelAppVersion": { + "message": "버전", + "description": "표시된 현재 확장 버전의 레이블 '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "이름 Cloudflare 공급자에 의해 표시되는 '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "이름 hCaptcha 공급자에 의해 표시되는 '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "더 많은 패스 가져오기!", + "description": "다음으로 표시되는 마우스오버 텍스트 '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "모든 패스 백업", + "description": "표시된 '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "백업으로부터 풀 복원", + "description": "표시된 '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "모든 패스 지우기", + "description": "표시된 '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "보기 Github", + "description": "표시된 '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/lt/messages.json b/public/_locales/lt/messages.json new file mode 100644 index 00000000..0a7fb17c --- /dev/null +++ b/public/_locales/lt/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "išplėtimo pavadinimas, kurį sudaro: 'manifest.json', ir rodoma: '@popup/components/Header'." + }, + "appDescription": { + "message": "Kliento parama Privacy Pass anoniminio leidimo protokolas.", + "description": "išplėtimas, kurį apima: 'manifest.json'." + }, + "labelFileBackup": { + "message": "atsarginė kopija", + "description": "etiketė, įtraukta į numatytąjį failo pavadinimą JSON atsargines kopijas, sukurtas pagal '@popup/store'." + }, + "labelAppVersion": { + "message": "Versija", + "description": "Esamos plėtinės versijos ženklas, matomas '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "pavadinimas Cloudflare Paslaugų teikėjas: '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "pavadinimas hCaptcha Paslaugų teikėjas: '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Gaukite daugiau leidimų!", + "description": "mouseover tekstas, rodomas '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Atsarginės kopijos visi praėjimai", + "description": "rodomi pagal '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Atstatyti pravažiavimas iš atsarginės kopijos", + "description": "rodomi pagal '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Išvalyti Visus Leidimus", + "description": "rodomi pagal '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Vaizdas į Github", + "description": "rodomi pagal '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/lv/messages.json b/public/_locales/lv/messages.json new file mode 100644 index 00000000..9e325a72 --- /dev/null +++ b/public/_locales/lv/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "paplašinājuma nosaukums, ko iekļauj 'manifest.json', , un parāda '@popup/components/Header'." + }, + "appDescription": { + "message": "Klientu atbalsts Privacy Pass anonīms atļaujas protokols.", + "description": "paplašinājuma apraksts, kas iekļauts 'manifest.json'." + }, + "labelFileBackup": { + "message": "Dublējums", + "description": "Noklusētā faila nosaukums JSON , ko ģenerē '@popup/store'." + }, + "labelAppVersion": { + "message": "Versija", + "description": "pašreizējā paplašinājuma versija, ko attēlo '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "vārds, uzvārds Cloudflare Pakalpojumu sniedzējs '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "vārds, uzvārds hCaptcha Pakalpojumu sniedzējs '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Iegūt vairāk caurlaides!", + "description": "iemusever teksts, ko attēlo '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Rezerves kopēšana", + "description": ", kas '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Atjaunot Caurlaides No Rezerves", + "description": ", kas '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Tīrīt visas caurlaides", + "description": ", kas '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Skats uz Github", + "description": ", kas '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ml/messages.json b/public/_locales/ml/messages.json new file mode 100644 index 00000000..3d6a5e6b --- /dev/null +++ b/public/_locales/ml/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "എക്സ്റ്റെന്ഷനിന്റെ പേരു് 'manifest.json', പ്രദര്ശിപ്പിക്കുക '@popup/components/Header'." + }, + "appDescription": { + "message": "ക്ലൈന്റ് പിന്തുണ Privacy Pass അജ്ഞാതമായ അധികാരം പ്രോട്ടോക്കോൾ.", + "description": "എക്സ്റ്റൻഷനുകൾ ഉൾപ്പെടുത്തിയുള്ള വിശദീകരണം 'manifest.json'." + }, + "labelFileBackup": { + "message": "ബാക്കപ്പ്", + "description": "ലേബലിന്റെ സ്വതവേയുള്ള ഫയലിന്റെ പേരു് JSON ബാക്ക്പ് സൃഷ്ടിക്കപ്പെട്ടിരിക്കുന്നു '@popup/store'." + }, + "labelAppVersion": { + "message": "പതിപ്പ്", + "description": "നിലവിലുള്ള എക്സ്റ്റെന്ഷന് പതിപ്പിന്റെ ലേബല് '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "പേരു് Cloudflare പ്രദര്ശിപ്പിച്ച പ്രദര്ശനം '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "പേരു് hCaptcha പ്രദര്ശിപ്പിച്ച പ്രദര്ശനം '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "കൂടുതല് കടന്നുപോകൂ!", + "description": "പ്രദര്ശിപ്പിക്കുന്ന പദാവലി '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "എല്ലാ പാസ്സുകളെയും ബാക്കപ്പ് ചെയ്യുക", + "description": "പ്രദര്ശിപ്പിക്കുക '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "ബാക്കപ്പ് മുതല് പാസ്സുകള് വീണ്ടെടുക്കുക", + "description": "പ്രദര്ശിപ്പിക്കുക '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "എല്ലാ പാസ്സും വൃത്തിയാക്കുക", + "description": "പ്രദര്ശിപ്പിക്കുക '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "കാണുക Github", + "description": "പ്രദര്ശിപ്പിക്കുക '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ms/messages.json b/public/_locales/ms/messages.json new file mode 100644 index 00000000..7d93fa2e --- /dev/null +++ b/public/_locales/ms/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "nama sambungan disertakan dengan 'manifest.json', dan dipaparkan oleh '@popup/components/Header'." + }, + "appDescription": { + "message": "Sokongan klien untuk Privacy Pass protokol keizinan tanpa nama.", + "description": "keterangan sambungan disertakan dengan 'manifest.json'." + }, + "labelFileBackup": { + "message": "sandaran", + "description": "label disertakan dalam nama fail lalai JSON backups dijana oleh '@popup/store'." + }, + "labelAppVersion": { + "message": "Versi", + "description": "label bagi versi sambungan semasa dipaparkan oleh '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nama bagi Cloudflare penyedia dipaparkan oleh '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nama bagi hCaptcha penyedia dipaparkan oleh '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Dapatkan lebih banyak pas!", + "description": "teks searah dipaparkan oleh '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sandar Semua Laluan", + "description": "dipapar oleh '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Pulih Semula Dari Bantuan", + "description": "dipapar oleh '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Kosongkan Semua Laluan", + "description": "dipapar oleh '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Lihat pada Github", + "description": "dipapar oleh '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/mt/messages.json b/public/_locales/mt/messages.json new file mode 100644 index 00000000..bc7c983d --- /dev/null +++ b/public/_locales/mt/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "isem ta ' estensjoni inkluż minn 'manifest.json', u murija minn '@popup/components/Header'." + }, + "appDescription": { + "message": "Klijent appoġġ għall Privacy Pass protokoll awtorizzazzjoni anonima.", + "description": "deskrizzjoni ta ' estensjoni inkluża minn 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "tikketta inkluża fil-filename default ta ' JSON backups iġġenerat minn '@popup/store'." + }, + "labelAppVersion": { + "message": "Verżjoni", + "description": "tikketta tal-verżjoni tal-estensjoni attwali murija minn '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "isem ta ' Cloudflare fornitur muri minn '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "isem ta ' hCaptcha fornitur muri minn '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Ikseb aktar tgħaddi!", + "description": "test mousever murija minn '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup Kollha Jgħaddi", + "description": "murija minn '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Jirrestawraw Jgħaddi Minn Backup", + "description": "murija minn '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Clear All Passe", + "description": "murija minn '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "View on Github", + "description": "murija minn '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/nb/messages.json b/public/_locales/nb/messages.json new file mode 100644 index 00000000..af1dc0a4 --- /dev/null +++ b/public/_locales/nb/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "navn på utvidelse inkludert av 'manifest.json', og vises av '@popup/components/Header'." + }, + "appDescription": { + "message": "Klientstøtte for Privacy Pass anonym autorisasjonsprotokoll.", + "description": "beskrivelse av utvidelse inkludert av 'manifest.json'." + }, + "labelFileBackup": { + "message": "sikkerhetskopiering", + "description": "etikett inkludert i standard filnavn for JSON sikkerhetskopier generert av '@popup/store'." + }, + "labelAppVersion": { + "message": "Versjon", + "description": "etikett av gjeldende utvidelsesversjon vist av '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "navn på Cloudflare leverandør vist av '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "navn på hCaptcha leverandør vist av '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Få flere pasninger!", + "description": "mouseover tekst vist av '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sikkerhetskopier alle passeringer", + "description": "vist av '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Gjenopprett pasninger fra sikkerhetskopi", + "description": "vist av '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Tøm alle passeringer", + "description": "vist av '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Vis på Github", + "description": "vist av '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ne/messages.json b/public/_locales/ne/messages.json new file mode 100644 index 00000000..df5d83d2 --- /dev/null +++ b/public/_locales/ne/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "द्वारा समावेश गरिएको विस्तारको नाम 'manifest.json', र द्वारा प्रदर्शित '@popup/components/Header'." + }, + "appDescription": { + "message": "लागि क्लाइन्ट समर्थन Privacy Pass गुमनाम प्राधिकरण प्रोटोकल.", + "description": "द्वारा समावेश गरिएको विस्तारको वर्णन 'manifest.json'." + }, + "labelFileBackup": { + "message": "जगेडा", + "description": "को पूर्वनिर्धारित फाइलनाममा लेबुल समावेश JSON द्वारा उत्पन्न ब्याकअपहरू '@popup/store'." + }, + "labelAppVersion": { + "message": "संस्करण", + "description": "द्वारा प्रदर्शित वर्तमान विस्तार संस्करणको लेबल '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "नाम Cloudflare द्वारा प्रदर्शित प्रदायक '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "नाम hCaptcha द्वारा प्रदर्शित प्रदायक '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "धेरै पास प्राप्त गर्नुहोस्!", + "description": "द्वारा प्रदर्शित माउस पाठ '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "सबै पासहरू जगेडा", + "description": "द्वारा प्रदर्शित '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "ब्याकअपबाट पासहरू पूर्वावस्थामा ल्याउनुहोस्", + "description": "द्वारा प्रदर्शित '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "सबै पासहरू खाली गर्नुहोस्", + "description": "द्वारा प्रदर्शित '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "मा हेर्नुहोस् Github", + "description": "द्वारा प्रदर्शित '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/nl/messages.json b/public/_locales/nl/messages.json new file mode 100644 index 00000000..aa9f0110 --- /dev/null +++ b/public/_locales/nl/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "naam van de uitbreiding, inclusief 'manifest.json', en wordt afgebeeld door '@popup/components/Header'." + }, + "appDescription": { + "message": "Clientondersteuning voor Privacy Pass anoniem machtigingsprotocol.", + "description": "beschrijving van de uitbreiding, inclusief 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup maken", + "description": "label in standaard bestandsnaam van JSON backups gegenereerd door '@popup/store'." + }, + "labelAppVersion": { + "message": "Versie", + "description": "label van huidige uitbreidingsversie weergegeven door '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "naam van Cloudflare provider afgebeeld door '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "naam van hCaptcha provider afgebeeld door '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Meer pasjes!", + "description": "Mouseover-tekst wordt afgebeeld door '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup van alle passen", + "description": "afgebeeld door '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Terugzetdoorloopt vanaf backup", + "description": "afgebeeld door '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Alle passen wissen", + "description": "afgebeeld door '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Bekijken op Github", + "description": "afgebeeld door '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/pl/messages.json b/public/_locales/pl/messages.json new file mode 100644 index 00000000..39661e37 --- /dev/null +++ b/public/_locales/pl/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Nazwa rozszerzenia dołączonego przez 'manifest.json', i wyświetlane przez '@popup/components/Header'." + }, + "appDescription": { + "message": "Obsługa klienta dla Privacy Pass anonimowy protokół autoryzacji.", + "description": "opis rozszerzenia dołączonego przez 'manifest.json'." + }, + "labelFileBackup": { + "message": "kopia zapasowa", + "description": "etykieta dołączona do domyślnej nazwy pliku JSON kopie zapasowe utworzone przez '@popup/store'." + }, + "labelAppVersion": { + "message": "Wersja", + "description": "etykieta bieżącej wersji rozszerzenia wyświetlana przez '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nazwa Cloudflare Dostawca wyświetlany przez '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nazwa hCaptcha Dostawca wyświetlany przez '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Pobierz więcej wejściów!", + "description": "tekst wyświetlany przez użytkownika mouseover '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Wszystkie wejściówki kopii zapasowej", + "description": "wyświetlane przez '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Odtwórz kopie zapasowe z kopii zapasowej", + "description": "wyświetlane przez '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Wyczyść wszystkie wejściówki", + "description": "wyświetlane przez '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Wyświetl na Github", + "description": "wyświetlane przez '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/pt/messages.json b/public/_locales/pt/messages.json new file mode 100644 index 00000000..5a7137f7 --- /dev/null +++ b/public/_locales/pt/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "nome de extensão incluído por 'manifest.json', e exibido por '@popup/components/Header'." + }, + "appDescription": { + "message": "Suporte ao cliente para Privacy Pass protocolo de autorização de.", + "description": "descrição da extensão incluída por 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "rótulo incluído no arquivo padrão de arquivo de JSON backups gerados por '@popup/store'." + }, + "labelAppVersion": { + "message": "Versão", + "description": "rótulo de versão de extensão atual exibida por '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "nome de Cloudflare provedor exibido por '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "nome de hCaptcha provedor exibido por '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Obter mais passes!", + "description": "texto mouseover exibido por '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup Todos Os Passes", + "description": "exibido por '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Restaurar Passes Do Backup", + "description": "exibido por '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Limpar Todos Os Passes", + "description": "exibido por '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Visualizar em Github", + "description": "exibido por '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ro/messages.json b/public/_locales/ro/messages.json new file mode 100644 index 00000000..e22f7c25 --- /dev/null +++ b/public/_locales/ro/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Denumirea de extensie inclusă de 'manifest.json', și afișată de '@popup/components/Header'." + }, + "appDescription": { + "message": "Suport client pentru Privacy Pass protocol de autorizare anonim.", + "description": "Descrierea extensiei incluse de 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "eticheta inclusă în numele de fișier implicit al JSON backup-uri generate de '@popup/store'." + }, + "labelAppVersion": { + "message": "Versiune", + "description": "eticheta de versiunea de extensie curentă afișată de '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Nume: Cloudflare furnizor afisat de '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Nume: hCaptcha furnizor afisat de '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Obține mai multe treceri!", + "description": "mouseover text afișat de '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Backup Toate Trecerile", + "description": "afişat de '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Restaurarea Trece De La Backup", + "description": "afişat de '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Șterge toate trecerile", + "description": "afişat de '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Vizualizare pe Github", + "description": "afişat de '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ru/messages.json b/public/_locales/ru/messages.json new file mode 100644 index 00000000..9db94e4e --- /dev/null +++ b/public/_locales/ru/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "имя расширения, включаное в 'manifest.json', и показанные '@popup/components/Header'." + }, + "appDescription": { + "message": "Поддержка клиента для Privacy Pass анонимный протокол авторизации.", + "description": "Описание расширения 'manifest.json'." + }, + "labelFileBackup": { + "message": "резервное копирование", + "description": "label включена в имя файла по умолчанию JSON резервные копии, созданные '@popup/store'." + }, + "labelAppVersion": { + "message": "Версия", + "description": "метка текущей версии расширения, отображаемого '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "имя Cloudflare провайдер, показанные '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "имя hCaptcha провайдер, показанные '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Получить больше пропусков!", + "description": "текст mouseover, отображаемый '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Резервное копирование всех пропусков", + "description": "показанные на '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Восстановить проходы из резервной копии", + "description": "показанные на '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Очистить все проходы", + "description": "показанные на '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Показать на Github", + "description": "показанные на '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/si/messages.json b/public/_locales/si/messages.json new file mode 100644 index 00000000..8454ad41 --- /dev/null +++ b/public/_locales/si/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "විසින් ඇතුලත් කරන ලද දිගුවක් 'manifest.json', විසින් පෙන්වයි. '@popup/components/Header'." + }, + "appDescription": { + "message": "සඳහා සහායක සහායක Privacy Pass නිර්නාමික අවසර පත්රය.", + "description": "විසින් ඇතුලත් කරන ලද දිගුවන විස්තරය 'manifest.json'." + }, + "labelFileBackup": { + "message": "උපස්ථ", + "description": "ලේබලය ඇතුලත් පෙරනිමි ගොනු නාමය JSON Name '@popup/store'." + }, + "labelAppVersion": { + "message": "සංස්කරණය", + "description": "විසින් පෙන්වන ලද වර්තමාන දිගහැරිම සංස්කරණය '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "නම Cloudflare විසින් පෙන්වන ලද සපයන්නා '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "නම hCaptcha විසින් පෙන්වන ලද සපයන්නා '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "තව පාස් වෙන්න.!", + "description": "විසින් ප්රදර්ශනය කරන ලද පෙළ '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "සියළුම මගපෙන්වීම", + "description": "විසින් පෙන්විය '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "බැකප් වලින් පාස් නැවත පිහිටුවන්න", + "description": "විසින් පෙන්විය '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "සියළු ගමන් මග පිරිසිදු කරන්න", + "description": "විසින් පෙන්විය '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "දසුන Github", + "description": "විසින් පෙන්විය '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/sk/messages.json b/public/_locales/sk/messages.json new file mode 100644 index 00000000..f4f9aecd --- /dev/null +++ b/public/_locales/sk/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "Názov rozšírenia, ktorý obsahuje 'manifest.json', a zobrazí '@popup/components/Header'." + }, + "appDescription": { + "message": "Podpora klientov pre Privacy Pass anonymný autorizačný.", + "description": "opis rozšírenia zahrnovaného 'manifest.json'." + }, + "labelFileBackup": { + "message": "záloha", + "description": "návestie zahrnuté do predvoleného názvu súboru JSON zálohy generované '@popup/store'." + }, + "labelAppVersion": { + "message": "Verzia", + "description": "návestie aktuálnej verzie rozšírenia, ktoré sa zobrazuje '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "názov Cloudflare poskytovateľ zobrazený '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "názov hCaptcha poskytovateľ zobrazený '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Získať viac priechodov!", + "description": "text, ktorý je zobrazený v ústí '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Zálohovať všetky prechody", + "description": "zobrazený podľa '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Obnoviť prechody zo zálohy", + "description": "zobrazený podľa '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Vyčistiť všetky prechody", + "description": "zobrazený podľa '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Zobraziť na Github", + "description": "zobrazený podľa '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/sl/messages.json b/public/_locales/sl/messages.json new file mode 100644 index 00000000..ca6f37a2 --- /dev/null +++ b/public/_locales/sl/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "ime razširitve, vključeno v 'manifest.json', in se prikaže '@popup/components/Header'." + }, + "appDescription": { + "message": "Podpora za odjemalca za Privacy Pass anonimni protokol za.", + "description": "opis razširitve, ki jo vključuje 'manifest.json'." + }, + "labelFileBackup": { + "message": "varnostna kopija", + "description": "oznaka vključena v privzeto ime datoteke JSON varnostne kopije, ki jih generira '@popup/store'." + }, + "labelAppVersion": { + "message": "Različica", + "description": "oznaka trenutne različice razširitve, ki jo prikazuje '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ime Cloudflare ponudnik prikazal '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ime hCaptcha ponudnik prikazal '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Get več prepustnih!", + "description": "jezikast prikaz besedila, ki ga prikaže '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Varnostna Kopija Vseh Dovolilnice", + "description": "prikazan z '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Obnovi Prepustnice Iz Varnostne Kopije", + "description": "prikazan z '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Počistite Vse Prepustnice", + "description": "prikazan z '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Prikaži v Github", + "description": "prikazan z '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/sr/messages.json b/public/_locales/sr/messages.json new file mode 100644 index 00000000..2f0eb1a1 --- /dev/null +++ b/public/_locales/sr/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "име проширења укључено од стране 'manifest.json', и приказане '@popup/components/Header'." + }, + "appDescription": { + "message": "Подршка за клијента за Privacy Pass анонимни протокол ауторизације.", + "description": "опис проширења укључени од стране 'manifest.json'." + }, + "labelFileBackup": { + "message": "подршка", + "description": "ознака је подразумевано укључена у име фајла JSON Повратне копије генерисане '@popup/store'." + }, + "labelAppVersion": { + "message": "Верзија", + "description": "ознака за актуелну верзију проширења која је приказана '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "име Cloudflare добављач приказао '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "име hCaptcha добављач приказао '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Набавите више додавања!", + "description": "mусео преко текста приказано '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Бацкуп све пролази", + "description": "је приказано '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Врати пропуснице од резервне копије", + "description": "је приказано '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Обриши све пропуснице", + "description": "је приказано '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Прикажи на Github", + "description": "је приказано '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/sv/messages.json b/public/_locales/sv/messages.json new file mode 100644 index 00000000..575c994b --- /dev/null +++ b/public/_locales/sv/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "namn på utökningar som ingår i 'manifest.json', och visas av '@popup/components/Header'." + }, + "appDescription": { + "message": "Klientfunktioner för Privacy Pass anonymt behörighetsprotokoll.", + "description": "Beskrivning av den utökning som ingår i 'manifest.json'." + }, + "labelFileBackup": { + "message": "säkerhetskopiera", + "description": "etikett som ingår i standardfilnamnet för JSON säkerhetskopior som genereras av '@popup/store'." + }, + "labelAppVersion": { + "message": "Version", + "description": "Etikett för aktuell utökningsversion som visas av '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "Namn på Cloudflare leverantör som visas av '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "Namn på hCaptcha leverantör som visas av '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Få fler passningar!", + "description": "mouseoverstext som visas av '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Säkerhetskopiera alla Passes", + "description": "visas av '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Återställ Passes från backup", + "description": "visas av '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Rensa alla Passes", + "description": "visas av '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Visa på Github", + "description": "visas av '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ta/messages.json b/public/_locales/ta/messages.json new file mode 100644 index 00000000..209d0ad1 --- /dev/null +++ b/public/_locales/ta/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "விரிவாக்கத்தின் பெயர் 'manifest.json', & மூலம் தெரியும் '@popup/components/Header'." + }, + "appDescription": { + "message": "உறுப்பினர் ஆதரவு Privacy Pass அநாமதேய அதிகார நெறிமுறை.", + "description": "விரிவாக்கத்தின் விவரம் 'manifest.json'." + }, + "labelFileBackup": { + "message": "காப்பு", + "description": "லேபல் முன்னிருப்பு கோப்புப் பெயரில் சேர்க்கப்பட்டது JSON @ info: status '@popup/store'." + }, + "labelAppVersion": { + "message": "பதிப்பு", + "description": "தற்போதைய விரிவான பதிப்பின் விளக்கம் '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "பெயரை Cloudflare வழங்குபவர் '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "பெயரை hCaptcha வழங்குபவர் '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "அதிக கடவுச்சொற்கள்!", + "description": "முழுமையான உரை மூலம் தெரியும் '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "எல்லா கடவுச்சொல்", + "description": "Name '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "பின்புலிருந்து கடவுச்சொல் மீட்கவும்", + "description": "Name '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "அனைத்து வாசிகளையும் துடைக்க", + "description": "Name '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "காட்சி Github", + "description": "Name '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/te/messages.json b/public/_locales/te/messages.json new file mode 100644 index 00000000..1b4511f6 --- /dev/null +++ b/public/_locales/te/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "ఎక్స్టెన్షన్ పేరును 'manifest.json', మరియు ప్రదర్శించబడినది '@popup/components/Header'." + }, + "appDescription": { + "message": "క్లయింట్ మద్దతుName Privacy Pass అనామక అధికారిత ప్రోటోకాల్.", + "description": "విస్తీర్ణము యొక్క వివరణ 'manifest.json'." + }, + "labelFileBackup": { + "message": "బ్యాకప్", + "description": "లేబుల్ అప్రమేయ ఫైల్ పేరు JSON Name '@popup/store'." + }, + "labelAppVersion": { + "message": "వెర్షన్", + "description": "ద్వారా ప్రదర్శించబడిన ప్రస్తుత విస్తరణ వెర్షన్ యొక్క లేబుల్ '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "పేరు Cloudflare ప్రొవైడర్ ద్వారా ప్రదర్శించబడినది '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "పేరు hCaptcha ప్రొవైడర్ ద్వారా ప్రదర్శించబడినది '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "ఎక్కువ పాస్ పొందండి!", + "description": "వున్న వచనమును చూపుము '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "బ్యాక్అప్ అన్ని పాస్", + "description": "ప్రదర్శించబడినది '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "బ్యాక్అప్ నుండి పాస్ ను పునఃప్రారంభించుము", + "description": "ప్రదర్శించబడినది '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "అన్ని పాస్ లను శుభ్రముచేయుము", + "description": "ప్రదర్శించబడినది '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "వీక్షణం Github", + "description": "ప్రదర్శించబడినది '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/th/messages.json b/public/_locales/th/messages.json new file mode 100644 index 00000000..189566d2 --- /dev/null +++ b/public/_locales/th/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "ชื่อของส่วนขยายที่รวมไว้โดย 'manifest.json', และแสดงโดย '@popup/components/Header'." + }, + "appDescription": { + "message": "การสนับสนุนไคลเอ็นต์สำหรับ Privacy Pass โปรโตคอลการพิสูจน์ตัวตน.", + "description": "รายละเอียดของส่วนขยายที่รวมโดย 'manifest.json'." + }, + "labelFileBackup": { + "message": "สำรองข้อมูล", + "description": "เลเบลรวมอยู่ในชื่อไฟล์ดีฟอลต์ของ JSON สำรองข้อมูลที่สร้างโดย '@popup/store'." + }, + "labelAppVersion": { + "message": "เวอร์ชัน", + "description": "เลเบลของเวอร์ชันส่วนขยายปัจจุบันที่แสดงโดย '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ชื่อของ Cloudflare ผู้ให้บริการที่แสดงโดย '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ชื่อของ hCaptcha ผู้ให้บริการที่แสดงโดย '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "รับบัตรผ่าน!", + "description": "Mouse over ข้อความที่แสดงโดย '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "สำรองข้อมูลผ่านทั้งหมด", + "description": "แสดงโดย '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "เรียกคืนผ่านจากสำเนาสำรอง", + "description": "แสดงโดย '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "ล้างรหัสผ่านทั้งหมด", + "description": "แสดงโดย '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "ดูบน Github", + "description": "แสดงโดย '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/tr/messages.json b/public/_locales/tr/messages.json new file mode 100644 index 00000000..08682965 --- /dev/null +++ b/public/_locales/tr/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "buna dahil olan uzantı adı 'manifest.json', ve görüntülenen '@popup/components/Header'." + }, + "appDescription": { + "message": "İstemci desteği Privacy Pass anonim yetkilendirme iletişim kuralı.", + "description": "içinde yer alan uzantının açıklaması 'manifest.json'." + }, + "labelFileBackup": { + "message": "yedekleme", + "description": "varsayılan dosya adı olan etiket JSON tarafından oluşturulan yedeklemeler '@popup/store'." + }, + "labelAppVersion": { + "message": "Sürüm", + "description": "Görüntülenen yürürlükteki uzantı sürümünün etiketi: '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "adı Cloudflare sağlayıcı tarafından görüntülenen '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "adı hCaptcha sağlayıcı tarafından görüntülenen '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Daha fazla pas al!", + "description": "fare tarafından görüntülenen mouseover metni '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Tüm Geçişleri Yedekle", + "description": "görüntülenen '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Yedekten Geçişleri Geri Yükle", + "description": "görüntülenen '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Tüm Geçişleri Temizle", + "description": "görüntülenen '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Görüntüle: Github", + "description": "görüntülenen '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/uk/messages.json b/public/_locales/uk/messages.json new file mode 100644 index 00000000..3642a1f5 --- /dev/null +++ b/public/_locales/uk/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "назва розширення, включено до 'manifest.json', і буде показано '@popup/components/Header'." + }, + "appDescription": { + "message": "Підтримка клієнта Privacy Pass анонімний протокол розпізнавання.", + "description": "опис суфікса 'manifest.json'." + }, + "labelFileBackup": { + "message": "backup", + "description": "мітка з міткою, включено до типового файла JSON створення резервних копій '@popup/store'." + }, + "labelAppVersion": { + "message": "Версія", + "description": "мітка поточної версії розширення, яку буде показано '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "ім ' я Cloudflare Постачальник показу '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "ім ' я hCaptcha Постачальник показу '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Отримати більше пропусків!", + "description": "mouseext text, показаних '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Резервувати всі пропуски", + "description": "Відображено '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Відновити пропуски з резервної копії", + "description": "Відображено '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Очистити всі пропуски", + "description": "Відображено '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Переглянути Github", + "description": "Відображено '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/ur/messages.json b/public/_locales/ur/messages.json new file mode 100644 index 00000000..609dcda8 --- /dev/null +++ b/public/_locales/ur/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "توسیع کے نام پر شامل 'manifest.json', اور دکھایا. '@popup/components/Header'." + }, + "appDescription": { + "message": "کے لئے کلائنٹ کی حمایت Privacy Pass گمنام اجازت نامہ.", + "description": "توسیع کی تفصیل شامل 'manifest.json'." + }, + "labelFileBackup": { + "message": "بیک اپ", + "description": "کا لیبل پہلے سے طے شدہ فائل میں شامل JSON کی طرف سے پیدا بیک اپ '@popup/store'." + }, + "labelAppVersion": { + "message": "ورژن", + "description": "موجودہ توسیع شدہ ورژن کا لیبل لگا کر آویزاں کریں '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "کا نام Cloudflare فراہم کردہ فراہم کار '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "کا نام hCaptcha فراہم کردہ فراہم کار '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "مزید گزر جاؤ!", + "description": "Mouseover کے ٹیکسٹ کی نمائش '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "بیک اپ تمام پاسورڈ", + "description": "کی نمائش '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "بیک اپ سے ریمور پاسورڈ", + "description": "کی نمائش '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "واضح تمام پاسورڈ", + "description": "کی نمائش '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "دیکھیں Github", + "description": "کی نمائش '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/vi/messages.json b/public/_locales/vi/messages.json new file mode 100644 index 00000000..1270598d --- /dev/null +++ b/public/_locales/vi/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "tên phần mở rộng bao gồm bởi 'manifest.json', và hiển thị bởi '@popup/components/Header'." + }, + "appDescription": { + "message": "Hỗ trợ khách hàng cho Privacy Pass giao thức ủy quyền.", + "description": "mô tả phần mở rộng bao gồm 'manifest.json'." + }, + "labelFileBackup": { + "message": "sao lưu", + "description": "Nhãn bao gồm tên tập tin mặc định của JSON lưu lại sau khi tạo '@popup/store'." + }, + "labelAppVersion": { + "message": "Phiên bản", + "description": "nhãn phiên bản mở rộng hiện tại hiển thị bởi '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "tên của Cloudflare được hiển thị bởi '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "tên của hCaptcha được hiển thị bởi '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "Get more passes!", + "description": "Văn bản mouseover hiển thị bởi '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "Sao lưu tất cả", + "description": "hiển thị bởi '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "Khôi Phục Thông Qua Sao Lưu", + "description": "hiển thị bởi '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "Xóa tất cả", + "description": "hiển thị bởi '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "Xem trên Github", + "description": "hiển thị bởi '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/zh/messages.json b/public/_locales/zh/messages.json new file mode 100644 index 00000000..2234e2db --- /dev/null +++ b/public/_locales/zh/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "扩展名所包含的扩展名的名称 'manifest.json', 并显示为 '@popup/components/Header'." + }, + "appDescription": { + "message": "客户机支持 Privacy Pass 匿名授权协议.", + "description": "扩展的描述 'manifest.json'." + }, + "labelFileBackup": { + "message": "备份", + "description": "缺省文件名中包含的标签 JSON 生成的备份 '@popup/store'." + }, + "labelAppVersion": { + "message": "版本", + "description": "当前扩展版本显示的标签 '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "名称 Cloudflare 提供者显示者 '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "名称 hCaptcha 提供者显示者 '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "获取更多通行证!", + "description": "显示的鼠标悬停文本 '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "备份所有传递", + "description": "显示的 '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "从备份恢复传递", + "description": "显示的 '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "清除所有传递", + "description": "显示的 '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "查看 Github", + "description": "显示的 '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/_locales/zh_TW/messages.json b/public/_locales/zh_TW/messages.json new file mode 100644 index 00000000..8f0b2a8a --- /dev/null +++ b/public/_locales/zh_TW/messages.json @@ -0,0 +1,46 @@ +{ + "appName": { + "message": "Privacy Pass", + "description": "包含的延伸名稱 'manifest.json', 並由顯示 '@popup/components/Header'." + }, + "appDescription": { + "message": "的用戶端支援 Privacy Pass 匿名授權通訊協定.", + "description": "說明的延伸說明 'manifest.json'." + }, + "labelFileBackup": { + "message": "備份", + "description": "預設檔名中包含的標籤 JSON 備份產生的 '@popup/store'." + }, + "labelAppVersion": { + "message": "版本", + "description": "顯示現行延伸版本的標籤 '@popup/components/Header'." + }, + "providerNameCloudflare": { + "message": "Cloudflare", + "description": "名 Cloudflare 顯示的提供者 '@popup/components/CloudflareButton'." + }, + "providerNameHcaptcha": { + "message": "hCaptcha", + "description": "名 hCaptcha 顯示的提供者 '@popup/components/HcaptchaButton'." + }, + "ctaGetMorePasses": { + "message": "取得更多通行證!", + "description": "顯示的 mouseover 文字 '@popup/components/PassButton'." + }, + "ctaBackupAllPasses": { + "message": "備份所有通道", + "description": "顯示者 '@popup/components/BackupButton'." + }, + "ctaRestorePasses": { + "message": "從備份還原傳遞", + "description": "顯示者 '@popup/components/RestoreButton'." + }, + "ctaClearAllPasses": { + "message": "清除所有傳遞", + "description": "顯示者 '@popup/components/ClearButton'." + }, + "ctaViewOnGithub": { + "message": "檢視於 Github", + "description": "顯示者 '@popup/components/GithubButton'." + } +} \ No newline at end of file diff --git a/public/manifest.json b/public/manifest.json index 3a5edf12..b62830aa 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,8 +1,9 @@ { - "name": "Privacy Pass", + "name": "__MSG_appName__", + "description": "__MSG_appDescription__", + "version": "3.7.2", "manifest_version": 2, - "description": "Client support for Privacy Pass anonymous authorization protocol.", - "version": "3.0.0", + "default_locale": "en", "icons": { "32": "icons/32/gold.png", "48": "icons/48/gold.png", @@ -24,5 +25,10 @@ "default_icon": "icons/32/grey.png", "default_title": "Privacy Pass", "default_popup": "popup.html" + }, + "browser_specific_settings": { + "gecko": { + "id": "challenge-bypass-extension@privacypass.github.io" + } } } diff --git a/public/restore.html b/public/restore.html new file mode 100644 index 00000000..47771f4b --- /dev/null +++ b/public/restore.html @@ -0,0 +1,9 @@ + + + + + + +
+ + diff --git a/src/background/crypto/pseudorandom-number-generators/hkdf.js b/src/background/crypto/pseudorandom-number-generators/hkdf.js new file mode 100644 index 00000000..5bb3195c --- /dev/null +++ b/src/background/crypto/pseudorandom-number-generators/hkdf.js @@ -0,0 +1,44 @@ +import sjcl from 'sjcl'; + +/** + * hkdf - The HMAC-based Key Derivation Function + * based on https://github.com/mozilla/node-hkdf + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * @param {bitArray} ikm Initial keying material + * @param {integer} length Length of the derived key in bytes + * @param {bitArray} info Key derivation data + * @param {bitArray} salt Salt + * @param {sjcl.hash} hash hash function + * @return {bitArray} + */ +export function evaluateHkdf(ikm, length, info, salt, hash) { + const mac = new sjcl.misc.hmac(salt, hash); + mac.update(ikm); + const prk = mac.digest(); + + const hashLength = Math.ceil(sjcl.bitArray.bitLength(prk) / 8); + const numBlocks = Math.ceil(length / hashLength); + if (numBlocks > 255) { + throw new Error( + `[privacy-pass]: HKDF error, number of proposed iterations too large: ${numBlocks}`, + ); + } + + let prev = sjcl.codec.hex.toBits(''); + let output = ''; + for (let i = 0; i < numBlocks; i++) { + const hmac = new sjcl.misc.hmac(prk, hash); + const input = sjcl.bitArray.concat( + sjcl.bitArray.concat(prev, info), + sjcl.codec.utf8String.toBits(String.fromCharCode(i + 1)), + ); + hmac.update(input); + prev = hmac.digest(); + output += sjcl.codec.hex.fromBits(prev); + } + return sjcl.bitArray.clamp(sjcl.codec.hex.toBits(output), length * 8); +} diff --git a/src/background/crypto/pseudorandom-number-generators/shake.ts b/src/background/crypto/pseudorandom-number-generators/shake.ts new file mode 100644 index 00000000..f033e120 --- /dev/null +++ b/src/background/crypto/pseudorandom-number-generators/shake.ts @@ -0,0 +1,6 @@ +import createKeccakHash, { Shake, ShakeAlgorithm } from 'keccak'; + +export function createShake256(): Shake { + const algorithm: ShakeAlgorithm = 'shake256'; + return createKeccakHash(algorithm); +} diff --git a/src/background/crypto/voprf.d.ts b/src/background/crypto/voprf.d.ts new file mode 100644 index 00000000..1badee72 --- /dev/null +++ b/src/background/crypto/voprf.d.ts @@ -0,0 +1,77 @@ +export type Point = unknown; +export type Bytes = unknown; +export type BigNum = { toString(): string }; + +export type Curve = 'p256'; +export type Hash = 'sha256'; +export type HashMethod = 'increment' | 'swu'; +export type HashLabel = 'H2C-P256-SHA256-SSWU-' | string; + +export interface ECSettings { + curve: any; + hash: Hash; + method: HashMethod; + label?: HashLabel; +} + +export const defaultECSettings: ECSettings; + +export function sec1Encode(point: Point, compressed: boolean): any; +export function sec1EncodeToBase64(point: Point, compressed: boolean): string; +export function getBigNumFromBytes(bytes: any): BigNum; +export function newBigNum(encoded: string): BigNum; +export function getBytesFromString(str: any): any; +export function getBase64FromBytes(bytes: any): any; +export function getBase64FromString(str: any): any; + +export class VOPRF { + private CURVE: any; + private CURVE_H2C_HASH: Hash; + private CURVE_H2C_METHOD: HashMethod; + private CURVE_H2C_LABEL: HashLabel | void; + + constructor(h2cParams: ECSettings | void): void; + getActiveECSettings(): ECSettings; + newRandomPoint(): { data: Bytes; point: Point }; + sec1DecodeFromBase64(encoded: string): Point; + sec1DecodeFromBytes(sec1Bytes: Bytes): Point; + blindPoint(point: Point): { blind: BigNum; point: Point }; + unblindPoint(factor: BigNum, blindedPoint: Point): Point; + verifyConfiguration(publicKey: string, config: any, signature: string): boolean; + verifyProof( + proof: string, + tokens: unknown[], + signatures: { points: Point[]; compressed: boolean }, + commitments: any, + prngName: string, + ): boolean; + deriveKey(N: Point, token: any): any; + createRequestBinding(key: any, data: any): any; + getCurvePoints(signatures: string[]): { + points: Point[]; + compressed: boolean; + }; + + private decompressPoint(bytes: Bytes): Point | null; + private parsePublicKeyfromPEM(pemPublicKey: string): any; + private recomputeComposites( + tokens: unknown[], + signatures: { points: Point[]; compressed: boolean }, + pointG: Point, + pointH: Point, + prngName: string + ): {M: Point; Z: Point}; + private computePRNGScalar( + prng: any, + seed: string, + salt?: any + ): BigNum; + private computeSeed( + chkM: any, + chkZ: Point[], + pointG: Point, + pointH: Point + ): string; + private hashAndInc(seed: any, hash: any, label: any): Point; + private h2Curve(alpha: any, ecSettings: ECSettings): Point; +} diff --git a/src/background/crypto/voprf.js b/src/background/crypto/voprf.js new file mode 100644 index 00000000..3a97818e --- /dev/null +++ b/src/background/crypto/voprf.js @@ -0,0 +1,924 @@ +/** + * This implements a 2HashDH-based token scheme using the SJCL ecc package. + * + * @author: George Tankersley + * @author: Alex Davidson + */ + +import 'asn1-parser'; + +import sjcl from 'sjcl'; + +import { evaluateHkdf } from './pseudorandom-number-generators/hkdf.js'; +import { createShake256 } from './pseudorandom-number-generators/shake.ts'; + +// ----------------------------------------------------------------------------- +// constant values and static methods + +let PEM; +let ASN1; +let crypto; +if (typeof window !== 'undefined') { + PEM = window.PEM; + ASN1 = window.ASN1; + crypto = window.crypto; +} + +const BATCH_PROOF_PREFIX = 'batch-proof='; +const MASK = ['0xff', '0x1', '0x3', '0x7', '0xf', '0x1f', '0x3f', '0x7f']; + +const DIGEST_INEQUALITY_ERR = '[privacy-pass]: Recomputed digest does not equal received digest'; +const PARSE_ERR = '[privacy-pass]: Error parsing proof'; + +// 1.2.840.10045.3.1.7 point generation seed +const INC_H2C_LABEL = sjcl.codec.hex.toBits( + '312e322e3834302e31303034352e332e312e3720706f696e742067656e65726174696f6e2073656564', +); +const SSWU_H2C_LABEL = 'H2C-P256-SHA256-SSWU-'; + +export const defaultECSettings = { + curve: 'p256', + hash: 'sha256', + method: 'increment', +}; + +/** + * Multiplies the point P with the scalar k and outputs kP + * @param {sjcl.bn} k scalar + * @param {sjcl.ecc.point} P curve point + * @return {sjcl.ecc.point} + */ +function _scalarMult(k, P) { + const Q = P.mult(k); + return Q; +} + +/** + * Encodes a curve point as bytes in SEC1 uncompressed format + * @param {sjcl.ecc.point} P + * @param {bool} compressed + * @return {sjcl.codec.bytes} + */ +export function sec1Encode(P, compressed) { + let out = []; + if (!compressed) { + const xyBytes = sjcl.codec.bytes.fromBits(P.toBits()); + out = [0x04].concat(xyBytes); + } else { + const xBytes = sjcl.codec.bytes.fromBits(P.x.toBits()); + const y = P.y.normalize(); + const sign = y.limbs[0] & 1 ? 0x03 : 0x02; + out = [sign].concat(xBytes); + } + return out; +} + +/** + * Encodes a curve point into bits for using as input to hash functions etc + * @param {sjcl.ecc.point} point curve point + * @param {bool} compressed flag indicating whether points have been compressed + * @return {sjcl.bitArray} + */ +function sec1EncodeToBits(point, compressed) { + return sjcl.codec.bytes.toBits(sec1Encode(point, compressed)); +} + +/** + * Encodes a point into a base 64 string + * @param {sjcl.ecc.point} point + * @param {bool} compressed + * @return {string} + */ +export function sec1EncodeToBase64(point, compressed) { + return sjcl.codec.base64.fromBits(sec1EncodeToBits(point, compressed)); +} + +/** + * Checks that the signed points from the IssueResponse have consistent + * compression + * @param {Object} compression compression object to be checked for consistency + * @param {bool} setting new setting based on point data + * @return {bool} + */ +function validResponseCompression(compression, setting) { + if (!compression.set) { + compression.on = setting; + compression.set = true; + } else if (compression.on !== setting) { + return false; + } + return true; +} + +// Commitments verification + +/** + * Parse a PEM-encoded signature. + * @param {string} pemSignature - A signature in PEM format. + * @return {sjcl.bitArray} a signature object for sjcl library. + */ +function parseSignaturefromPEM(pemSignature) { + try { + const bytes = PEM.parseBlock(pemSignature); + const json = ASN1.parse(bytes.der); + const r = sjcl.codec.bytes.toBits(json.children[0].value); + const s = sjcl.codec.bytes.toBits(json.children[1].value); + return sjcl.bitArray.concat(r, s); + } catch (e) { + throw new Error('[privacy-pass]: Failed on parsing commitment signature. ' + e.message); + } +} + +/** + * Returns a decoded DLEQ proof as an object that can be verified + * @param {Object} bp batch proof as encoded JSON + * @return {Object} DLEQ proof object + */ +function retrieveProof(bp) { + let dleqProof; + try { + dleqProof = parseDleqProof(atob(bp.P)); + } catch (e) { + console.error(`${PARSE_ERR}: ${e}`); + return; + } + return dleqProof; +} + +/** + * Decode proof string and remove prefix + * @param {string} proof base64-encoded batched DLEQ proof + * @return {Object} JSON batched DLEQ proof + */ +function getMarshaledBatchProof(proof) { + let proofStr = atob(proof); + if (proofStr.indexOf(BATCH_PROOF_PREFIX) === 0) { + proofStr = proofStr.substring(BATCH_PROOF_PREFIX.length); + } + return JSON.parse(proofStr); +} + +/** + * Decode the proof that is sent into an Object + * @param {string} proofStr proof JSON as string + * @return {Object} + */ +function parseDleqProof(proofStr) { + const dleqProofM = JSON.parse(proofStr); + const dleqProof = {}; + dleqProof.R = getBigNumFromB64(dleqProofM.R); + dleqProof.C = getBigNumFromB64(dleqProofM.C); + return dleqProof; +} + +/** + * Return a bignum from a base64-encoded string + * @param {string} b64Str + * @return {sjcl.bn} + */ +function getBigNumFromB64(b64Str) { + const bits = sjcl.codec.base64.toBits(b64Str); + return sjcl.bn.fromBits(bits); +} + +/** + * Return a big number from an array of bytes + * @param {sjcl.codec.bytes} bytes + * @return {sjcl.bn} + */ +export function getBigNumFromBytes(bytes) { + const bits = sjcl.codec.bytes.toBits(bytes); + return sjcl.bn.fromBits(bits); +} + +/** + * Return a big number from hex-encoded string + * @param {string} hex hex-encoded string + * @return {sjcl.bn} + */ +function getBigNumFromHex(hex) { + return sjcl.bn.fromBits(sjcl.codec.hex.toBits(hex)); +} + +const p256Curve = sjcl.ecc.curves.c256; +const precomputedP256 = { + // a=-3, but must be reduced mod p for P256; otherwise, + // inverseMod function loops forever. + A: p256Curve.a.fullReduce(), + B: p256Curve.b, + baseField: p256Curve.field, + c1: p256Curve.b.mul(-1).mul(p256Curve.a.inverseMod(p256Curve.field.modulus)), + c2: p256Curve.field.modulus.sub(1).cnormalize().halveM(), + sqrt: p256Curve.field.modulus.add(1).cnormalize().halveM().halveM(), +}; + +/** + * Converts the number x into a byte array of length n + * @param {Number} x + * @param {Number} n + * @return {sjcl.codec.bytes} + */ +function i2osp(x, n) { + const bytes = []; + for (let i = n - 1; i > -1; i--) { + bytes[i] = x & 0xff; + x = x >> 8; + } + + if (x > 0) { + throw new Error(`[privacy-pass]: number to convert (${x}) is too long for ${n} bytes.`); + } + return bytes; +} + +/** + * hashes bits to the base field (as described in + * draft-irtf-cfrg-hash-to-curve) + * @param {sjcl.bitArray} x bits of element to be translated + * @param {sjcl.ecc.curve} curve elliptic curve + * @param {sjcl.hash} hash hash function object + * @param {string} label context label for domain separation + * @return {int} integer in the base field of curve + */ +function h2Base(x, curve, hash, label) { + const dataLen = sjcl.codec.bytes.fromBits(x).length; + const h = new hash(); + h.update('h2b'); + h.update(label); + h.update(sjcl.codec.bytes.toBits(i2osp(dataLen, 4))); + h.update(x); + const t = h.finalize(); + const y = curve.field.fromBits(t).cnormalize(); + return y; +} + +/** + * hashes bits onto affine curve point using simplified SWU encoding algorithm + * Not constant-time due to conditional check + * @param {sjcl.bitArray} alpha bits to be encoded + * @param {sjcl.ecc.curve} activeCurve elliptic curve + * @param {sjcl.hash} hash hash function for hashing bytes to base field + * @param {String} label + * @return {sjcl.ecc.point} curve point + */ +function simplifiedSWU(alpha, activeCurve, hash, label) { + const params = getCurveParams(activeCurve); + const u = h2Base(alpha, activeCurve, hash, label); + const { X, Y } = computeSWUCoordinates(u, params); + const point = new sjcl.ecc.point(activeCurve, X, Y); + if (!point.isValid()) { + throw new Error(`[privacy-pass]: Generated point is not on curve, X: ${X}, Y: ${Y}`); + } + return point; +} + +/** + * Compute (X,Y) coordinates from integer u + * Operations taken from draft-irtf-cfrg-hash-to-curve.txt at commit + * cea8485220812a5d371deda25b5eca96bd7e6c0e + * @param {sjcl.bn} u integer to map + * @param {Object} params curve parameters + * @return {Object} curve coordinates + */ +function computeSWUCoordinates(u, params) { + const { A, B, baseField, c1, c2, sqrt } = params; + const p = baseField.modulus; + const t1 = u.square().mul(-1); // steps 2-3 + const t2 = t1.square(); // step 4 + let x1 = t2.add(t1); // step 5 + x1 = x1.inverse(); // step 6 + x1 = x1.add(1); // step 7 + x1 = x1.mul(c1); // step 8 + + let gx1 = x1.square().mod(p); // steps 9-12 + gx1 = gx1.add(A); + gx1 = gx1.mul(x1); + gx1 = gx1.add(B); + gx1 = gx1.mod(p); + + const x2 = t1.mul(x1); // step 13 + let gx2 = x2.square().mod(p); // step 14-17 + gx2 = gx2.add(A); + gx2 = gx2.mul(x2); + gx2 = gx2.add(B); + gx2 = gx2.mod(p); + + const e = new baseField(gx1.powermod(c2, p)).equals(new sjcl.bn(1)); // step 18 + const X = cmov(x2, x1, e, baseField); // step 19 + const gx = cmov(gx2, gx1, e, baseField); // step 20 + let y1 = gx.powermod(sqrt, p); // step 21 + // choose the positive (the smallest) root + const r = c2.greaterEquals(y1); + let y2 = y1.mul(-1).mod(p); + const Y = cmov(y2, y1, r, baseField); + return { X: X, Y: Y }; +} + +/** + * Return the parameters for the active curve + * @param {sjcl.ecc.curve} curve elliptic curve + * @return {p;A;B} + */ +function getCurveParams(curve) { + let curveParams; + switch (sjcl.ecc.curveName(curve)) { + case 'c256': + curveParams = precomputedP256; + break; + default: + throw new Error( + '[privacy-pass]: Incompatible curve chosen for H2C: ' + sjcl.ecc.curveName(curve), + ); + } + return curveParams; +} + +/** + * Conditional move selects x or y depending on the bit input. + * @param {sjcl.bn} x is a big number + * @param {sjcl.bn} y is a big number + * @param {boolean} b is a bit + * @param {sjcl.bn} field is the prime field used. + * @return {sjcl.bn} returns x is b=0, otherwise return y. + */ +function cmov(x, y, b, field) { + let z = new field(); + const m = z.radixMask; + const m0 = m & (m + b); + const m1 = m & (m + !b); + x.fullReduce(); + y.fullReduce(); + for (let i = Math.max(x.limbs.length, y.limbs.length) - 1; i >= 0; i--) { + z.limbs.unshift((x.getLimb(i) & m0) ^ (y.getLimb(i) & m1)); + } + return z.mod(field.modulus); +} + +export function newBigNum(s) { + return new sjcl.bn(s); +} + +export function getBytesFromString(str) { + const bits = sjcl.codec.utf8String.toBits(str); + const bytes = sjcl.codec.bytes.fromBits(bits); + return bytes; +} + +export function getBase64FromBytes(bytes) { + const bits = sjcl.codec.bytes.toBits(bytes); + const encoded = sjcl.codec.base64.fromBits(bits); + return encoded; +} + +export function getBase64FromString(str) { + const bits = sjcl.codec.utf8String.toBits(str); + const encoded = sjcl.codec.base64.fromBits(bits); + return encoded; +} + +// ----------------------------------------------------------------------------- +// encapsulated class + +export class VOPRF { + CURVE; + CURVE_H2C_HASH; + CURVE_H2C_METHOD; + CURVE_H2C_LABEL; + + /** + * Sets the curve parameters for the current session based on the contents of + * activeConfig.h2c-params + * @param h2cParams + */ + constructor(h2cParams) { + if (!h2cParams || !(h2cParams instanceof Object)) + h2cParams = defaultECSettings; + + const curveStr = h2cParams.curve; + const hashStr = h2cParams.hash; + const methodStr = h2cParams.method; + + switch (curveStr) { + case 'p256': + if (methodStr != 'swu' && methodStr != 'increment') { + throw new Error( + "[privacy-pass]: Incompatible h2c method: '" + + methodStr + + "', for curve " + + curveStr, + ); + } else if (hashStr != 'sha256') { + throw new Error( + "[privacy-pass]: Incompatible h2c hash: '" + + hashStr + + "', for curve " + + curveStr, + ); + } + this.CURVE = sjcl.ecc.curves.c256; + this.CURVE_H2C_HASH = sjcl.hash.sha256; + this.CURVE_H2C_METHOD = methodStr; + this.CURVE_H2C_LABEL = methodStr === 'increment' ? INC_H2C_LABEL : SSWU_H2C_LABEL; + break; + default: + throw new Error('[privacy-pass]: Incompatible curve chosen: ' + curveStr); + } + } + + /** + * Returns the active configuration for the elliptic curve setting + * @return {Object} Object containing the active curve and h2c configuration + */ + getActiveECSettings() { + return { curve: this.CURVE, hash: this.CURVE_H2C_HASH, method: this.CURVE_H2C_METHOD, label: this.CURVE_H2C_LABEL }; + } + + /** + * Creates a new random point on the curve by sampling random bytes and then + * hashing to the chosen curve. + * @return {sjcl.ecc.point} + */ + newRandomPoint() { + const random = crypto.getRandomValues(new Int32Array(8)); + + // Choose hash-to-curve method + const point = this.h2Curve(random, this.getActiveECSettings()); + + let t; + if (point) { + t = { data: sjcl.codec.bytes.fromBits(random), point: point }; + } + return t; + } + + /** + * Decodes a base64-encoded string into a curve point + * @param {string} p a base64-encoded, uncompressed curve point + * @return {sjcl.ecc.point} + */ + sec1DecodeFromBase64(p) { + const sec1Bits = sjcl.codec.base64.toBits(p); + const sec1Bytes = sjcl.codec.bytes.fromBits(sec1Bits); + return this.sec1DecodeFromBytes(sec1Bytes); + } + + /** + * Decodes (SEC1) curve point bytes into a valid curve point + * @param {sjcl.codec.bytes} sec1Bytes bytes of an uncompressed curve point + * @return {sjcl.ecc.point} + */ + sec1DecodeFromBytes(sec1Bytes) { + let P; + switch (sec1Bytes[0]) { + case 0x02: + case 0x03: + P = this.decompressPoint(sec1Bytes); + break; + case 0x04: + P = this.CURVE.fromBits(sjcl.codec.bytes.toBits(sec1Bytes.slice(1))); + break; + default: + throw new Error( + '[privacy-pass]: attempted sec1 point decoding with incorrect tag: ' + sec1Bytes[0], + ); + } + return P; + } + + /** + * Samples a random scalar and uses it to blind the point P + * @param {sjcl.ecc.point} P curve point + * @return {sjcl.ecc.point} + */ + blindPoint(P) { + const bF = sjcl.bn.random(this.CURVE.r, 10); + const bP = _scalarMult(bF, P); + return { point: bP, blind: bF }; + } + + /** + * unblindPoint takes an assumed-to-be blinded point Q and an accompanying + * blinding scalar b, then returns the point (1/b)*Q. + * @param {sjcl.bn} b scalar blinding factor + * @param {sjcl.ecc.point} Q curve point + * @return {sjcl.ecc.point} + */ + unblindPoint(b, Q) { + const binv = b.inverseMod(this.CURVE.r); + return _scalarMult(binv, Q); + } + + /** + * Attempts to decompress a curve point in SEC1 encoded format. Returns null if + * the point is invalid + * @param {sjcl.codec.bytes} bytes bytes of a compressed curve point (SEC1) + * @return {sjcl.ecc.point} may be null if compressed bytes are not valid + */ + decompressPoint(bytes) { + const yTag = bytes[0]; + const expLength = this.CURVE.r.bitLength() / 8 + 1; // bitLength rounds up + if (yTag != 2 && yTag != 3) { + throw new Error('[privacy-pass]: compressed point is invalid, bytes[0] = ' + yTag); + } else if (bytes.length !== expLength) { + throw new Error( + `[privacy-pass]: compressed point is too long, actual = ${bytes.length}, expected = ${expLength}`, + ); + } + const xBytes = bytes.slice(1); + const x = this.CURVE.field.fromBits(sjcl.codec.bytes.toBits(xBytes)).normalize(); + const sign = yTag & 1; + + // y^2 = x^3 - 3x + b (mod p) + let rh = x.power(3); + const threeTimesX = x.mul(this.CURVE.a); + rh = rh.add(threeTimesX).add(this.CURVE.b).mod(this.CURVE.field.modulus); // mod() normalizes + + // modsqrt(z) for p = 3 mod 4 is z^(p+1/4) + const sqrt = this.CURVE.field.modulus.add(1).normalize().halveM().halveM(); + let y = new this.CURVE.field(rh.powermod(sqrt, this.CURVE.field.modulus)); + + const parity = y.limbs[0] & 1; + if (parity != sign) { + y = this.CURVE.field.modulus.sub(y).normalize(); + } + + const point = new sjcl.ecc.point(this.CURVE, x, y); + if (!point.isValid()) { + // we return null here rather than an error as we iterate over this + // method during hash-and-inc + return null; + } + return point; + } + + /** + * Parse a PEM-encoded public key. + * @param {string} pemPublicKey - A public key in PEM format. + * @return {sjcl.ecc.ecdsa.publicKey} a public key for sjcl library. + */ + parsePublicKeyfromPEM(pemPublicKey) { + try { + let bytes = PEM.parseBlock(pemPublicKey); + let json = ASN1.parse(bytes.der); + let xy = json.children[1].value; + const point = this.sec1DecodeFromBytes(xy); + return new sjcl.ecc.ecdsa.publicKey(this.CURVE, point); + } catch (e) { + throw new Error('[privacy-pass]: Failed on parsing public key. ' + e.message); + } + } + + /** + * Verify the signature of the retrieved configuration portion. + * @param {Number} cfgId - ID of configuration being used. + * @param {json} config - commitments to verify + * @return {boolean} True, if the commitment has valid signature and is not + * expired; otherwise, throws an exception. + */ + verifyConfiguration(publicKey, config, signature) { + const sig = parseSignaturefromPEM(signature); + const msg = JSON.stringify(config); + const pk = this.parsePublicKeyfromPEM(publicKey); + const hmsg = sjcl.hash.sha256.hash(msg); + try { + return pk.verify(hmsg, sig); + } catch (error) { + throw new Error('[privacy-pass]: Invalid configuration verification.'); + } + } + + /** + * DLEQ proof verification logic + */ + + /** + * Verify the DLEQ proof object using the information provided + * @param {string} proofObj base64-encoded batched DLEQ proof object + * @param {Object} tokens array of token objects containing blinded curve points + * @param {Array} signatures an array of signed points + * @param {Object} commitments JSON object containing encoded curve points + * @param {string} prngName name of the PRNG used for verifying proof + * @return {boolean} + */ + verifyProof(proofObj, tokens, signatures, commitments, prngName) { + const bp = getMarshaledBatchProof(proofObj); + const dleq = retrieveProof(bp); + if (!dleq) { + // Error has probably occurred + return false; + } + if (tokens.length !== signatures.points.length) { + return false; + } + const pointG = this.sec1DecodeFromBase64(commitments.G); + const pointH = this.sec1DecodeFromBase64(commitments.H); + + // Recompute A and B for proof verification + const cH = _scalarMult(dleq.C, pointH); + const rG = _scalarMult(dleq.R, pointG); + const A = cH.toJac().add(rG).toAffine(); + + const composites = this.recomputeComposites(tokens, signatures, pointG, pointH, prngName); + const cZ = _scalarMult(dleq.C, composites.Z); + const rM = _scalarMult(dleq.R, composites.M); + const B = cZ.toJac().add(rM).toAffine(); + + // Recalculate C' and check if C =?= C' + const h = new this.CURVE_H2C_HASH(); // use the h2c hash for convenience + h.update(sec1EncodeToBits(pointG, signatures.compressed)); + h.update(sec1EncodeToBits(pointH, signatures.compressed)); + h.update(sec1EncodeToBits(composites.M, signatures.compressed)); + h.update(sec1EncodeToBits(composites.Z, signatures.compressed)); + h.update(sec1EncodeToBits(A, signatures.compressed)); + h.update(sec1EncodeToBits(B, signatures.compressed)); + const digestBits = h.finalize(); + const receivedDigestBits = dleq.C.toBits(); + if (!sjcl.bitArray.equal(digestBits, receivedDigestBits)) { + console.error(DIGEST_INEQUALITY_ERR); + console.error('Computed digest: ' + digestBits.toString()); + console.error('Received digest: ' + receivedDigestBits.toString()); + return false; + } + return true; + } + + /** + * Recompute the composite M and Z values for verifying DLEQ + * @param {Array} tokens array of token objects containing blinded curve points + * @param {Object} signatures contains array of signed curve points and compression flag + * @param {sjcl.ecc.point} pointG curve point + * @param {sjcl.ecc.point} pointH curve point + * @param {string} prngName name of PRNG used to verify proof + * @return {Object} Object containing composite points M and Z + */ + recomputeComposites(tokens, signatures, pointG, pointH, prngName) { + const seed = this.computeSeed(tokens, signatures, pointG, pointH); + let cM = new sjcl.ecc.pointJac(this.CURVE); // can only add points in jacobian representation + let cZ = new sjcl.ecc.pointJac(this.CURVE); + const prng = { name: prngName }; + switch (prng.name) { + case 'shake': + prng.func = createShake256(); + prng.func.update(seed, 'hex'); + break; + case 'hkdf': + prng.func = evaluateHkdf; + break; + default: + throw new Error(`Server specified PRNG is not compatible: ${prng.name}`); + } + let iter = -1; + for (let i = 0; i < tokens.length; i++) { + iter++; + const ci = this.computePRNGScalar(prng, seed, new sjcl.bn(iter).toBits()); + // Moved this check out of computePRNGScalar to here + if (ci.greaterEquals(this.CURVE.r)) { + i--; + continue; + } + const cMi = _scalarMult(ci, tokens[i].point); + const cZi = _scalarMult(ci, signatures.points[i]); + cM = cM.add(cMi); + cZ = cZ.add(cZi); + } + return { M: cM.toAffine(), Z: cZ.toAffine() }; + } + + /** + * Computes an output of a PRNG (using the seed if it is HKDF) as a sjcl bn + * object + * @param {Object} prng PRNG object for generating output + * @param {string} seed hex-encoded seed + * @param {sjcl.bitArray} salt optional salt for each PRNG eval + * @return {sjcl.bn} PRNG output as scalar value + */ + computePRNGScalar(prng, seed, salt) { + const bitLen = this.CURVE.r.bitLength(); + const mask = MASK[bitLen % 8]; + let out; + switch (prng.name) { + case 'shake': + out = prng.func.squeeze(32, 'hex'); + break; + case 'hkdf': + out = sjcl.codec.hex.fromBits( + prng.func( + sjcl.codec.hex.toBits(seed), + bitLen / 8, + sjcl.codec.utf8String.toBits('DLEQ_PROOF'), + salt, + this.CURVE_H2C_HASH, + ), + ); + break; + default: + throw new Error(`Server specified PRNG is not compatible: ${prng.name}`); + } + // Masking is not strictly necessary for p256 but better to be completely + // compatible in case that the curve changes + const h = parseInt(out.substr(0, 2), 16); + const mh = sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits([h & mask])); + out = mh + out.substr(2); + const nOut = getBigNumFromHex(out); + return nOut; + } + + /** + * Computes a seed for the PRNG for verifying batch DLEQ proofs + * @param {Object} chkM array of token objects containing blinded curve points + * @param {sjcl.ecc.point[]} chkZ array of signed curve points + * @param {sjcl.ecc.point} pointG curve point + * @param {sjcl.ecc.point} pointH curve point + * @return {string} hex-encoded PRNG seed + */ + computeSeed(chkM, chkZ, pointG, pointH) { + const compressed = chkZ.compressed; + const h = new this.CURVE_H2C_HASH(); // we use the h2c hash for convenience + h.update(sec1EncodeToBits(pointG, compressed)); + h.update(sec1EncodeToBits(pointH, compressed)); + for (let i = 0; i < chkM.length; i++) { + h.update(sec1EncodeToBits(chkM[i].point, compressed)); + h.update(sec1EncodeToBits(chkZ.points[i], compressed)); + } + return sjcl.codec.hex.fromBits(h.finalize()); + } + + /** + * Derives the shared key used for redemption MACs + * @param {sjcl.ecc.point} N Signed curve point associated with token + * @param {Object} token client-generated token data + * @return {sjcl.codec.bytes} bytes of derived key + */ + deriveKey(N, token) { + // the exact bits of the string "hash_derive_key" + const tagBits = sjcl.codec.hex.toBits('686173685f6465726976655f6b6579'); + const hash = this.getActiveECSettings().hash; + const h = new sjcl.misc.hmac(tagBits, hash); + + // Always compute derived key using uncompressed point bytes + const encodedPoint = sec1Encode(N, false); + const tokenBits = sjcl.codec.bytes.toBits(token); + const pointBits = sjcl.codec.bytes.toBits(encodedPoint); + + h.update(tokenBits); + h.update(pointBits); + + const keyBytes = sjcl.codec.bytes.fromBits(h.digest()); + return keyBytes; + } + + createRequestBinding(key, data) { + // the exact bits of the string "hash_request_binding" + const tagBits = sjcl.codec.utf8String.toBits('hash_request_binding'); + const keyBits = sjcl.codec.bytes.toBits(key); + const hash = this.getActiveECSettings().hash; + + const h = new sjcl.misc.hmac(keyBits, hash); + h.update(tagBits); + + let dataBits = null; + for (let i = 0; i < data.length; i++) { + dataBits = sjcl.codec.bytes.toBits(data[i]); + h.update(dataBits); + } + + return sjcl.codec.base64.fromBits(h.digest()); + } + + /** + * Decodes the received curve points + * @param {Array} signatures An array of base64-encoded signed points + * @return {Object} object containing array of curve points and compression flag + */ + getCurvePoints(signatures) { + const self = this; + const compression = { on: false, set: false }; + const sigBytes = []; + signatures.forEach(function (signature) { + const buf = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(signature)); + let setting = false; + switch (buf[0]) { + case 2: + case 3: + setting = true; + break; + case 4: + // do nothing + break; + default: + throw new Error(`[privacy-pass]: point, ${buf}, is not encoded correctly`); + } + if (!validResponseCompression(compression, setting)) { + throw new Error('[privacy-pass]: inconsistent point compression in server response'); + } + sigBytes.push(buf); + }); + + const usablePoints = []; + sigBytes.forEach(function (buf) { + const usablePoint = self.sec1DecodeFromBytes(buf); + if (usablePoint == null) { + throw new Error('[privacy-pass]: unable to decode point: ' + buf); + } + usablePoints.push(usablePoint); + }); + return { points: usablePoints, compressed: compression.on }; + } + + /** + * DEPRECATED: Method for hashing to curve based on the principal of attempting + * to hash the bytes multiple times and recover a curve point. Has non-negligble + * probailistic failure conditions. + * @param {sjcl.bitArray} seed + * @param {sjcl.hash} hash hash function for hashing bytes to base field + * @param {sjcl.bitArray} label + * @return {sjcl.ecc.point} returns a curve point on the active curve + */ + hashAndInc(seed, hash, label) { + const h = new hash(); + + // Need to match the Go curve hash, so we decode the exact bytes of the + // string "1.2.840.100045.3.1.7 point generation seed" instead of relying + // on the utf8 codec that didn't match. + const separator = label; + + h.update(separator); + + let i = 0; + // Increased increments to decrease chance of failure + for (i = 0; i < 20; i++) { + // little endian uint32 + const ctr = new Uint8Array(4); + // typecast hack: number -> Uint32, bitwise Uint8 + ctr[0] = (i >>> 0) & 0xff; + const ctrBits = sjcl.codec.bytes.toBits(ctr); + + // H(s||ctr) + h.update(seed); + h.update(ctrBits); + + const digestBits = h.finalize(); + const bytes = sjcl.codec.bytes.fromBits(digestBits); + + // attempt to decompress a point with a valid tag (don't need to try + // 0x03 because this is just the negative version) + // curve choice is implicit based on active curve parameters + const point = this.sec1DecodeFromBytes([2].concat(bytes)); + if (point !== null) { + return point; + } + + seed = digestBits; + h.reset(); + } + + throw new Error('Unable to construct point using hash and increment'); + } + + /** + * hashes bits to the chosen elliptic curve + * @param {sjcl.bitArray} alpha bits to be encoded onto curve + * @param {Object} ecSettings the curve settings being used by the extension + * @return {sjcl.ecc.point} point on curve + */ + h2Curve(alpha, ecSettings) { + let point; + switch (ecSettings.method) { + case 'swu': + point = simplifiedSWU(alpha, ecSettings.curve, ecSettings.hash, ecSettings.label); + break; + case 'increment': + point = this.hashAndInc(alpha, ecSettings.hash, ecSettings.label); + break; + default: + throw new Error( + '[privacy-pass]: Incompatible curve chosen for hashing, SJCL chosen curve: ' + + sjcl.ecc.curveName(ecSettings.curve), + ); + } + return point; + } +} + +// ----------------------------------------------------------------------------- +/* summary of exports: + +module.exports = { + // data values: + defaultECSettings, + + // functions: + sec1Encode, + sec1EncodeToBase64, + getBigNumFromBytes, + newBigNum, + getBytesFromString, + getBase64FromBytes, + getBase64FromString, + + // classes: + VOPRF, +} + +*/ +// ----------------------------------------------------------------------------- diff --git a/src/background/crypto/voprf.test.ts b/src/background/crypto/voprf.test.ts new file mode 100644 index 00000000..d7692aec --- /dev/null +++ b/src/background/crypto/voprf.test.ts @@ -0,0 +1,8 @@ +import { VOPRF, defaultECSettings } from './voprf'; + +test('randomPoint', () => { + const voprf = new VOPRF(defaultECSettings); + const P = voprf.newRandomPoint(); + + expect(P).toBeDefined(); +}); diff --git a/src/background/index.ts b/src/background/index.ts index 46c79005..8fe80e5b 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,8 +1,5 @@ -import { - handleBeforeRequest, - handleBeforeSendHeaders, - handleHeadersReceived, -} from './listeners/webRequestListener'; +import { Tab } from './tab'; + import { handleActivated, handleCreated, @@ -10,9 +7,23 @@ import { handleReplaced, } from './listeners/tabListener'; -import { Tab } from './tab'; +import { + handleBeforeRequest, + handleBeforeSendHeaders, + handleHeadersReceived, + handleOnCompleted, + handleOnErrorOccurred, +} from './listeners/webRequestListener'; -/* Listeners for navigator */ +import { + handleChangedCookies, +} from './listeners/cookiesListener'; + +import { + handleReceivedMessage, +} from './listeners/messageListener'; + +/* Local state */ declare global { interface Window { @@ -24,6 +35,15 @@ declare global { window.ACTIVE_TAB_ID = chrome.tabs.TAB_ID_NONE; window.TABS = new Map(); +/* Access to local state */ + +export function forceUpdateIcon(): void { + const activeTab = window.TABS.get(window.ACTIVE_TAB_ID); + if (activeTab !== undefined) { + activeTab.forceUpdateIcon(); + } +} + /* Listeners for navigator */ chrome.tabs.onActivated.addListener(handleActivated); @@ -52,49 +72,43 @@ chrome.tabs.query({ active: true, currentWindow: true }, function (tabs: chrome. } }); -chrome.webRequest.onBeforeRequest.addListener(handleBeforeRequest, { urls: [''] }, [ - 'requestBody', - 'blocking', -]); +chrome.webRequest.onBeforeRequest.addListener( + handleBeforeRequest, + { urls: [''] }, + ((chrome.webRequest).OnBeforeRequestOptions !== undefined) + ? Object.values((chrome.webRequest).OnBeforeRequestOptions) + : ['blocking', 'requestBody'] +); chrome.webRequest.onBeforeSendHeaders.addListener( handleBeforeSendHeaders, { urls: [''] }, - ['requestHeaders', 'blocking'], + ((chrome.webRequest).OnBeforeSendHeadersOptions !== undefined) + ? Object.values((chrome.webRequest).OnBeforeSendHeadersOptions) + : ['blocking', 'requestHeaders'] ); -chrome.webRequest.onHeadersReceived.addListener(handleHeadersReceived, { urls: [''] }, [ - 'responseHeaders', - 'blocking', -]); - -// TODO Using Message passing is dirty. It's better to use chrome.storage for sharing -// common data between the popup and the background script. -chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { - if (request.clear === true) { - window.localStorage.clear(); - - // Update the browser action icon after clearing the tokens. - const activeTab = window.TABS.get(window.ACTIVE_TAB_ID); - if (activeTab !== undefined) { - activeTab.forceUpdateIcon(); - } - return; - } +chrome.webRequest.onHeadersReceived.addListener( + handleHeadersReceived, + { urls: [''] }, + ((chrome.webRequest).OnHeadersReceivedOptions !== undefined) + ? Object.values((chrome.webRequest).OnHeadersReceivedOptions) + : ['blocking', 'responseHeaders'] +); - if (request.key !== undefined && typeof request.key === 'string') { - sendResponse(window.localStorage.getItem(request.key)); - } -}); +chrome.webRequest.onCompleted.addListener( + handleOnCompleted, + { urls: [''] }, + ((chrome.webRequest).OnCompletedOptions !== undefined) + ? Object.values((chrome.webRequest).OnCompletedOptions) + : ['responseHeaders'] +); -// TODO It's better to move this to the provider class. Let's figure out how to do it later. -// Removes cookies for captcha.website to enable getting more tokens in the future. -chrome.cookies.onChanged.addListener((changeInfo) => { - if ( - !changeInfo.removed && - changeInfo.cookie.domain === '.captcha.website' && - changeInfo.cookie.name === 'cf_clearance' - ) { - chrome.cookies.remove({ url: 'https://captcha.website', name: 'cf_clearance' }); - } -}); +chrome.webRequest.onErrorOccurred.addListener( + handleOnErrorOccurred, + { urls: [''] }, +); + +chrome.cookies.onChanged.addListener(handleChangedCookies); + +chrome.runtime.onMessage.addListener(handleReceivedMessage); diff --git a/src/background/listeners/cookiesListener.ts b/src/background/listeners/cookiesListener.ts new file mode 100644 index 00000000..e9035143 --- /dev/null +++ b/src/background/listeners/cookiesListener.ts @@ -0,0 +1,17 @@ +import { Providers, EarnedTokenCookie } from '../providers'; + +export function handleChangedCookies(changeInfo: any): void { + if (!changeInfo.removed && Array.isArray(Providers) && Providers.length) { + for (const provider of Providers) { + const cookie: EarnedTokenCookie | void = provider.EARNED_TOKEN_COOKIE; + if (!cookie) continue; + + if ( + changeInfo.cookie.domain === cookie.domain && + changeInfo.cookie.name === cookie.name + ) { + chrome.cookies.remove({ url: cookie.url, name: cookie.name }); + } + } + } +} diff --git a/src/background/listeners/messageListener.ts b/src/background/listeners/messageListener.ts new file mode 100644 index 00000000..301d3f4a --- /dev/null +++ b/src/background/listeners/messageListener.ts @@ -0,0 +1,143 @@ +import { forceUpdateIcon } from '..' +import { Providers, Provider } from '../providers'; +import { LocalStorage, generatePrefixFromID, clearAllPasses } from '../storage' + +function getAllPasses(providerID: number | void): {[key: string]: string[]} { + const response: {[key: string]: string[]} = {}; + + for (const provider of Providers) { + if ((providerID === undefined) || (providerID === provider.ID)) { + try { + const storage = new LocalStorage( + generatePrefixFromID(provider.ID) + ); + + const tokensJSON: string | null = storage.getItem(Provider.TOKEN_STORE_KEY); + + const tokensArray: string[] = (tokensJSON === null) ? [] : JSON.parse(tokensJSON); + + response[ provider.ID.toString() ] = tokensArray; + } + catch (error: any) {} + } + } + + return response; +} + +function addPasses(providerID: string, newTokensArray: string[]): boolean { + try { + const provider: (typeof Provider) | void = Providers.find(p => p.ID.toString() === providerID); + if (provider === undefined) throw 'no matching provider for ID value'; + + const storage = new LocalStorage( + generatePrefixFromID(provider.ID) + ); + + const tokensJSON: string | null = storage.getItem(Provider.TOKEN_STORE_KEY); + + const oldTokensArray: string[] = (tokensJSON === null) ? [] : JSON.parse(tokensJSON); + + const mergedTokensArray: string[] = [ + ...oldTokensArray, + ...(newTokensArray.filter(token => oldTokensArray.indexOf(token) === -1)) + ]; + + storage.setItem( + Provider.TOKEN_STORE_KEY, + JSON.stringify(mergedTokensArray), + ); + + return true; + } + catch (error: any) { + return false; + } +} + +function restorePasses(backup: {[key: string]: string[]} | void): boolean { + let did_restore: boolean = false; + + if (backup !== undefined) { + for (const providerID in backup) { + if (addPasses(providerID, backup[providerID]) && !did_restore) { + did_restore = true; + } + } + } + + return did_restore; +} + +export function handleReceivedMessage(request: any, sender: chrome.runtime.MessageSender, sendResponse: Function): void { + + // ------------------------------------------------------------------------- + if (request.tokensCount === true) { + const allPasses: {[key: string]: string[]} = getAllPasses(request.providerID); + const response: {[key: string]: number } = {}; + + for (const providerID in allPasses) { + response[providerID] = Number(allPasses[providerID].length); + } + + sendResponse(response); + return; + } + + // ------------------------------------------------------------------------- + if (request.backup === true) { + const allPasses: {[key: string]: string[]} = getAllPasses(request.providerID); + + sendResponse(allPasses); + return; + } + + // ------------------------------------------------------------------------- + if (request.restore === true) { + if (request.tab !== undefined) { + if (request.tab.open === true) { + chrome.tabs.create({ url: '/restore.html', active: true }); + + sendResponse(); + return; + } + + if (request.tab.close === true) { + if ((sender.tab !== undefined) && (sender.tab.id !== undefined) && (sender.tab.id !== chrome.tabs.TAB_ID_NONE)) { + chrome.tabs.remove(sender.tab.id); + } + + sendResponse(); + return; + } + } + + if (request.backup !== undefined) { + const did_restore: boolean = restorePasses(request.backup); + + if (did_restore) { + // Update the browser action icon after restoring tokens. + forceUpdateIcon(); + } + + sendResponse(did_restore); + return; + } + + sendResponse(); + return; + } + + // ------------------------------------------------------------------------- + if (request.clear === true) { + clearAllPasses(); + + // Update the browser action icon after clearing the tokens. + forceUpdateIcon(); + + sendResponse(); + return; + } + + // ------------------------------------------------------------------------- +} diff --git a/src/background/listeners/webRequestListener.ts b/src/background/listeners/webRequestListener.ts index 02e9d604..7ac19c2d 100644 --- a/src/background/listeners/webRequestListener.ts +++ b/src/background/listeners/webRequestListener.ts @@ -1,38 +1,58 @@ -export function handleBeforeRequest( - details: chrome.webRequest.WebRequestBodyDetails, -): chrome.webRequest.BlockingResponse | void { - if (details.tabId === chrome.tabs.TAB_ID_NONE) { +import { Tab } from '../tab'; + +function getTab(id: number): Tab | null { + if (id === chrome.tabs.TAB_ID_NONE) { // The request does not correspond to any tab. - return; + return null; } - const tab = window.TABS.get(details.tabId); // The tab can be removed already if the request comes after the tab is closed. - return tab?.handleBeforeRequest(details); + const tab: Tab | void = window.TABS.get(id); + + return (tab === undefined) ? null : tab; +} + +export function handleBeforeRequest( + details: chrome.webRequest.WebRequestBodyDetails, +): chrome.webRequest.BlockingResponse | void { + const tab = getTab(details.tabId); + if (tab === null) return; + + return tab!.handleBeforeRequest(details); } export function handleBeforeSendHeaders( details: chrome.webRequest.WebRequestHeadersDetails, ): chrome.webRequest.BlockingResponse | void { - if (details.tabId === chrome.tabs.TAB_ID_NONE) { - // The request does not correspond to any tab. - return; - } + const tab = getTab(details.tabId); + if (tab === null) return; - const tab = window.TABS.get(details.tabId); - // The tab can be removed already if the request comes after the tab is closed. - return tab?.handleBeforeSendHeaders(details); + return tab!.handleBeforeSendHeaders(details); } export function handleHeadersReceived( details: chrome.webRequest.WebResponseHeadersDetails, ): chrome.webRequest.BlockingResponse | void { - if (details.tabId === chrome.tabs.TAB_ID_NONE) { - // The request does not correspond to any tab. - return; - } + const tab = getTab(details.tabId); + if (tab === null) return; + + return tab!.handleHeadersReceived(details); +} + +export function handleOnCompleted( + details: chrome.webRequest.WebResponseHeadersDetails, +): void { + const tab = getTab(details.tabId); + if (tab === null) return; + + return tab!.handleOnCompleted(details); +} + +export function handleOnErrorOccurred( + details: chrome.webRequest.WebResponseErrorDetails, +): void { + const tab = getTab(details.tabId); + if (tab === null) return; - const tab = window.TABS.get(details.tabId); - // The tab can be removed already if the response comes after the tab is closed. - return tab?.handleHeadersReceived(details); + return tab!.handleOnErrorOccurred(details); } diff --git a/src/background/providers/cloudflare.test.ts b/src/background/providers/cloudflare.test.ts index 94b3de00..14152510 100644 --- a/src/background/providers/cloudflare.test.ts +++ b/src/background/providers/cloudflare.test.ts @@ -18,7 +18,7 @@ export class StorageMock { } } -test('getStoredTokens', () => { +test('setStoredTokens', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); @@ -26,13 +26,18 @@ test('getStoredTokens', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); const tokens = [new Token(), new Token()]; provider['setStoredTokens'](tokens); - const storedTokens = provider['getStoredTokens'](); - expect(storedTokens.map((token) => token.toString())).toEqual( - tokens.map((token) => token.toString()), - ); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const storedTokens = JSON.parse(storage.store.get('tokens')!); + expect(storedTokens).toEqual(tokens.map((token) => token.toString())); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); }); -test('setStoredTokens', () => { +test('getStoredTokens', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); @@ -40,8 +45,17 @@ test('setStoredTokens', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); const tokens = [new Token(), new Token()]; provider['setStoredTokens'](tokens); - const storedTokens = JSON.parse(storage.store.get('tokens')!); - expect(storedTokens).toEqual(tokens.map((token) => token.toString())); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const storedTokens = provider['getStoredTokens'](); + expect(storedTokens.map((token) => token.toString())).toEqual( + tokens.map((token) => token.toString()), + ); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); }); test('getBadgeText', () => { @@ -57,20 +71,55 @@ test('getBadgeText', () => { }); /* - * The issuance involves handleBeforeRequest listener. - * 1. Firstly, the listener check if the request looks like the one that we - * should send an issuance request. - * 2. If it passes the check, the listener returns the cancel command to - * cancel the request. If not, it returns nothing and let the request - * continue. - * 3. At the same time the listener returns, it calls a private method - * "issue" to send an issuance request to the server and the method return - * an array of issued tokens. - * 4. The listener stored the issued tokens in the storage. - * 5. The listener reloads the tab to get the proper web page for the tab.); + * The issuance involves handleBeforeRequest and handleBeforeSendHeaders listeners. + * + * In handleBeforeRequest listener, + * 1. Check that the request matches the criteria for issuing new tokens. + * Such requests are submitting a solved captcha to the provider + * on a website controlled by the provider. + * 2. If so, the listener sets the "issueInfo" property, + * which includes the request id for subsequent processing. + * + * In handleBeforeSendHeaders, + * 1. Check that the "issueInfo" property is set, and its request id is a match. + * 2. If so, complete the check to determine that the request matches the criteria for issuing new tokens. + * 3. If so, + * 3a. Cancel the original request. + * 3b. Initiate a secondary request to the provider for the issuing of signed tokens. */ describe('issuance', () => { describe('handleBeforeRequest', () => { + + beforeEach(() => { + jest.useFakeTimers(); + jest.spyOn(global, 'setTimeout'); + }); + + afterEach(() => { + jest.clearAllTimers(); + jest.useRealTimers(); + }); + + const validDetails: chrome.webRequest.WebRequestBodyDetails = { + method: 'POST', + url: 'https://captcha.website/?__cf_chl_f_tk=query-param', + requestId: 'xxx', + frameId: 1, + parentFrameId: 1, + tabId: 1, + type: 'xmlhttprequest' as chrome.webRequest.ResourceType, + timeStamp: 1, + requestBody: { + formData: { + 'h-captcha-response': ['body-param'], + }, + }, + }; + + const flattenFormData: { [key: string]: string[] | string } = { + 'h-captcha-response': 'body-param', + }; + test('valid request', async () => { const storage = new StorageMock(); const updateIcon = jest.fn(); @@ -82,51 +131,132 @@ describe('issuance', () => { return tokens; }); provider['issue'] = issue; - const url = 'https://captcha.website/?__cf_chl_captcha_tk__=query-param'; - const details = { - method: 'POST', - url, - requestId: 'xxx', - frameId: 1, - parentFrameId: 1, - tabId: 1, - type: 'xmlhttprequest' as chrome.webRequest.ResourceType, - timeStamp: 1, - requestBody: { - formData: { - ['h-captcha-response']: ['body-param'], - }, - }, + let result, issueInfo; + + const bodyDetails: chrome.webRequest.WebRequestBodyDetails = validDetails; + result = provider.handleBeforeRequest(bodyDetails); + expect(result).toEqual({ cancel: false }); + + // Expect issueInfo to be set. + issueInfo = provider['issueInfo']; + expect(issueInfo!.requestId).toEqual(bodyDetails.requestId); + expect(issueInfo!.url).toEqual(bodyDetails.url); + expect(issueInfo!.formData).toEqual(flattenFormData); + + const headDetails: any = { + ...validDetails, + requestHeaders: [] }; - const result = await provider.handleBeforeRequest(details); + delete headDetails.requestBody; + + result = provider.handleBeforeSendHeaders(headDetails); expect(result).toEqual({ cancel: true }); + // Expect issueInfo to be unset. + issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 0); + jest.runAllTimers(); + await Promise.resolve(); + expect(issue.mock.calls.length).toBe(1); - expect(issue).toHaveBeenCalledWith(url, { - ['h-captcha-response']: 'body-param', + expect(issue).toHaveBeenCalledWith(headDetails.url, { + 'h-captcha-response': 'body-param', }); + // Expect the tokens are added. + const storedTokens = provider['getStoredTokens'](); + expect(storedTokens.map((token) => token.toString())).toEqual( + tokens.map((token) => token.toString()), + ); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + expect(navigateUrl.mock.calls.length).toBe(1); expect(navigateUrl).toHaveBeenCalledWith('https://captcha.website/'); + }); + + test('[workaround] invalid request: with a valid referer header', async () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token(), new Token()]; + const issue = jest.fn(async () => { + return tokens; + }); + provider['issue'] = issue; + let result, issueInfo; + + const bodyDetails: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + url: validDetails.url.substring(0, validDetails.url.indexOf('?')), + }; + result = provider.handleBeforeRequest(bodyDetails); + expect(result).toEqual({ cancel: false }); + + // Expect issueInfo to be set. + issueInfo = provider['issueInfo']; + expect(issueInfo!.requestId).toEqual(bodyDetails.requestId); + expect(issueInfo!.url).toEqual(bodyDetails.url); + expect(issueInfo!.formData).toEqual(flattenFormData); + + const headDetails: any = { + ...validDetails, + requestHeaders: [ + { name: "referer", value: validDetails.url.replace('__cf_chl_f_tk', '__cf_chl_tk') }, + ], + }; + delete headDetails.requestBody; + + result = provider.handleBeforeSendHeaders(headDetails); + expect(result).toEqual({ cancel: true }); + + // Expect issueInfo to be unset. + issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 0); + jest.runAllTimers(); + await Promise.resolve(); + + expect(issue.mock.calls.length).toBe(1); + expect(issue).toHaveBeenCalledWith(headDetails.url, { + 'h-captcha-response': 'body-param', + }); // Expect the tokens are added. const storedTokens = provider['getStoredTokens'](); expect(storedTokens.map((token) => token.toString())).toEqual( tokens.map((token) => token.toString()), ); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + expect(navigateUrl.mock.calls.length).toBe(1); + expect(navigateUrl).toHaveBeenCalledWith('https://captcha.website/'); }); /* * The request is invalid if any of the followings is true: * 1. It has no url param of any of the followings: - * a. '__cf_chl_captcha_tk__' - * b. '__cf_chl_managed_tk__' + * a. '__cf_chl_f_tk' + * b. '__cf_chl_captcha_tk__' + * c. '__cf_chl_managed_tk__' * 2. It has no body param of any of the followings: * a. 'g-recaptcha-response' * b. 'h-captcha-response' * c. 'cf_captcha_kind' + * d. 'cf_ch_verify' */ - test('invalid request', async () => { + + test('invalid request: no query param', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); @@ -134,58 +264,106 @@ describe('issuance', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); const issue = jest.fn(async () => []); provider['issue'] = issue; - const details = { - method: 'GET', - url: 'https://cloudflare.com/', - requestId: 'xxx', - frameId: 1, - parentFrameId: 1, - tabId: 1, - type: 'xmlhttprequest' as chrome.webRequest.ResourceType, - timeStamp: 1, + let result, issueInfo; + + const bodyDetails: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + url: validDetails.url.substring(0, validDetails.url.indexOf('?')), + }; + result = provider.handleBeforeRequest(bodyDetails); + expect(result).toEqual({ cancel: false }); + + // Expect issueInfo to be set. + issueInfo = provider['issueInfo']; + expect(issueInfo!.requestId).toEqual(bodyDetails.requestId); + expect(issueInfo!.url).toEqual(bodyDetails.url); + expect(issueInfo!.formData).toEqual(flattenFormData); + + const headDetails: any = { + ...validDetails, + requestHeaders: [] + }; + delete headDetails.requestBody; + + result = provider.handleBeforeSendHeaders(headDetails); + expect(result).toBeUndefined(); + + // Expect issueInfo to be unset. + issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(setTimeout).not.toHaveBeenCalled(); + expect(issue).not.toHaveBeenCalled(); + expect(updateIcon).not.toHaveBeenCalled(); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + test('invalid request: no body param', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); + const issue = jest.fn(async () => []); + provider['issue'] = issue; + let result, issueInfo; + + const bodyDetails: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, requestBody: {}, }; - const result = await provider.handleBeforeRequest(details); + result = provider.handleBeforeRequest(bodyDetails); expect(result).toBeUndefined(); + + // Expect issueInfo to be unset. + issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + const headDetails: any = { + ...validDetails, + requestHeaders: [] + }; + delete headDetails.requestBody; + + result = provider.handleBeforeSendHeaders(headDetails); + expect(result).toBeUndefined(); + + // Expect issueInfo to be unset. + issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(setTimeout).not.toHaveBeenCalled(); expect(issue).not.toHaveBeenCalled(); + expect(updateIcon).not.toHaveBeenCalled(); expect(navigateUrl).not.toHaveBeenCalled(); }); }); }); /* - * The redemption involves handleHeadersReceived and handleBeforeSendHeaders - * listeners. In handleHeadersReceived listener, - * 1. Firstly, the listener check if the response is the challenge page and - * it supports Privacy Pass redemption. - * 2. If it passes the check, the listener gets a token from the storage to - * redeem. - * 3. The listener sets "redeemInfo" property which includes the request id - * and the mentioned token. The property will be used by - * handleBeforeSendHeaders to redeem the token. - * 4. The listener returns the redirect command so that the browser will - * send the same request again with the token attached. + * The redemption involves handleHeadersReceived and handleBeforeSendHeaders listeners. + * + * In handleHeadersReceived listener, + * 1. Check that the request matches the criteria for redemption. + * Such requests have a status code of 403, and a special header. + * 2. If so, the listener sets the "redeemInfo" property, + * and returns a value that causes the request to be resent. * * In handleBeforeSendHeaders, - * 1. The listener will check if the provided request id matches the - * request id in "redeemInfo". If so, it means that the request is from the - * redirect command returned by handleHeadersReceived. If not, it returns - * nothing and let the request continue. - * 2. If it passes the check, the listener attaches the token from - * "redeemInfo" in the "challenge-bypass-token" HTTP header and clears the - * "redeemInfo" property because "redeemInfo" is used already. + * 1. Check that the "redeemInfo" property is set, and its request id is a match. + * 2. If so, add headers to include one token for redemption by provider. */ describe('redemption', () => { describe('handleHeadersReceived', () => { - const validDetails = { - url: 'https://cloudflare.com/', + const validDetails: chrome.webRequest.WebResponseHeadersDetails = { + method: 'GET', + url: 'https://non-issuing-domain.example.com/', requestId: 'xxx', frameId: 1, parentFrameId: 1, tabId: 1, type: 'main_frame' as chrome.webRequest.ResourceType, timeStamp: 1, - statusLine: 'HTTP/1.1 403 Forbidden', statusCode: 403, responseHeaders: [ @@ -194,10 +372,9 @@ describe('redemption', () => { value: '1', }, ], - method: 'GET', }; - test('valid response with tokens', () => { + test('valid response with tokens in wallet', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); @@ -205,33 +382,83 @@ describe('redemption', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); const tokens = [new Token(), new Token(), new Token()]; provider['setStoredTokens'](tokens); - const details = validDetails; + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebResponseHeadersDetails = validDetails; const result = provider.handleHeadersReceived(details); expect(result).toEqual({ redirectUrl: details.url }); + // Expect redeemInfo to be set. const redeemInfo = provider['redeemInfo']; expect(redeemInfo!.requestId).toEqual(details.requestId); expect(redeemInfo!.token.toString()).toEqual(tokens[0].toString()); + + expect(updateIcon.mock.calls.length).toBe(2); + expect(updateIcon).toHaveBeenLastCalledWith((tokens.length - 1).toString()); + // Expect a token is used. const storedTokens = provider['getStoredTokens'](); expect(storedTokens.map((token) => token.toString())).toEqual( tokens.slice(1).map((token) => token.toString()), ); + + expect(updateIcon.mock.calls.length).toBe(2); + expect(navigateUrl).not.toHaveBeenCalled(); }); - test('valid response without tokens', () => { + test('valid response without tokens in wallet', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); provider['setStoredTokens']([]); - const details = validDetails; + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith('0'); + + const details: chrome.webRequest.WebResponseHeadersDetails = validDetails; + const result = provider.handleHeadersReceived(details); + expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(2); + expect(updateIcon).toHaveBeenLastCalledWith('0'); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + /* + * The response is invalid if any of the followings is true: + * 1. The URL is hosted by a site that issues tokens. + * 2. The status code is not 403. + * 3. There is no HTTP header of "cf-chl-bypass: 1" + */ + + test('invalid response: from issuing domain', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token(), new Token()]; + provider['setStoredTokens'](tokens); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebResponseHeadersDetails = { + ...validDetails, + url: 'https://captcha.website/', + }; const result = provider.handleHeadersReceived(details); expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); }); - test('captcha.website response', () => { + test('invalid response: wrong status code', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); @@ -239,18 +466,23 @@ describe('redemption', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); const tokens = [new Token(), new Token(), new Token()]; provider['setStoredTokens'](tokens); - const details = validDetails; - details.url = 'https://captcha.website/'; + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebResponseHeadersDetails = { + ...validDetails, + statusLine: 'HTTP/1.1 200 OK', + statusCode: 200, + }; const result = provider.handleHeadersReceived(details); expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); }); - /* - * The response is invalid if any of the followings is true: - * 1. The status code is not 403. - * 2. There is no HTTP header of "cf-chl-bypass: 1" - */ - test('invalid response', () => { + test('invalid response: no bypass header', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); const navigateUrl = jest.fn(); @@ -258,25 +490,35 @@ describe('redemption', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); const tokens = [new Token(), new Token(), new Token()]; provider['setStoredTokens'](tokens); - const details = { - url: 'https://cloudflare.com/', - requestId: 'xxx', - frameId: 1, - parentFrameId: 1, - tabId: 1, - type: 'main_frame' as chrome.webRequest.ResourceType, - timeStamp: 1, - - statusLine: 'HTTP/1.1 403 Forbidden', - statusCode: 403, - method: 'GET', + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebResponseHeadersDetails = { + ...validDetails, + responseHeaders: [], }; const result = provider.handleHeadersReceived(details); expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); }); }); describe('handleBeforeSendHeaders', () => { + const validDetails: chrome.webRequest.WebRequestHeadersDetails = { + method: 'GET', + url: 'https://non-issuing-domain.example.com/', + requestId: 'xxx', + frameId: 1, + parentFrameId: 1, + tabId: 1, + type: 'main_frame' as chrome.webRequest.ResourceType, + timeStamp: 1, + requestHeaders: [], + }; + test('with redeemInfo', () => { const storage = new StorageMock(); const updateIcon = jest.fn(); @@ -292,31 +534,23 @@ describe('redemption', () => { token, }; provider['redeemInfo'] = redeemInfo; - const details = { - method: 'GET', - url: 'https://cloudflare.com/', - requestId: 'xxx', - frameId: 1, - parentFrameId: 1, - tabId: 1, - type: 'main_frame' as chrome.webRequest.ResourceType, - timeStamp: 1, - requestHeaders: [], - }; + + const details: chrome.webRequest.WebRequestHeadersDetails = validDetails; const result = provider.handleBeforeSendHeaders(details); expect(result).toEqual({ requestHeaders: [ { name: 'challenge-bypass-token', - value: 'eyJ0eXBlIjoiUmVkZWVtIiwiY29udGVudHMiOlsiN3Mweit1TDdrRVNxUk9zWjU1aDlQOWNLS2lWQm5UZ1dZaGVCQ1oyejMwQT0iLCJyeXRSRExLN3J2THVhd09XZkJ0RXJTclVuUWpIaGpLbkNKK3RqQnhQSFYwPSIsImV5SmpkWEoyWlNJNkluQXlOVFlpTENKb1lYTm9Jam9pYzJoaE1qVTJJaXdpYldWMGFHOWtJam9pYVc1amNtVnRaVzUwSW4wPSJdfQ==', + value: 'eyJ0eXBlIjoiUmVkZWVtIiwiY29udGVudHMiOlsiN3Mweit1TDdrRVNxUk9zWjU1aDlQOWNLS2lWQm5UZ1dZaGVCQ1oyejMwQT0iLCJIWVA2QnlqYmFCK0trNG9qM2Rtazc4Qy9aWWFMVlNYTHZtT0JIMms0QTFRPSIsImV5SmpkWEoyWlNJNkluQXlOVFlpTENKb1lYTm9Jam9pYzJoaE1qVTJJaXdpYldWMGFHOWtJam9pYVc1amNtVnRaVzUwSW4wPSJdfQ==', }, ], }); + const newRedeemInfo = provider['redeemInfo']; expect(newRedeemInfo).toBeNull(); - expect(updateIcon.mock.calls.length).toBe(1); - expect(updateIcon).toHaveBeenCalledWith('0'); + expect(updateIcon).not.toHaveBeenCalled(); + expect(navigateUrl).not.toHaveBeenCalled(); }); test('without redeemInfo', () => { @@ -326,20 +560,12 @@ describe('redemption', () => { const provider = new CloudflareProvider(storage, { updateIcon, navigateUrl }); - const details = { - method: 'GET', - url: 'https://cloudflare.com/', - requestId: 'xxx', - frameId: 1, - parentFrameId: 1, - tabId: 1, - type: 'main_frame' as chrome.webRequest.ResourceType, - timeStamp: 1, - requestHeaders: [], - }; + const details: chrome.webRequest.WebRequestHeadersDetails = validDetails; const result = provider.handleBeforeSendHeaders(details); expect(result).toBeUndefined(); + expect(updateIcon).not.toHaveBeenCalled(); + expect(navigateUrl).not.toHaveBeenCalled(); }); }); }); diff --git a/src/background/providers/cloudflare.ts b/src/background/providers/cloudflare.ts index 2f9f1fe1..6b0bfdfe 100644 --- a/src/background/providers/cloudflare.ts +++ b/src/background/providers/cloudflare.ts @@ -1,122 +1,349 @@ -import * as voprf from '../voprf'; +import * as voprf from '../crypto/voprf'; -import { Callbacks, Provider } from '.'; +import { Provider, EarnedTokenCookie, Callbacks, QUALIFIED_HOSTNAMES, QUALIFIED_PATHNAMES, QUALIFIED_PARAMS, isIssuingHostname, isQualifiedPathname, areQualifiedQueryParams, areQualifiedBodyFormParams, getNormalizedFormData } from './provider'; import { Storage } from '../storage'; import Token from '../token'; import axios from 'axios'; import qs from 'qs'; -const ISSUE_HEADER_NAME = 'cf-chl-bypass'; -const NUMBER_OF_REQUESTED_TOKENS = 30; -const ISSUANCE_BODY_PARAM_NAME = 'blinded-tokens'; +const NUMBER_OF_REQUESTED_TOKENS: number = 30; +const DEFAULT_ISSUING_HOSTNAME: string = 'captcha.website'; +const DEFAULT_ISSUING_QUERY_PARAM: string = '__cf_chl_f_tk'; +const CHL_BYPASS_SUPPORT: string = 'cf-chl-bypass'; +const ISSUE_HEADER_NAME: string = 'cf-chl-bypass'; +const ISSUANCE_BODY_PARAM_NAME: string = 'blinded-tokens'; -const COMMITMENT_URL = +const COMMITMENT_URL: string = 'https://raw.githubusercontent.com/privacypass/ec-commitments/master/commitments-p256.json'; -const QUALIFIED_QUERY_PARAMS = ['__cf_chl_captcha_tk__', '__cf_chl_managed_tk__']; -const QUALIFIED_BODY_PARAMS = ['g-recaptcha-response', 'h-captcha-response', 'cf_captcha_kind']; +const ALL_ISSUING_CRITERIA: { + HOSTNAMES: QUALIFIED_HOSTNAMES | void; + PATHNAMES: QUALIFIED_PATHNAMES | void; + QUERY_PARAMS: QUALIFIED_PARAMS | void; + BODY_PARAMS: QUALIFIED_PARAMS | void; +} = { + HOSTNAMES: { + exact : [DEFAULT_ISSUING_HOSTNAME], + contains: [`.${DEFAULT_ISSUING_HOSTNAME}`], + }, + PATHNAMES: { + exact : ['/'], + }, + QUERY_PARAMS: { + some: [DEFAULT_ISSUING_QUERY_PARAM, '__cf_chl_captcha_tk__', '__cf_chl_managed_tk__'], + }, + BODY_PARAMS: { + some: ['g-recaptcha-response', 'h-captcha-response', 'cf_captcha_kind', 'cf_ch_verify'], + }, +} -const CHL_BYPASS_SUPPORT = 'cf-chl-bypass'; -const DEFAULT_ISSUING_HOSTNAME = 'captcha.website'; +const ISSUANCE_REFERER_REGEX: RegExp = /^(.*[\?&])(?:__cf_chl_tk)([=].*)$/i; +const ISSUANCE_QUERY_PARAM_REGEX: RegExp = new RegExp('^(.*[\\?&])(?:' + ALL_ISSUING_CRITERIA.QUERY_PARAMS!.some!.join('|') + ')([=].*)$', 'i'); -const VERIFICATION_KEY = `-----BEGIN PUBLIC KEY----- +const VERIFICATION_KEY: string = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExf0AftemLr0YSz5odoj3eJv6SkOF VcH7NNb2xwdEz6Pxm44tvovEl/E+si8hdIDVg1Ys+cbaWwP0jYJW3ygv+Q== -----END PUBLIC KEY-----`; -const TOKEN_STORE_KEY = 'tokens'; +interface IssueInfo { + requestId: string; + url: string; + formData: { [key: string]: string[] | string }; +} interface RedeemInfo { requestId: string; token: Token; } -export class CloudflareProvider implements Provider { +export class CloudflareProvider extends Provider { static readonly ID: number = 1; - private callbacks: Callbacks; - private storage: Storage; + static readonly EARNED_TOKEN_COOKIE: EarnedTokenCookie = { + url: `https://${DEFAULT_ISSUING_HOSTNAME}/`, + domain: `.${DEFAULT_ISSUING_HOSTNAME}`, + name: 'cf_clearance' + }; + + private VOPRF: voprf.VOPRF; + private callbacks: Callbacks; + private storage: Storage; + private issueInfo: IssueInfo | null; private redeemInfo: RedeemInfo | null; constructor(storage: Storage, callbacks: Callbacks) { - // TODO This changes the global state in the crypto module, which can be a side effect outside of this object. - // It's better if we can refactor the crypto module to be in object-oriented concept. - voprf.initECSettings(voprf.defaultECSettings); + super(storage, callbacks); - this.callbacks = callbacks; - this.storage = storage; + this.VOPRF = new voprf.VOPRF(voprf.defaultECSettings); + this.callbacks = callbacks; + this.storage = storage; + this.issueInfo = null; this.redeemInfo = null; } private getStoredTokens(): Token[] { - const stored = this.storage.getItem(TOKEN_STORE_KEY); + const stored = this.storage.getItem(Provider.TOKEN_STORE_KEY); if (stored === null) { return []; } const tokens: string[] = JSON.parse(stored); - return tokens.map((token) => Token.fromString(token)); + return tokens.map((token) => Token.fromString(token, this.VOPRF)); } private setStoredTokens(tokens: Token[]) { this.storage.setItem( - TOKEN_STORE_KEY, + Provider.TOKEN_STORE_KEY, JSON.stringify(tokens.map((token) => token.toString())), ); + + this.forceUpdateIcon(); } - getID(): number { - return CloudflareProvider.ID; + private getBadgeText(): string { + return this.getStoredTokens().length.toString(); } - private async getCommitment(version: string): Promise<{ G: string; H: string }> { - const keyPrefix = 'commitment-'; - const cached = this.storage.getItem(`${keyPrefix}${version}`); - if (cached !== null) { - return JSON.parse(cached); + forceUpdateIcon(): void { + this.callbacks.updateIcon(this.getBadgeText()); + } + + handleActivated(): void { + this.forceUpdateIcon(); + } + + handleBeforeRequest( + details: chrome.webRequest.WebRequestBodyDetails, + ): chrome.webRequest.BlockingResponse | void { + + if (this.matchesIssuingBodyCriteria(details)) { + // do NOT cancel the request with captcha solution. + // note: "handleBeforeSendHeaders" will cancel this request if additional criteria are satisfied. + return { cancel: false }; } + } - interface Response { - CF: { [version: string]: { H: string; expiry: string; sig: string } }; + private matchesIssuingBodyCriteria( + details: chrome.webRequest.WebRequestBodyDetails, + ): boolean { + + // Only issue tokens for POST requests that contain data in body. + if ( + (details.method.toUpperCase() !== 'POST' ) || + (details.requestBody === null ) || + (details.requestBody === undefined) + ) { + return false; } - // Download the commitment - const { data } = await axios.get(COMMITMENT_URL); - const commitment = data.CF[version]; - if (commitment === undefined) { - throw new Error(`No commitment for the version ${version} is found`); + const url: URL = new URL(details.url); + + // Only issue tokens to hosts belonging to the provider. + if (!isIssuingHostname(ALL_ISSUING_CRITERIA.HOSTNAMES, url)) { + return false; } - // Check the expiry date. - const expiry = new Date(commitment.expiry); - if (Date.now() >= +expiry) { - throw new Error(`Commitments expired in ${expiry.toString()}`); + // Only issue tokens when the pathname passes defined criteria. + if (!isQualifiedPathname(ALL_ISSUING_CRITERIA.PATHNAMES, url)) { + return false; } - // This will throw an error on a bad signature. - voprf.verifyConfiguration( - VERIFICATION_KEY, - { - H: commitment.H, - expiry: commitment.expiry, - }, - commitment.sig, - ); + const formData: { [key: string]: string[] | string } = getNormalizedFormData(details, /* flatten= */ true); - // Cache. - const item = { - G: voprf.sec1EncodeToBase64(voprf.getActiveECSettings().curve.G, false), - H: commitment.H, + // Only issue tokens when 'application/x-www-form-urlencoded' or 'application/json' data parameters in POST body pass defined criteria. + if (!areQualifiedBodyFormParams(ALL_ISSUING_CRITERIA.BODY_PARAMS, formData)) { + return false; + } + + this.issueInfo = { requestId: details.requestId, url: details.url, formData }; + + return true; + } + + handleHeadersReceived( + details: chrome.webRequest.WebResponseHeadersDetails, + ): chrome.webRequest.BlockingResponse | void { + // Don't redeem a token on the issuing website. + if (isIssuingHostname(ALL_ISSUING_CRITERIA.HOSTNAMES, new URL(details.url))) { + return; + } + + // Check if it's the response of the request that we should insert a token. + if (details.statusCode !== 403 || details.responseHeaders === undefined) { + return; + } + const hasSupportHeader = details.responseHeaders.some((header) => { + return ( + header.name.toLowerCase() === CHL_BYPASS_SUPPORT && + header.value !== undefined && + parseInt(header.value, 10) === CloudflareProvider.ID + ); + }); + if (!hasSupportHeader) { + return; + } + + // Redeem one token (if available) + + const tokens = this.getStoredTokens(); + const token = tokens.shift(); + this.setStoredTokens(tokens); + + // No tokens in wallet! + if (token === undefined) { + return; + } + + this.redeemInfo = { requestId: details.requestId, token }; + + // Redirect to resend the request attached with the token. + return { + redirectUrl: details.url, }; - this.storage.setItem(`${keyPrefix}${version}`, JSON.stringify(item)); - return item; + } + + handleBeforeSendHeaders( + details: chrome.webRequest.WebRequestHeadersDetails, + ): chrome.webRequest.BlockingResponse | void { + + if ( + (this.issueInfo !== null) && + (this.issueInfo.requestId === details.requestId) + ) { + if (this.matchesIssuingHeadersCriteria(details)) { + this.triggerIssueRequest(details.requestId); + + // cancel the request with captcha solution. + return { cancel: true }; + } + else { + // Clear the issue info. + this.issueInfo = null; + } + } + + return this.redeemToken(details); + } + + private redeemToken( + details: chrome.webRequest.WebRequestHeadersDetails, + ): chrome.webRequest.BlockingResponse | void { + if ( + (this.redeemInfo === null) || + (this.redeemInfo.requestId !== details.requestId) + ) { + return; + } + + const token = this.redeemInfo!.token; + + // Clear the redeem info. + this.redeemInfo = null; + + const url = new URL(details.url); + const key = token.getMacKey(); + const binding = this.VOPRF.createRequestBinding(key, [ + voprf.getBytesFromString(url.hostname), + voprf.getBytesFromString(details.method + ' ' + url.pathname), + ]); + + const contents = [ + voprf.getBase64FromBytes(token.getInput()), + binding, + voprf.getBase64FromString(JSON.stringify(voprf.defaultECSettings)), + ]; + const redemption = btoa(JSON.stringify({ type: 'Redeem', contents })); + + const headers = details.requestHeaders ?? []; + headers.push({ name: 'challenge-bypass-token', value: redemption }); + + return {requestHeaders: headers}; + } + + private matchesIssuingHeadersCriteria( + details: chrome.webRequest.WebRequestHeadersDetails, + ): boolean { + let href: string; + let url: URL; + + if ( + (this.issueInfo === null) || + (this.issueInfo.requestId !== details.requestId) + ) { + return false; + } + + href = this.issueInfo.url; + url = new URL(href); + + // Issue tokens when querystring parameters pass defined criteria. + if (areQualifiedQueryParams(ALL_ISSUING_CRITERIA.QUERY_PARAMS, url)) { + if (href.indexOf(DEFAULT_ISSUING_QUERY_PARAM) === -1) { + // Normalize name of querystring parameter + href = href.replace(ISSUANCE_QUERY_PARAM_REGEX, ('$1' + DEFAULT_ISSUING_QUERY_PARAM + '$2')); + this.issueInfo.url = href; + } + return true; + } + + // Issue tokens when querystring parameters in value of 'Referer' request header pass defined criteria. + if (details.requestHeaders) { + const ref_header = details.requestHeaders.find(h => (h !== undefined) && h.name && h.value && (h.name.toLowerCase() === 'referer')); + + if ((ref_header !== undefined) && (ref_header.value !== undefined) && ISSUANCE_REFERER_REGEX.test(ref_header.value)) { + href = ref_header.value.replace(ISSUANCE_REFERER_REGEX, ('$1' + DEFAULT_ISSUING_QUERY_PARAM + '$2')); + this.issueInfo.url = href; + return true; + } + } + + return false; + } + + private triggerIssueRequest(requestId: string): void { + // Is the current (cancelled) request a trigger to initiate a secondary request to the provider for the issuing of signed tokens? + if ( + (this.issueInfo !== null) && + (this.issueInfo.requestId === requestId) + ) { + const issueInfo: IssueInfo = { ...this.issueInfo }; + + // Clear the issue info. + this.issueInfo = null; + + setTimeout( + (): void => { + this.sendIssueRequest(issueInfo.url, issueInfo.formData); + }, + 0 + ); + } + } + + private async sendIssueRequest( + url: string, + formData: { [key: string]: string[] | string }, + ): Promise { + try { + // Issue tokens. + const tokens = await this.issue(url, formData); + + // Store tokens. + const cached = this.getStoredTokens(); + this.setStoredTokens(cached.concat(tokens)); + } + catch(error: any) { + console.error(error.message); + } + + this.callbacks.navigateUrl(CloudflareProvider.EARNED_TOKEN_COOKIE.url); } private async issue( - url: string, + url: string, formData: { [key: string]: string[] | string }, ): Promise { - const tokens = Array.from(Array(NUMBER_OF_REQUESTED_TOKENS).keys()).map(() => new Token()); + const tokens = Array.from(Array(NUMBER_OF_REQUESTED_TOKENS).keys()).map(() => new Token(this.VOPRF)); const issuance = { type: 'Issue', contents: tokens.map((token) => token.getEncodedBlindedPoint()), @@ -129,7 +356,8 @@ export class CloudflareProvider implements Provider { }); const headers = { - 'content-type': 'application/x-www-form-urlencoded', + 'accept': 'application/json', + 'content-type': 'application/x-www-form-urlencoded', [ISSUE_HEADER_NAME]: CloudflareProvider.ID.toString(), }; @@ -147,23 +375,23 @@ export class CloudflareProvider implements Provider { } interface SignaturesParam { - sigs: string[]; + sigs: string[]; version: string; - proof: string; - prng: string; + proof: string; + prng?: string; } const data: SignaturesParam = JSON.parse(atob(signatures)); - const returned = voprf.getCurvePoints(data.sigs); + const returned = this.VOPRF.getCurvePoints(data.sigs); const commitment = await this.getCommitment(data.version); - const result = voprf.verifyProof( + const result = this.VOPRF.verifyProof( data.proof, tokens.map((token) => token.toLegacy()), returned, commitment, - data.prng, + data.prng || 'shake', ); if (!result) { throw new Error('DLEQ proof is invalid.'); @@ -176,143 +404,68 @@ export class CloudflareProvider implements Provider { return tokens; } - private getBadgeText(): string { - return this.getStoredTokens().length.toString(); - } - - forceUpdateIcon(): void { - this.callbacks.updateIcon(this.getBadgeText()); - } - - handleActivated(): void { - this.callbacks.updateIcon(this.getBadgeText()); - } - - handleBeforeSendHeaders( - details: chrome.webRequest.WebRequestHeadersDetails, - ): chrome.webRequest.BlockingResponse | void { - if (this.redeemInfo === null || details.requestId !== this.redeemInfo.requestId) { - return; - } - - const url = new URL(details.url); - - const token = this.redeemInfo!.token; - // Clear the redeem info to indicate that we are already redeeming the token. - this.redeemInfo = null; - - const key = token.getMacKey(); - const binding = voprf.createRequestBinding(key, [ - voprf.getBytesFromString(url.hostname), - voprf.getBytesFromString(details.method + ' ' + url.pathname), - ]); - - const contents = [ - voprf.getBase64FromBytes(token.getInput()), - binding, - voprf.getBase64FromString(JSON.stringify(voprf.defaultECSettings)), - ]; - const redemption = btoa(JSON.stringify({ type: 'Redeem', contents })); - - const headers = details.requestHeaders ?? []; - headers.push({ name: 'challenge-bypass-token', value: redemption }); - - this.callbacks.updateIcon(this.getBadgeText()); - - return { - requestHeaders: headers, - }; - } - - handleBeforeRequest( - details: chrome.webRequest.WebRequestBodyDetails, - ): chrome.webRequest.BlockingResponse | void { - const url = new URL(details.url); - - if ( - details.requestBody === null || - details.requestBody === undefined || - details.requestBody.formData === undefined - ) { - return; + private async getCommitment(version: string): Promise<{ G: string; H: string }> { + const keyPrefix = 'commitment-'; + const cached = this.storage.getItem(`${keyPrefix}${version}`); + if (cached !== null) { + return JSON.parse(cached); } - const hasQueryParams = QUALIFIED_QUERY_PARAMS.some((param) => { - return url.searchParams.has(param); - }); - const hasBodyParams = QUALIFIED_BODY_PARAMS.some((param) => { - return details.requestBody !== null && param in details.requestBody.formData!; - }); - if (!hasQueryParams || !hasBodyParams) { - return; + interface Response { + CF: { [version: string]: { G: string; H: string } | { H: string; expiry: string; sig: string } }; } - const flattenFormData: { [key: string]: string[] | string } = {}; - for (const key in details.requestBody.formData) { - if (details.requestBody.formData[key].length == 1) { - const [value] = details.requestBody.formData[key]; - flattenFormData[key] = value; - } else { - flattenFormData[key] = details.requestBody.formData[key]; - } + // Download the commitment + const { data } = await axios.get(COMMITMENT_URL); + const commitment = data.CF[version]; + if (commitment === undefined) { + throw new Error(`No commitment for the version ${version} is found`); } - (async () => { - // Issue tokens. - const tokens = await this.issue(details.url, flattenFormData); - // Store tokens. - const cached = this.getStoredTokens(); - this.setStoredTokens(cached.concat(tokens)); - - this.callbacks.navigateUrl(`${url.origin}${url.pathname}`); - })(); + let item: { G: string; H: string }; - // TODO I tried to use redirectUrl with data URL or text/html and text/plain but it didn't work, so I continue - // cancelling the request. However, it seems that we can use image/* except image/svg+html. Let's figure how to - // use image data URL later. - // https://blog.mozilla.org/security/2017/11/27/blocking-top-level-navigations-data-urls-firefox-59/ - return { cancel: true }; - } - - handleHeadersReceived( - details: chrome.webRequest.WebResponseHeadersDetails, - ): chrome.webRequest.BlockingResponse | void { - // Don't redeem a token in the issuing website. - const url = new URL(details.url); - if (url.host === DEFAULT_ISSUING_HOSTNAME) { - return; + // Does the commitment require verification? + if ('G' in commitment) { + item = commitment; } + else { + // Check the expiry date. + const expiry: number = (new Date(commitment.expiry)).getTime(); + if (Date.now() >= expiry) { + throw new Error(`Commitments expired in ${expiry.toString()}`); + } - // Check if it's the response of the request that we should insert a token. - if (details.statusCode !== 403 || details.responseHeaders === undefined) { - return; - } - const hasSupportHeader = details.responseHeaders.some((header) => { - return ( - header.name.toLowerCase() === CHL_BYPASS_SUPPORT && - header.value !== undefined && - +header.value === CloudflareProvider.ID + // This will throw an error on a bad signature. + this.VOPRF.verifyConfiguration( + VERIFICATION_KEY, + { + H: commitment.H, + expiry: commitment.expiry, + }, + commitment.sig, ); - }); - if (!hasSupportHeader) { - return; + + item = { + G: voprf.sec1EncodeToBase64(this.VOPRF.getActiveECSettings().curve.G, false), + H: commitment.H, + }; } - // Let's try to redeem. + // Cache. + this.storage.setItem(`${keyPrefix}${version}`, JSON.stringify(item)); - // Get one token. - const tokens = this.getStoredTokens(); - const token = tokens.shift(); - this.setStoredTokens(tokens); + return item; + } - if (token === undefined) { - return; - } + handleOnCompleted( + _details: chrome.webRequest.WebResponseHeadersDetails, + ): void { + return; + } - this.redeemInfo = { requestId: details.requestId, token }; - // Redirect to resend the request attached with the token. - return { - redirectUrl: details.url, - }; + handleOnErrorOccurred( + _details: chrome.webRequest.WebResponseErrorDetails, + ): void { + return; } } diff --git a/src/background/providers/hcaptcha.test.ts b/src/background/providers/hcaptcha.test.ts new file mode 100644 index 00000000..7232d1ab --- /dev/null +++ b/src/background/providers/hcaptcha.test.ts @@ -0,0 +1,403 @@ +import { jest } from '@jest/globals'; +import { HcaptchaProvider } from './hcaptcha'; +import Token from '../token'; + +export class StorageMock { + store: Map; + + constructor() { + this.store = new Map(); + } + + getItem(key: string): string | null { + return this.store.get(key) ?? null; + } + + setItem(key: string, value: string): void { + this.store.set(key, value); + } +} + +test('setStoredTokens', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token()]; + provider['setStoredTokens'](tokens); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const storedTokens = JSON.parse(storage.store.get('tokens')!); + expect(storedTokens).toEqual(tokens.map((token) => token.toString())); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); +}); + +test('getStoredTokens', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token()]; + provider['setStoredTokens'](tokens); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const storedTokens = provider['getStoredTokens'](); + expect(storedTokens.map((token) => token.toString())).toEqual( + tokens.map((token) => token.toString()), + ); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); +}); + +test('getBadgeText', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token()]; + provider['setStoredTokens'](tokens); + const text = provider['getBadgeText'](); + expect(text).toBe('2'); +}); + +/* + * The issuance involves handleBeforeRequest and handleOnCompleted listeners. + * + * In handleBeforeRequest listener, + * 1. Check that the request matches the criteria for issuing new tokens. + * Such requests are submitting a solved captcha to the provider + * on a website controlled by the provider. + * 2. If so, the listener sets the "issueInfo" property, + * which includes the request id for subsequent processing. + * + * In handleOnCompleted, + * 1. Check that the "issueInfo" property is set, and its request id is a match. + * 2. If so, initiate a secondary request to the provider for the issuing of signed tokens. + */ +describe('issuance', () => { + describe('handleBeforeRequest', () => { + const validDetails: chrome.webRequest.WebRequestBodyDetails = { + method: 'POST', + url: 'https://hcaptcha.com/checkcaptcha/xxx?s=00000000-0000-0000-0000-000000000000', + requestId: 'xxx', + frameId: 1, + parentFrameId: 1, + tabId: 1, + type: 'xmlhttprequest' as chrome.webRequest.ResourceType, + timeStamp: 1, + requestBody: {}, + }; + + test('valid request', async () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + let result, issueInfo + + const reqDetails: chrome.webRequest.WebRequestBodyDetails = validDetails; + result = provider.handleBeforeRequest(reqDetails); + expect(result).toEqual({ cancel: false }); + + // Expect issueInfo to be set. + issueInfo = provider['issueInfo']; + expect(issueInfo!.requestId).toEqual(reqDetails.requestId); + expect(issueInfo!.url).toEqual(reqDetails.url); + + const tokens = [new Token(), new Token(), new Token()]; + const issue = jest.fn(async () => { + return tokens; + }); + provider['issue'] = issue; + + const resDetails: chrome.webRequest.WebResponseHeadersDetails = { + ...validDetails, + statusLine: 'HTTP/1.1 200 OK', + statusCode: 200, + responseHeaders: [], + }; + result = provider.handleOnCompleted(resDetails); + expect(result).toBeUndefined(); + await Promise.resolve(); + + expect(issue.mock.calls.length).toBe(1); + expect(issue).toHaveBeenCalledWith(issueInfo!.url); + + // Expect the tokens are added. + const storedTokens = provider['getStoredTokens'](); + expect(storedTokens.map((token) => token.toString())).toEqual( + tokens.map((token) => token.toString()), + ); + + // Expect issueInfo to be null. + issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + expect(navigateUrl.mock.calls.length).toBe(1); + expect(navigateUrl).toHaveBeenCalledWith('https://www.hcaptcha.com/privacy-pass'); + }); + + /* + * The request is invalid if any of the followings is true: + * 1. It has no url param of any of the followings: + * a. 's=00000000-0000-0000-0000-000000000000' + * 2. Its pathname does not contain of any of the followings: + * a. '/checkcaptcha' + */ + + test('invalid request: no query param', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + + const details: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + url: validDetails.url.substring(0, validDetails.url.indexOf('?')), + }; + const result = provider.handleBeforeRequest(details); + expect(result).toBeUndefined(); + + // Expect issueInfo to be null. + const issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(updateIcon).not.toHaveBeenCalled(); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + test('invalid request: no matching pathname', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + + const details: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + url: validDetails.url.replace(/checkcaptcha/g, 'getcaptcha'), + }; + const result = provider.handleBeforeRequest(details); + expect(result).toBeUndefined(); + + // Expect issueInfo to be null. + const issueInfo = provider['issueInfo']; + expect(issueInfo).toBeNull(); + + expect(updateIcon).not.toHaveBeenCalled(); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + }); +}); + +/* + * The redemption involves handleBeforeRequest and handleBeforeSendHeaders listeners. + * + * In handleBeforeRequest listener, + * 1. Check that the request matches the criteria for redemption. + * Such requests are asking for the provider to generate a new captcha. + * 2. If so, the listener sets the "redeemInfo" property, + * which includes the request id for subsequent processing. + * + * In handleBeforeSendHeaders, + * 1. Check that the "redeemInfo" property is set, and its request id is a match. + * 2. If so, add headers to include one token for redemption by provider. + */ +describe('redemption', () => { + describe('handleBeforeRequest', () => { + const validDetails: chrome.webRequest.WebRequestBodyDetails = { + method: 'POST', + url: 'https://hcaptcha.com/getcaptcha/xxx?s=11111111-1111-1111-1111-111111111111', + requestId: 'xxx', + frameId: 1, + parentFrameId: 1, + tabId: 1, + type: 'xmlhttprequest' as chrome.webRequest.ResourceType, + timeStamp: 1, + requestBody: { + formData: { + sitekey: ['xxx'], + motionData: ['xxx'], + host: ['non-issuing-domain.example.com'] + } + }, + }; + + test('valid response with tokens', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const token = Token.fromString( + '{"input":[238,205,51,250,226,251,144,68,170,68,235,25,231,152,125,63,215,10,42,37,65,157,56,22,98,23,129,9,157,179,223,64],"factor":"0x359953995df006ba98bdcf1383a4c75ca79ae41d4e718dcb051832ce65c002bc","blindedPoint":"BCrzbuVf2eSD/5NtR+o09ovo+oRWAwjwopzl7lb+IuOPuj/ctLkdlkeJQUeyjtUbfgJqU4BFNBRz9ln4z3Dk7Us=","unblindedPoint":"BLKf1op+oq4FcbNdP5vygTkGO3WWLHD6oXCCZDfaFyuFlruih49BStHm6QxtZZAqgCR9i6SsO6VP69hHnfBDNeg=","signed":{"blindedPoint":"BKEnbsQSwnHCxEv4ppp6XuqLV60FiQpF8YWvodQHdnmFHv7CKyWHqBLBW8fJ2uuV+uLxl99+VRYPxr8Q8E7i2Iw=","unblindedPoint":"BA8G3dHM554FzDiOtEsSBu0XYW8p5vA2OIEvnYQcJlRGHTiq2N6j3BKUbiI7I6fAy2vsOrwhrLGHOD+q7YxO+UM="}}', + ); + const tokens = [token, new Token(), new Token()]; + let result, redeemInfo; + + provider['setStoredTokens'](tokens); + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const bodyDetails: chrome.webRequest.WebRequestBodyDetails = validDetails; + result = provider.handleBeforeRequest(bodyDetails); + expect(result).toEqual({ cancel: false }); + + // Expect redeemInfo to be set. + redeemInfo = provider['redeemInfo']; + expect(redeemInfo!.requestId).toEqual(bodyDetails.requestId); + + const headDetails: any = { + ...validDetails, + requestHeaders: [], + }; + delete headDetails.requestBody; + + result = provider.handleBeforeSendHeaders(headDetails); + expect(result).toEqual({ + requestHeaders: [ + { name: 'challenge-bypass-host', value: 'hcaptcha.com' }, + { name: 'challenge-bypass-path', value: 'POST /getcaptcha' }, + { name: 'challenge-bypass-token', value: 'eyJ0eXBlIjoiUmVkZWVtIiwiY29udGVudHMiOlsiN3Mweit1TDdrRVNxUk9zWjU1aDlQOWNLS2lWQm5UZ1dZaGVCQ1oyejMwQT0iLCJhR3ZFRmJaUmN1SnZvcHpSUDBFT1pQb084eDJtdzV6Q3ptUG9mL3AwY3F3PSIsImV5SmpkWEoyWlNJNkluQXlOVFlpTENKb1lYTm9Jam9pYzJoaE1qVTJJaXdpYldWMGFHOWtJam9pYVc1amNtVnRaVzUwSW4wPSJdfQ==' }, + ], + }); + + // Expect redeemInfo to be unset. + redeemInfo = provider['redeemInfo']; + expect(redeemInfo).toBeNull(); + + // Expect one token to be consumed. + const storedTokens = provider['getStoredTokens'](); + expect(storedTokens.map((token) => token.toString())).toEqual( + tokens.slice(1).map((token) => token.toString()), + ); + + expect(updateIcon.mock.calls.length).toBe(2); + expect(updateIcon).toHaveBeenLastCalledWith((tokens.length - 1).toString()); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + test('valid response without tokens', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + let result; + + provider['setStoredTokens']([]); + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith('0'); + + const bodyDetails: chrome.webRequest.WebRequestBodyDetails = validDetails; + result = provider.handleBeforeRequest(bodyDetails); + + const headDetails: any = { + ...validDetails, + requestHeaders: [], + }; + delete headDetails.requestBody; + + result = provider.handleBeforeSendHeaders(headDetails); + expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(2); + expect(updateIcon).toHaveBeenLastCalledWith('0'); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + test('no response from an issuing domain (hostname)', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token(), new Token()]; + provider['setStoredTokens'](tokens); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + requestBody: { + formData: { + ...validDetails.requestBody!.formData!, + host: ['www.hcaptcha.com'], + }, + }, + }; + const result = provider.handleBeforeRequest(details); + expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + test('no response from an issuing domain (sitekey in body)', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token(), new Token()]; + provider['setStoredTokens'](tokens); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + requestBody: { + formData: { + ...validDetails.requestBody!.formData!, + sitekey: ['00000000-0000-0000-0000-000000000000'], + }, + }, + }; + const result = provider.handleBeforeRequest(details); + expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + + test('no response from an issuing domain (sitekey in querystring)', () => { + const storage = new StorageMock(); + const updateIcon = jest.fn(); + const navigateUrl = jest.fn(); + + const provider = new HcaptchaProvider(storage, { updateIcon, navigateUrl }); + const tokens = [new Token(), new Token(), new Token()]; + provider['setStoredTokens'](tokens); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(updateIcon).toHaveBeenCalledWith(tokens.length.toString()); + + const details: chrome.webRequest.WebRequestBodyDetails = { + ...validDetails, + url: validDetails.url.replace(/\?s=.*$/, '?s=00000000-0000-0000-0000-000000000000'), + }; + const result = provider.handleBeforeRequest(details); + expect(result).toBeUndefined(); + + expect(updateIcon.mock.calls.length).toBe(1); + expect(navigateUrl).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/background/providers/hcaptcha.ts b/src/background/providers/hcaptcha.ts index ba9d61c6..3cef9745 100644 --- a/src/background/providers/hcaptcha.ts +++ b/src/background/providers/hcaptcha.ts @@ -1,19 +1,119 @@ -import { Callbacks, Provider } from '.'; +import * as voprf from '../crypto/voprf'; -export class HcaptchaProvider implements Provider { +import { Provider, EarnedTokenCookie, Callbacks, QUALIFIED_HOSTNAMES, QUALIFIED_PATHNAMES, QUALIFIED_PARAMS, isIssuingHostname, isQualifiedPathname, areQualifiedQueryParams, areQualifiedBodyFormParams, getNormalizedFormData } from './provider'; +import { Storage } from '../storage'; +import Token from '../token'; +import axios from 'axios'; +import qs from 'qs'; + +const NUMBER_OF_REQUESTED_TOKENS: number = 5; +const DEFAULT_ISSUING_HOSTNAME: string = 'hcaptcha.com'; +const ISSUE_HEADER_NAME: string = 'cf-chl-bypass'; +const ISSUANCE_BODY_PARAM_NAME: string = 'blinded-tokens'; + +const COMMITMENT_URL: string = + 'https://raw.githubusercontent.com/privacypass/ec-commitments/master/commitments-p256.json'; + +const ALL_ISSUING_CRITERIA: { + HOSTNAMES: QUALIFIED_HOSTNAMES | void; + PATHNAMES: QUALIFIED_PATHNAMES | void; + QUERY_PARAMS: QUALIFIED_PARAMS | void; + BODY_PARAMS: QUALIFIED_PARAMS | void; +} = { + HOSTNAMES: { + exact : [DEFAULT_ISSUING_HOSTNAME], + contains: [`.${DEFAULT_ISSUING_HOSTNAME}`], + }, + PATHNAMES: { + contains: ['/checkcaptcha'], + }, + QUERY_PARAMS: { + some: ['s=00000000-0000-0000-0000-000000000000'], + }, + BODY_PARAMS: undefined, +} + +const ALL_REDEMPTION_CRITERIA: { + HOSTNAMES: QUALIFIED_HOSTNAMES | void; + PATHNAMES: QUALIFIED_PATHNAMES | void; + QUERY_PARAMS: QUALIFIED_PARAMS | void; + BODY_PARAMS: QUALIFIED_PARAMS | void; +} = { + HOSTNAMES: { + exact : [DEFAULT_ISSUING_HOSTNAME], + contains: [`.${DEFAULT_ISSUING_HOSTNAME}`], + }, + PATHNAMES: { + contains: ['/getcaptcha'], + }, + QUERY_PARAMS: { + some: ['s!=00000000-0000-0000-0000-000000000000'], + }, + BODY_PARAMS: { + every: ['sitekey!=00000000-0000-0000-0000-000000000000', 'motionData', 'host!=www.hcaptcha.com'], + }, +} + +const VERIFICATION_KEY: string = `-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4OifvSTxGcy3T/yac6LVugArFb89 +wvqGivp0/54wgeyWkvUZiUdlbIQF7BuGeO9C4sx4nHkpAgRfvd8jdBGz9g== +-----END PUBLIC KEY-----`; + +interface IssueInfo { + requestId: string; + url: string; +} + +interface RedeemInfo { + requestId: string; +} + +export class HcaptchaProvider extends Provider { static readonly ID: number = 2; - private callbacks: Callbacks; - constructor(callbacks: Callbacks) { - this.callbacks = callbacks; + static readonly EARNED_TOKEN_COOKIE: EarnedTokenCookie = { + url: `https://www.${DEFAULT_ISSUING_HOSTNAME}/privacy-pass`, + domain: `.${DEFAULT_ISSUING_HOSTNAME}`, + name: 'hc_clearance' + }; + + private VOPRF: voprf.VOPRF; + private callbacks: Callbacks; + private storage: Storage; + private issueInfo: IssueInfo | null; + private redeemInfo: RedeemInfo | null; + + constructor(storage: Storage, callbacks: Callbacks) { + super(storage, callbacks); + + this.VOPRF = new voprf.VOPRF(voprf.defaultECSettings); + this.callbacks = callbacks; + this.storage = storage; + this.issueInfo = null; + this.redeemInfo = null; } - getID(): number { - return HcaptchaProvider.ID; + private getStoredTokens(): Token[] { + const stored = this.storage.getItem(Provider.TOKEN_STORE_KEY); + if (stored === null) { + return []; + } + + const tokens: string[] = JSON.parse(stored); + return tokens.map((token) => Token.fromString(token, this.VOPRF)); + } + + private setStoredTokens(tokens: Token[]) { + this.storage.setItem( + Provider.TOKEN_STORE_KEY, + JSON.stringify(tokens.map((token) => token.toString())), + ); + + this.forceUpdateIcon(); } private getBadgeText(): string { - return 'N/A'; + return this.getStoredTokens().length.toString(); } forceUpdateIcon(): void { @@ -21,22 +121,324 @@ export class HcaptchaProvider implements Provider { } handleActivated(): void { - this.callbacks.updateIcon(this.getBadgeText()); + this.forceUpdateIcon(); } handleBeforeRequest( - _details: chrome.webRequest.WebRequestBodyDetails, + details: chrome.webRequest.WebRequestBodyDetails, ): chrome.webRequest.BlockingResponse | void { - return; + + if (this.matchesIssuingCriteria(details)) { + // do NOT cancel the request with captcha solution. + return { cancel: false }; + } + + if (this.matchesRedemptionCriteria(details)) { + // do NOT cancel the request to generate a new captcha. + // note: "handleBeforeSendHeaders" will add request headers to embed a token. + return { cancel: false }; + } + } + + private matchesIssuingCriteria( + details: chrome.webRequest.WebRequestBodyDetails, + ): boolean { + + // Only issue tokens for POST requests that contain data in body. + if ( + (details.method.toUpperCase() !== 'POST' ) || + (details.requestBody === null ) || + (details.requestBody === undefined) + ) { + return false; + } + + const url: URL = new URL(details.url); + + // Only issue tokens to hosts belonging to the provider. + if (!isIssuingHostname(ALL_ISSUING_CRITERIA.HOSTNAMES, url)) { + return false; + } + + // Only issue tokens when the pathname passes defined criteria. + if (!isQualifiedPathname(ALL_ISSUING_CRITERIA.PATHNAMES, url)) { + return false; + } + + // Only issue tokens when querystring parameters pass defined criteria. + if (!areQualifiedQueryParams(ALL_ISSUING_CRITERIA.QUERY_PARAMS, url)) { + return false; + } + + // conditionally short-circuit an expensive operation + if (ALL_ISSUING_CRITERIA.BODY_PARAMS !== undefined) { + const formData: { [key: string]: string[] | string } = getNormalizedFormData(details); + + // Only issue tokens when 'application/x-www-form-urlencoded' or 'application/json' data parameters in POST body pass defined criteria. + if (!areQualifiedBodyFormParams(ALL_ISSUING_CRITERIA.BODY_PARAMS, formData)) { + return false; + } + } + + this.issueInfo = { requestId: details.requestId, url: details.url }; + + return true; + } + + private matchesRedemptionCriteria( + details: chrome.webRequest.WebRequestBodyDetails, + ): boolean { + + // Only redeem tokens for POST requests that contain data in body. + if ( + (details.method.toUpperCase() !== 'POST' ) || + (details.requestBody === null ) || + (details.requestBody === undefined) + ) { + return false; + } + + const url: URL = new URL(details.url); + + // Only redeem tokens to hosts belonging to the provider. + if (!isIssuingHostname(ALL_REDEMPTION_CRITERIA.HOSTNAMES, url)) { + return false; + } + + // Only redeem tokens when the pathname passes defined criteria. + if (!isQualifiedPathname(ALL_REDEMPTION_CRITERIA.PATHNAMES, url)) { + return false; + } + + // Only redeem tokens when querystring parameters pass defined criteria. + if (!areQualifiedQueryParams(ALL_REDEMPTION_CRITERIA.QUERY_PARAMS, url)) { + return false; + } + + // conditionally short-circuit an expensive operation + if (ALL_REDEMPTION_CRITERIA.BODY_PARAMS !== undefined) { + const formData: { [key: string]: string[] | string } = getNormalizedFormData(details); + + // Only redeem tokens when 'application/x-www-form-urlencoded' or 'application/json' data parameters in POST body pass defined criteria. + if (!areQualifiedBodyFormParams(ALL_REDEMPTION_CRITERIA.BODY_PARAMS, formData)) { + return false; + } + } + + this.redeemInfo = { requestId: details.requestId }; + + return true; } + handleBeforeSendHeaders( - _details: chrome.webRequest.WebRequestHeadersDetails, + details: chrome.webRequest.WebRequestHeadersDetails, ): chrome.webRequest.BlockingResponse | void { - return; + if ( + (this.redeemInfo === null) || + (this.redeemInfo.requestId !== details.requestId) + ) { + return; + } + + // Clear the redeem info. + this.redeemInfo = null; + + // Redeem one token (if available) + + const tokens = this.getStoredTokens(); + const token = tokens.shift(); + this.setStoredTokens(tokens); + + // No tokens in wallet! + if (token === undefined) { + return; + } + + const url = new URL(details.url); + const key = token.getMacKey(); + const binding = this.VOPRF.createRequestBinding(key, [ + voprf.getBytesFromString(url.hostname), + voprf.getBytesFromString(details.method + ' ' + url.pathname), + ]); + + const contents = [ + voprf.getBase64FromBytes(token.getInput()), + binding, + voprf.getBase64FromString(JSON.stringify(voprf.defaultECSettings)), + ]; + const redemption = btoa(JSON.stringify({ type: 'Redeem', contents })); + + const headers = details.requestHeaders ?? []; + headers.push( + { name: 'challenge-bypass-host', value: 'hcaptcha.com' }, + { name: 'challenge-bypass-path', value: 'POST /getcaptcha' }, + { name: 'challenge-bypass-token', value: redemption }, + ); + + return {requestHeaders: headers}; } + handleHeadersReceived( _details: chrome.webRequest.WebResponseHeadersDetails, ): chrome.webRequest.BlockingResponse | void { return; } + + handleOnCompleted( + details: chrome.webRequest.WebResponseHeadersDetails, + ): void { + this.triggerIssueRequest(details.requestId); + } + + handleOnErrorOccurred( + details: chrome.webRequest.WebResponseErrorDetails, + ): void { + this.triggerIssueRequest(details.requestId); + } + + private triggerIssueRequest(requestId: string): void { + // Is the current (completed) request a trigger to initiate a secondary request to the provider for the issuing of signed tokens? + if ( + (this.issueInfo !== null) && + (this.issueInfo.requestId === requestId) + ) { + const url: string = this.issueInfo!.url; + + // Clear the issue info. + this.issueInfo = null; + + this.sendIssueRequest(url); + } + } + + private async sendIssueRequest(url: string): Promise { + try { + // Issue tokens. + const tokens = await this.issue(url); + + // Store tokens. + const cached = this.getStoredTokens(); + this.setStoredTokens(cached.concat(tokens)); + } + catch(error: any) { + console.error(error.message); + } + + this.callbacks.navigateUrl(HcaptchaProvider.EARNED_TOKEN_COOKIE.url); + } + + private async issue(url: string): Promise { + const tokens = Array.from(Array(NUMBER_OF_REQUESTED_TOKENS).keys()).map(() => new Token(this.VOPRF)); + const issuance = { + type: 'Issue', + contents: tokens.map((token) => token.getEncodedBlindedPoint()), + }; + const param = btoa(JSON.stringify(issuance)); + + const body = qs.stringify({ + [ISSUANCE_BODY_PARAM_NAME]: param, + 'captcha-bypass': true, + }); + + const headers = { + 'accept': 'application/json', + 'content-type': 'application/x-www-form-urlencoded', + [ISSUE_HEADER_NAME]: HcaptchaProvider.ID.toString(), + }; + + const response = await axios.post(url, body, { + headers, + responseType: 'text', + }); + + const { signatures } = qs.parse(response.data); + if (signatures === undefined) { + throw new Error('There is no signatures parameter in the issuance response.'); + } + if (typeof signatures !== 'string') { + throw new Error('The signatures parameter in the issuance response is not a string.'); + } + + interface SignaturesParam { + sigs: string[]; + version: string; + proof: string; + prng?: string; + } + + const data: SignaturesParam = JSON.parse(atob(signatures)); + const returned = this.VOPRF.getCurvePoints(data.sigs); + + const commitment = await this.getCommitment(data.version); + + const result = this.VOPRF.verifyProof( + data.proof, + tokens.map((token) => token.toLegacy()), + returned, + commitment, + data.prng || 'shake', + ); + if (!result) { + throw new Error('DLEQ proof is invalid.'); + } + + tokens.forEach((token, index) => { + token.setSignedPoint(returned.points[index]); + }); + + return tokens; + } + + private async getCommitment(version: string): Promise<{ G: string; H: string }> { + const keyPrefix = 'commitment-'; + const cached = this.storage.getItem(`${keyPrefix}${version}`); + if (cached !== null) { + return JSON.parse(cached); + } + + interface Response { + HC: { [version: string]: { G: string; H: string } | { H: string; expiry: string; sig: string } }; + } + + // Download the commitment + const { data } = await axios.get(COMMITMENT_URL); + const commitment = data.HC[version]; + if (commitment === undefined) { + throw new Error(`No commitment for the version ${version} is found`); + } + + let item: { G: string; H: string }; + + // Does the commitment require verification? + if ('G' in commitment) { + item = commitment; + } + else { + // Check the expiry date. + const expiry: number = (new Date(commitment.expiry)).getTime(); + if (Date.now() >= expiry) { + throw new Error(`Commitments expired in ${expiry.toString()}`); + } + + // This will throw an error on a bad signature. + this.VOPRF.verifyConfiguration( + VERIFICATION_KEY, + { + H: commitment.H, + expiry: commitment.expiry, + }, + commitment.sig, + ); + + item = { + G: voprf.sec1EncodeToBase64(this.VOPRF.getActiveECSettings().curve.G, false), + H: commitment.H, + }; + } + + // Cache. + this.storage.setItem(`${keyPrefix}${version}`, JSON.stringify(item)); + + return item; + } } diff --git a/src/background/providers/index.ts b/src/background/providers/index.ts index a133ae97..ec606072 100644 --- a/src/background/providers/index.ts +++ b/src/background/providers/index.ts @@ -1,22 +1,20 @@ -export { CloudflareProvider } from './cloudflare'; -export { HcaptchaProvider } from './hcaptcha'; +import { Callbacks, EarnedTokenCookie, Provider } from './provider'; -export interface Provider { - getID(): number; - forceUpdateIcon(): void; - handleBeforeRequest( - details: chrome.webRequest.WebRequestBodyDetails, - ): chrome.webRequest.BlockingResponse | void; - handleHeadersReceived( - details: chrome.webRequest.WebResponseHeadersDetails, - ): chrome.webRequest.BlockingResponse | void; - handleBeforeSendHeaders( - details: chrome.webRequest.WebRequestHeadersDetails, - ): chrome.webRequest.BlockingResponse | void; - handleActivated(): void; +import { CloudflareProvider } from './cloudflare'; +import { HcaptchaProvider } from './hcaptcha'; + +export type { + Callbacks, + EarnedTokenCookie, } -export interface Callbacks { - updateIcon(text: string): void; - navigateUrl(url: string): void; +export { + Provider, + CloudflareProvider, + HcaptchaProvider, } + +export const Providers: (typeof Provider)[] = [ + CloudflareProvider, + HcaptchaProvider, +] diff --git a/src/background/providers/provider.ts b/src/background/providers/provider.ts new file mode 100644 index 00000000..968e65e0 --- /dev/null +++ b/src/background/providers/provider.ts @@ -0,0 +1,232 @@ +import { Storage } from '../storage'; +import qs from 'qs'; + +export interface Callbacks { + updateIcon(text: string): void; + navigateUrl(url: string): void; +} + +export interface EarnedTokenCookie { + url: string; + domain: string; + name: string; +} + +export abstract class Provider { + static readonly TOKEN_STORE_KEY: string = 'tokens'; + + static readonly ID: number; + static readonly EARNED_TOKEN_COOKIE: EarnedTokenCookie | void; + + constructor(_storage: Storage, _callbacks: Callbacks){} + + abstract forceUpdateIcon(): void; + abstract handleActivated(): void; + abstract handleBeforeRequest( + details: chrome.webRequest.WebRequestBodyDetails, + ): chrome.webRequest.BlockingResponse | void; + abstract handleHeadersReceived( + details: chrome.webRequest.WebResponseHeadersDetails, + ): chrome.webRequest.BlockingResponse | void; + abstract handleBeforeSendHeaders( + details: chrome.webRequest.WebRequestHeadersDetails, + ): chrome.webRequest.BlockingResponse | void; + abstract handleOnCompleted( + details: chrome.webRequest.WebResponseHeadersDetails, + ): void; + abstract handleOnErrorOccurred( + details: chrome.webRequest.WebResponseErrorDetails, + ): void; +} + +// ----------------------------------------------------------------------------- +// static methods + +interface QUALIFIED_STRING { + exact?: string[]; + contains?: string[]; +} + +export type QUALIFIED_HOSTNAMES = QUALIFIED_STRING; +export type QUALIFIED_PATHNAMES = QUALIFIED_STRING; + +export interface QUALIFIED_PARAMS { + some?: string[]; + every?: string[]; +} + +function isQualifiedStringFound(haystack: QUALIFIED_STRING | void, needle: string, result_empty_haystack: boolean = true): boolean { + let empty = true; + let found = false; + + if (haystack instanceof Object) { + if (!found && Array.isArray(haystack.exact) && haystack.exact.length) { + empty = false; + found = (haystack.exact.indexOf(needle) >= 0); + } + if (!found && Array.isArray(haystack.contains) && haystack.contains.length) { + empty = false; + found = haystack.contains.some(part => (needle.indexOf(part) >= 0)); + } + } + + return empty ? result_empty_haystack : found; +} + +export function isIssuingHostname(hostnames: QUALIFIED_HOSTNAMES | void, url: URL): boolean { + const hostname = url.host.toLowerCase(); + return isQualifiedStringFound(hostnames, hostname, false); +} + +export function isQualifiedPathname(pathnames: QUALIFIED_PATHNAMES | void, url: URL): boolean { + const pathname = url.pathname.toLowerCase(); + return isQualifiedStringFound(pathnames, pathname, true); +} + +function areQualifiedParamsFound(params: QUALIFIED_PARAMS | void, test: (param: string) => boolean, result_empty_haystack: boolean = true): boolean { + let empty = true; + let found = false; + + if (params instanceof Object) { + if (!found && Array.isArray(params.some) && params.some.length) { + empty = false; + found = params.some.some(test); + } + if (!found && Array.isArray(params.every) && params.every.length) { + empty = false; + found = params.every.every(test); + } + } + + return empty ? result_empty_haystack : found; +} + +function isQualifiedQueryParam(url: URL, param: string): boolean { + let [param_name, param_value] = param.split('=', 2); + let param_exact: boolean = true; + if (param_value) { + if (param_name[param_name.length - 1] === '!') { + param_exact = false; + param_name = param_name.substring(0, param_name.length - 1); + } + } + + if (!url.searchParams.has(param_name)) return false; + + if (param_value) { + const actual_value: string | null = url.searchParams.get(param_name); + + return param_exact + ? (actual_value! === param_value) + : (actual_value! !== param_value) + ; + } + else { + return true; + } +} + +export function areQualifiedQueryParams(params: QUALIFIED_PARAMS | void, url: URL): boolean { + const test: (param: string) => boolean = isQualifiedQueryParam.bind(null, url); + return areQualifiedParamsFound(params, test, true); +} + +function isQualifiedBodyFormParam(formData: { [key: string]: string[] | string } | void, param: string): boolean { + if (!(formData instanceof Object)) return false; + + let [param_name, param_value] = param.split('=', 2); + let param_exact: boolean = true; + if (param_value) { + if (param_name[param_name.length - 1] === '!') { + param_exact = false; + param_name = param_name.substring(0, param_name.length - 1); + } + } + + if (!(param_name in formData)) return false; + + if (param_value) { + const actual_value: string | string[] = formData[param_name]; + + if (Array.isArray(actual_value)) { + const isInArray: boolean = (actual_value.indexOf(param_value) !== -1); + + return param_exact + ? isInArray + : !isInArray + ; + } + else { + return param_exact + ? (actual_value === param_value) + : (actual_value !== param_value) + ; + } + } + else { + return true; + } +} + +export function areQualifiedBodyFormParams(params: QUALIFIED_PARAMS | void, formData: { [key: string]: string[] | string } | void): boolean { + const test: (param: string) => boolean = isQualifiedBodyFormParam.bind(null, formData); + return areQualifiedParamsFound(params, test, true); +} + +export function getNormalizedFormData( + details: chrome.webRequest.WebRequestBodyDetails, + flatten: boolean = false, +): { [key: string]: string[] | string } { + let formData: { [key: string]: string[] | string } = {}; + + if (details.requestBody instanceof Object) { + if (details.requestBody.formData instanceof Object) { + formData = details.requestBody.formData; + } + else if (Array.isArray(details.requestBody.raw) && (details.requestBody.raw.length > 0)) { + try { + const decodedData = details.requestBody.raw.map(val => (val && val.bytes) ? new TextDecoder().decode(new Uint8Array(val.bytes!)) : '').join(''); + let isParsed: boolean = false; + + if (!isParsed) { + // content-type: application/x-www-form-urlencoded + try { + const parsedData: any = qs.parse(decodedData); + + if ((parsedData !== undefined) && (parsedData instanceof Object)) { + isParsed = true; + formData = parsedData; + } + } + catch(e1) {} + } + + if (!isParsed) { + // content-type: application/json + try { + const parsedData: any = JSON.parse(decodedData); + + if ((parsedData !== undefined) && (parsedData instanceof Object)) { + formData = parsedData; + } + } + catch(e2) {} + } + } + catch(error) {} + } + } + + if (flatten) { + for (const key in formData) { + if ( + Array.isArray(formData[key]) && + (formData[key].length === 1) + ) { + formData[key] = formData[key][0]; + } + } + } + + return formData; +} diff --git a/src/background/storage.ts b/src/background/storage.ts index b59eaa28..0e455bed 100644 --- a/src/background/storage.ts +++ b/src/background/storage.ts @@ -1,4 +1,9 @@ -export class LocalStorage { +export interface Storage { + getItem(key: string): string | null; + setItem(key: string, value: string): void; +} + +export class LocalStorage implements Storage { private prefix: string; constructor(prefix: string) { @@ -14,7 +19,10 @@ export class LocalStorage { } } -export interface Storage { - getItem(key: string): string | null; - setItem(key: string, value: string): void; +export function generatePrefixFromID(id: number): string { + return 'id-' + id; +} + +export function clearAllPasses(): void { + window.localStorage.clear(); } diff --git a/src/background/tab.ts b/src/background/tab.ts index bcafb690..33f3a461 100644 --- a/src/background/tab.ts +++ b/src/background/tab.ts @@ -1,5 +1,5 @@ -import { CloudflareProvider, HcaptchaProvider, Provider } from './providers'; -import { LocalStorage } from './storage'; +import { Provider, CloudflareProvider, HcaptchaProvider } from './providers'; +import { LocalStorage, generatePrefixFromID } from './storage'; // Header from server to indicate that Privacy Pass is supported. const CHL_BYPASS_SUPPORT = 'cf-chl-bypass'; @@ -92,8 +92,12 @@ export class Tab { return; } const [providerId] = details.responseHeaders - .filter((header) => header.name.toLowerCase() === CHL_BYPASS_SUPPORT) - .map((header) => header.value !== undefined && +header.value); + .filter((header) => (header.name.toLowerCase() === CHL_BYPASS_SUPPORT) && header.value) + .map((header) => header.value ? parseInt(header.value, 10) : null); + + if ((typeof providerId !== 'number') || isNaN(providerId)) { + return + } if (details.type === 'main_frame') { // The page in the tab is changed, so the context should change. @@ -103,7 +107,7 @@ export class Tab { // Cloudflare has higher precedence than Hcaptcha. if (providerId === CloudflareProvider.ID && !(this.context instanceof CloudflareProvider)) { - const context = new CloudflareProvider(new LocalStorage('cf'), { + const context = new CloudflareProvider(new LocalStorage(generatePrefixFromID(CloudflareProvider.ID)), { updateIcon: this.updateIcon, navigateUrl: this.navigateUrl, }); @@ -115,7 +119,7 @@ export class Tab { !(this.context instanceof CloudflareProvider) && !(this.context instanceof HcaptchaProvider) ) { - this.context = new HcaptchaProvider({ + this.context = new HcaptchaProvider(new LocalStorage(generatePrefixFromID(HcaptchaProvider.ID)), { updateIcon: this.updateIcon, navigateUrl: this.navigateUrl, }); @@ -129,4 +133,20 @@ export class Tab { return result; } + + handleOnCompleted( + details: chrome.webRequest.WebResponseHeadersDetails, + ): void { + if (this.context !== null) { + this.context.handleOnCompleted(details); + } + } + + handleOnErrorOccurred( + details: chrome.webRequest.WebResponseErrorDetails, + ): void { + if (this.context !== null) { + this.context.handleOnErrorOccurred(details); + } + } } diff --git a/src/background/token.test.ts b/src/background/token.test.ts index 7cd804c8..ccddf509 100644 --- a/src/background/token.test.ts +++ b/src/background/token.test.ts @@ -1,14 +1,4 @@ import Token from './token'; -import { initECSettings } from './voprf'; - -beforeAll(() => { - // TODO This shouldn't be needed after refactoring the voprf module. - initECSettings({ - curve: 'p256', - hash: 'sha256', - method: 'increment', - }); -}); test('Construct a token', () => { new Token(); diff --git a/src/background/token.ts b/src/background/token.ts index ca4c4e38..9cbffba9 100644 --- a/src/background/token.ts +++ b/src/background/token.ts @@ -1,4 +1,4 @@ -import * as voprf from './voprf'; +import * as voprf from './crypto/voprf'; interface SignedComponent { blindedPoint: voprf.Point; @@ -6,6 +6,8 @@ interface SignedComponent { } export default class Token { + private VOPRF: voprf.VOPRF; + private input: voprf.Bytes; private factor: voprf.BigNum; @@ -14,9 +16,15 @@ export default class Token { private signed: SignedComponent | null; - constructor() { - const { data: input, point: unblindedPoint } = voprf.newRandomPoint(); - const { blind: factor, point: blindedPoint } = voprf.blindPoint(unblindedPoint); + constructor(VOPRF: voprf.VOPRF | void) { + if (VOPRF === undefined) { + VOPRF = new voprf.VOPRF(voprf.defaultECSettings); + } + + this.VOPRF = VOPRF; + + const { data: input, point: unblindedPoint } = this.VOPRF.newRandomPoint(); + const { blind: factor, point: blindedPoint } = this.VOPRF.blindPoint(unblindedPoint); this.input = input; this.factor = factor; @@ -27,22 +35,27 @@ export default class Token { this.signed = null; } - static fromString(str: string): Token { + static fromString(str: string, VOPRF: voprf.VOPRF | void): Token { + if (VOPRF === undefined) { + VOPRF = new voprf.VOPRF(voprf.defaultECSettings); + } + const json = JSON.parse(str); const token: Token = Object.create(Token.prototype); - token.input = json.input; + token.VOPRF = VOPRF; + token.input = json.input; token.factor = voprf.newBigNum(json.factor); - token.blindedPoint = voprf.sec1DecodeFromBase64(json.blindedPoint); - token.unblindedPoint = voprf.sec1DecodeFromBase64(json.unblindedPoint); + token.blindedPoint = VOPRF.sec1DecodeFromBase64(json.blindedPoint); + token.unblindedPoint = VOPRF.sec1DecodeFromBase64(json.unblindedPoint); token.signed = json.signed !== null ? { - blindedPoint: voprf.sec1DecodeFromBase64(json.signed.blindedPoint), - unblindedPoint: voprf.sec1DecodeFromBase64(json.signed.unblindedPoint), + blindedPoint: VOPRF.sec1DecodeFromBase64(json.signed.blindedPoint), + unblindedPoint: VOPRF.sec1DecodeFromBase64(json.signed.unblindedPoint), } : null; @@ -50,8 +63,8 @@ export default class Token { } setSignedPoint(point: voprf.Point): void { - const blindedPoint = point; - const unblindedPoint = voprf.unblindPoint(this.factor, point); + const blindedPoint = point; + const unblindedPoint = this.VOPRF.unblindPoint(this.factor, point); this.signed = { blindedPoint, @@ -76,7 +89,7 @@ export default class Token { if (this.signed === null) { throw new Error('Unsigned token is used to derive a MAC key'); } - return voprf.deriveKey(this.signed.unblindedPoint, this.input); + return this.VOPRF.deriveKey(this.signed.unblindedPoint, this.input); } getInput(): voprf.Bytes { diff --git a/src/background/tsconfig.json b/src/background/tsconfig.json index 0ea43e49..147b5df7 100644 --- a/src/background/tsconfig.json +++ b/src/background/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "allowJs": true, "lib": [ "dom" ] diff --git a/src/background/voprf.d.ts b/src/background/voprf.d.ts deleted file mode 100644 index 9c4730c4..00000000 --- a/src/background/voprf.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -export type Point = unknown; -export type Bytes = unknown; -export type BigNum = { toString(): string }; - -export type Curve = 'p256'; -export type Hash = 'sha256'; -export type HashMethod = 'increment' | 'swu'; - -export interface ECSettings { - curve: any; - hash: Hash; - method: HashMethod; -} - -export const defaultECSettings: ECSettings; - -// TODO This should be implemented in a new Point class. -export function blindPoint(point: Point): { blind: BigNum; point: Point }; -// TODO This should be implemented in a new Point class. -export function newRandomPoint(): { data: Bytes; point: Point }; - -export function getActiveECSettings(): ECSettings; - -export function initECSettings(params: { curve: Curve; hash: Hash; method: HashMethod }): void; - -// TODO This should be implemented in a new Point class. -export function getCurvePoints(signatures: string[]): { - points: Point[]; - compressed: boolean; -}; - -// TODO This should be implemented in a new Point class. -export function sec1EncodeToBase64(point: Point, compressed: boolean): string; -// TODO This should be implemented in a new Point class. -export function sec1DecodeFromBase64(encoded: string): Point; - -export function verifyConfiguration(publicKey: string, config: any, signature: string): boolean; -// TODO Proof verification should be inside Token class. -export function verifyProof( - proof: string, - tokens: unknown[], - signatures: { points: Point[]; compressed: boolean }, - commitments: any, - prngName: any, -): boolean; - -export function unblindPoint(factor: BigNum, blindedPoint: Point): Point; - -export function newBigNum(encoded: string): BigNum; - -export function deriveKey(N: Point, token: any): any; -export function createRequestBinding(key: any, data: any): any; -export function getBytesFromString(str: any): any; -export function getBase64FromString(str: any): any; -export function getBase64FromBytes(bytes: any): any; diff --git a/src/background/voprf.js b/src/background/voprf.js deleted file mode 100644 index 38b19169..00000000 --- a/src/background/voprf.js +++ /dev/null @@ -1,931 +0,0 @@ -/** - * This implements a 2HashDH-based token scheme using the SJCL ecc package. - * - * @author: George Tankersley - * @author: Alex Davidson - */ - -import 'asn1-parser'; - -import sjcl from 'sjcl'; - -let PEM; -let ASN1; -if (typeof window !== 'undefined') { - PEM = window.PEM; - ASN1 = window.ASN1; -} - -export let shake256 = () => { - return createShake256(); -}; - -const BATCH_PROOF_PREFIX = 'batch-proof='; -const MASK = ['0xff', '0x1', '0x3', '0x7', '0xf', '0x1f', '0x3f', '0x7f']; - -const DIGEST_INEQUALITY_ERR = '[privacy-pass]: Recomputed digest does not equal received digest'; -const PARSE_ERR = '[privacy-pass]: Error parsing proof'; - -// Globals for keeping track of EC curve settings -let CURVE; -let CURVE_H2C_HASH; -let CURVE_H2C_METHOD; -let CURVE_H2C_LABEL; - -// 1.2.840.10045.3.1.7 point generation seed -const INC_H2C_LABEL = sjcl.codec.hex.toBits( - '312e322e3834302e31303034352e332e312e3720706f696e742067656e65726174696f6e2073656564', -); -const SSWU_H2C_LABEL = 'H2C-P256-SHA256-SSWU-'; - -export const defaultECSettings = { - curve: 'p256', - hash: 'sha256', - method: 'increment', -}; - -/** - * Sets the curve parameters for the current session based on the contents of - * activeConfig.h2c-params - * @param h2cParams - */ -export function initECSettings(h2cParams) { - const curveStr = h2cParams.curve; - const hashStr = h2cParams.hash; - const methodStr = h2cParams.method; - switch (curveStr) { - case 'p256': - if (methodStr != 'swu' && methodStr != 'increment') { - throw new Error( - "[privacy-pass]: Incompatible h2c method: '" + - methodStr + - "', for curve " + - curveStr, - ); - } else if (hashStr != 'sha256') { - throw new Error( - "[privacy-pass]: Incompatible h2c hash: '" + - hashStr + - "', for curve " + - curveStr, - ); - } - CURVE = sjcl.ecc.curves.c256; - CURVE_H2C_HASH = sjcl.hash.sha256; - CURVE_H2C_METHOD = methodStr; - CURVE_H2C_LABEL = methodStr === 'increment' ? INC_H2C_LABEL : SSWU_H2C_LABEL; - break; - default: - throw new Error('[privacy-pass]: Incompatible curve chosen: ' + curveStr); - } -} - -/** - * Returns the active configuration for the elliptic curve setting - * @return {Object} Object containing the active curve and h2c configuration - */ -export function getActiveECSettings() { - return { curve: CURVE, hash: CURVE_H2C_HASH, method: CURVE_H2C_METHOD, label: CURVE_H2C_LABEL }; -} - -/** - * Multiplies the point P with the scalar k and outputs kP - * @param {sjcl.bn} k scalar - * @param {sjcl.ecc.point} P curve point - * @return {sjcl.ecc.point} - */ -function _scalarMult(k, P) { - const Q = P.mult(k); - return Q; -} - -/** - * Samples a random scalar and uses it to blind the point P - * @param {sjcl.ecc.point} P curve point - * @return {sjcl.ecc.point} - */ -export function blindPoint(P) { - const bF = sjcl.bn.random(CURVE.r, 10); - const bP = _scalarMult(bF, P); - return { point: bP, blind: bF }; -} - -/** - * unblindPoint takes an assumed-to-be blinded point Q and an accompanying - * blinding scalar b, then returns the point (1/b)*Q. - * @param {sjcl.bn} b scalar blinding factor - * @param {sjcl.ecc.point} Q curve point - * @return {sjcl.ecc.point} - */ -export function unblindPoint(b, Q) { - const binv = b.inverseMod(CURVE.r); - return _scalarMult(binv, Q); -} - -/** - * Creates a new random point on the curve by sampling random bytes and then - * hashing to the chosen curve. - * @return {sjcl.ecc.point} - */ -export function newRandomPoint() { - const random = crypto.getRandomValues(new Int32Array(8)); - - // Choose hash-to-curve method - const point = h2Curve(random, getActiveECSettings()); - - let t; - if (point) { - t = { data: sjcl.codec.bytes.fromBits(random), point: point }; - } - return t; -} - -/** - * Encodes a curve point as bytes in SEC1 uncompressed format - * @param {sjcl.ecc.point} P - * @param {bool} compressed - * @return {sjcl.codec.bytes} - */ -export function sec1Encode(P, compressed) { - let out = []; - if (!compressed) { - const xyBytes = sjcl.codec.bytes.fromBits(P.toBits()); - out = [0x04].concat(xyBytes); - } else { - const xBytes = sjcl.codec.bytes.fromBits(P.x.toBits()); - const y = P.y.normalize(); - const sign = y.limbs[0] & 1 ? 0x03 : 0x02; - out = [sign].concat(xBytes); - } - return out; -} - -/** - * Encodes a curve point into bits for using as input to hash functions etc - * @param {sjcl.ecc.point} point curve point - * @param {bool} compressed flag indicating whether points have been compressed - * @return {sjcl.bitArray} - */ -function sec1EncodeToBits(point, compressed) { - return sjcl.codec.bytes.toBits(sec1Encode(point, compressed)); -} - -/** - * Encodes a point into a base 64 string - * @param {sjcl.ecc.point} point - * @param {bool} compressed - * @return {string} - */ -export function sec1EncodeToBase64(point, compressed) { - return sjcl.codec.base64.fromBits(sec1EncodeToBits(point, compressed)); -} - -/** - * Decodes a base64-encoded string into a curve point - * @param {string} p a base64-encoded, uncompressed curve point - * @return {sjcl.ecc.point} - */ -export function sec1DecodeFromBase64(p) { - const sec1Bits = sjcl.codec.base64.toBits(p); - const sec1Bytes = sjcl.codec.bytes.fromBits(sec1Bits); - return sec1DecodeFromBytes(sec1Bytes); -} - -/** - * Decodes (SEC1) curve point bytes into a valid curve point - * @param {sjcl.codec.bytes} sec1Bytes bytes of an uncompressed curve point - * @return {sjcl.ecc.point} - */ -export function sec1DecodeFromBytes(sec1Bytes) { - let P; - switch (sec1Bytes[0]) { - case 0x02: - case 0x03: - P = decompressPoint(sec1Bytes); - break; - case 0x04: - P = CURVE.fromBits(sjcl.codec.bytes.toBits(sec1Bytes.slice(1))); - break; - default: - throw new Error( - '[privacy-pass]: attempted sec1 point decoding with incorrect tag: ' + sec1Bytes[0], - ); - } - return P; -} - -/** - * Attempts to decompress a curve point in SEC1 encoded format. Returns null if - * the point is invalid - * @param {sjcl.codec.bytes} bytes bytes of a compressed curve point (SEC1) - * @return {sjcl.ecc.point} may be null if compressed bytes are not valid - */ -function decompressPoint(bytes) { - const yTag = bytes[0]; - const expLength = CURVE.r.bitLength() / 8 + 1; // bitLength rounds up - if (yTag != 2 && yTag != 3) { - throw new Error('[privacy-pass]: compressed point is invalid, bytes[0] = ' + yTag); - } else if (bytes.length !== expLength) { - throw new Error( - `[privacy-pass]: compressed point is too long, actual = ${bytes.length}, expected = ${expLength}`, - ); - } - const xBytes = bytes.slice(1); - const x = CURVE.field.fromBits(sjcl.codec.bytes.toBits(xBytes)).normalize(); - const sign = yTag & 1; - - // y^2 = x^3 - 3x + b (mod p) - let rh = x.power(3); - const threeTimesX = x.mul(CURVE.a); - rh = rh.add(threeTimesX).add(CURVE.b).mod(CURVE.field.modulus); // mod() normalizes - - // modsqrt(z) for p = 3 mod 4 is z^(p+1/4) - const sqrt = CURVE.field.modulus.add(1).normalize().halveM().halveM(); - let y = new CURVE.field(rh.powermod(sqrt, CURVE.field.modulus)); - - const parity = y.limbs[0] & 1; - if (parity != sign) { - y = CURVE.field.modulus.sub(y).normalize(); - } - - const point = new sjcl.ecc.point(CURVE, x, y); - if (!point.isValid()) { - // we return null here rather than an error as we iterate over this - // method during hash-and-inc - return null; - } - return point; -} - -/** - * Decodes the received curve points - * @param {Array} signatures An array of base64-encoded signed points - * @return {Object} object containing array of curve points and compression flag - */ -export function getCurvePoints(signatures) { - const compression = { on: false, set: false }; - const sigBytes = []; - signatures.forEach(function (signature) { - const buf = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(signature)); - let setting = false; - switch (buf[0]) { - case 2: - case 3: - setting = true; - break; - case 4: - // do nothing - break; - default: - throw new Error(`[privacy-pass]: point, ${buf}, is not encoded correctly`); - } - if (!validResponseCompression(compression, setting)) { - throw new Error('[privacy-pass]: inconsistent point compression in server response'); - } - sigBytes.push(buf); - }); - - const usablePoints = []; - sigBytes.forEach(function (buf) { - const usablePoint = sec1DecodeFromBytes(buf); - if (usablePoint == null) { - throw new Error('[privacy-pass]: unable to decode point: ' + buf); - } - usablePoints.push(usablePoint); - }); - return { points: usablePoints, compressed: compression.on }; -} - -/** - * Checks that the signed points from the IssueResponse have consistent - * compression - * @param {Object} compression compression object to be checked for consistency - * @param {bool} setting new setting based on point data - * @return {bool} - */ -function validResponseCompression(compression, setting) { - if (!compression.set) { - compression.on = setting; - compression.set = true; - } else if (compression.on !== setting) { - return false; - } - return true; -} - -// Commitments verification - -/** - * Parse a PEM-encoded signature. - * @param {string} pemSignature - A signature in PEM format. - * @return {sjcl.bitArray} a signature object for sjcl library. - */ -function parseSignaturefromPEM(pemSignature) { - try { - const bytes = PEM.parseBlock(pemSignature); - const json = ASN1.parse(bytes.der); - const r = sjcl.codec.bytes.toBits(json.children[0].value); - const s = sjcl.codec.bytes.toBits(json.children[1].value); - return sjcl.bitArray.concat(r, s); - } catch (e) { - throw new Error('[privacy-pass]: Failed on parsing commitment signature. ' + e.message); - } -} - -/** - * Parse a PEM-encoded public key. - * @param {string} pemPublicKey - A public key in PEM format. - * @return {sjcl.ecc.ecdsa.publicKey} a public key for sjcl library. - */ -function parsePublicKeyfromPEM(pemPublicKey) { - try { - let bytes = PEM.parseBlock(pemPublicKey); - let json = ASN1.parse(bytes.der); - let xy = json.children[1].value; - const point = sec1DecodeFromBytes(xy); - return new sjcl.ecc.ecdsa.publicKey(CURVE, point); - } catch (e) { - throw new Error('[privacy-pass]: Failed on parsing public key. ' + e.message); - } -} - -/** - * Verify the signature of the retrieved configuration portion. - * @param {Number} cfgId - ID of configuration being used. - * @param {json} config - commitments to verify - * @return {boolean} True, if the commitment has valid signature and is not - * expired; otherwise, throws an exception. - */ -export function verifyConfiguration(publicKey, config, signature) { - const sig = parseSignaturefromPEM(signature); - const msg = JSON.stringify(config); - const pk = parsePublicKeyfromPEM(publicKey); - const hmsg = sjcl.hash.sha256.hash(msg); - try { - return pk.verify(hmsg, sig); - } catch (error) { - throw new Error('[privacy-pass]: Invalid configuration verification.'); - } -} - -/** - * DLEQ proof verification logic - */ - -/** - * Verify the DLEQ proof object using the information provided - * @param {string} proofObj base64-encoded batched DLEQ proof object - * @param {Object} tokens array of token objects containing blinded curve points - * @param {Array} signatures an array of signed points - * @param {Object} commitments JSON object containing encoded curve points - * @param {string} prngName name of the PRNG used for verifying proof - * @return {boolean} - */ -export function verifyProof(proofObj, tokens, signatures, commitments, prngName) { - const bp = getMarshaledBatchProof(proofObj); - const dleq = retrieveProof(bp); - if (!dleq) { - // Error has probably occurred - return false; - } - if (tokens.length !== signatures.points.length) { - return false; - } - const pointG = sec1DecodeFromBase64(commitments.G); - const pointH = sec1DecodeFromBase64(commitments.H); - - // Recompute A and B for proof verification - const cH = _scalarMult(dleq.C, pointH); - const rG = _scalarMult(dleq.R, pointG); - const A = cH.toJac().add(rG).toAffine(); - - const composites = recomputeComposites(tokens, signatures, pointG, pointH, prngName); - const cZ = _scalarMult(dleq.C, composites.Z); - const rM = _scalarMult(dleq.R, composites.M); - const B = cZ.toJac().add(rM).toAffine(); - - // Recalculate C' and check if C =?= C' - const h = new CURVE_H2C_HASH(); // use the h2c hash for convenience - h.update(sec1EncodeToBits(pointG, signatures.compressed)); - h.update(sec1EncodeToBits(pointH, signatures.compressed)); - h.update(sec1EncodeToBits(composites.M, signatures.compressed)); - h.update(sec1EncodeToBits(composites.Z, signatures.compressed)); - h.update(sec1EncodeToBits(A, signatures.compressed)); - h.update(sec1EncodeToBits(B, signatures.compressed)); - const digestBits = h.finalize(); - const receivedDigestBits = dleq.C.toBits(); - if (!sjcl.bitArray.equal(digestBits, receivedDigestBits)) { - console.error(DIGEST_INEQUALITY_ERR); - console.error('Computed digest: ' + digestBits.toString()); - console.error('Received digest: ' + receivedDigestBits.toString()); - return false; - } - return true; -} - -/** - * Recompute the composite M and Z values for verifying DLEQ - * @param {Array} tokens array of token objects containing blinded curve points - * @param {Object} signatures contains array of signed curve points and compression flag - * @param {sjcl.ecc.point} pointG curve point - * @param {sjcl.ecc.point} pointH curve point - * @param {string} prngName name of PRNG used to verify proof - * @return {Object} Object containing composite points M and Z - */ -function recomputeComposites(tokens, signatures, pointG, pointH, prngName) { - const seed = computeSeed(tokens, signatures, pointG, pointH); - let cM = new sjcl.ecc.pointJac(CURVE); // can only add points in jacobian representation - let cZ = new sjcl.ecc.pointJac(CURVE); - const prng = { name: prngName }; - switch (prng.name) { - case 'shake': - prng.func = shake256(); - prng.func.update(seed, 'hex'); - break; - case 'hkdf': - prng.func = evaluateHkdf; - break; - default: - throw new Error(`Server specified PRNG is not compatible: ${prng.name}`); - } - let iter = -1; - for (let i = 0; i < tokens.length; i++) { - iter++; - const ci = computePRNGScalar(prng, seed, new sjcl.bn(iter).toBits()); - // Moved this check out of computePRNGScalar to here - if (ci.greaterEquals(CURVE.r)) { - i--; - continue; - } - const cMi = _scalarMult(ci, tokens[i].point); - const cZi = _scalarMult(ci, signatures.points[i]); - cM = cM.add(cMi); - cZ = cZ.add(cZi); - } - return { M: cM.toAffine(), Z: cZ.toAffine() }; -} - -/** - * Computes an output of a PRNG (using the seed if it is HKDF) as a sjcl bn - * object - * @param {Object} prng PRNG object for generating output - * @param {string} seed hex-encoded seed - * @param {sjcl.bitArray} salt optional salt for each PRNG eval - * @return {sjcl.bn} PRNG output as scalar value - */ -function computePRNGScalar(prng, seed, salt) { - const bitLen = CURVE.r.bitLength(); - const mask = MASK[bitLen % 8]; - let out; - switch (prng.name) { - case 'shake': - out = prng.func.squeeze(32, 'hex'); - break; - case 'hkdf': - out = sjcl.codec.hex.fromBits( - prng.func( - sjcl.codec.hex.toBits(seed), - bitLen / 8, - sjcl.codec.utf8String.toBits('DLEQ_PROOF'), - salt, - CURVE_H2C_HASH, - ), - ); - break; - default: - throw new Error(`Server specified PRNG is not compatible: ${prng.name}`); - } - // Masking is not strictly necessary for p256 but better to be completely - // compatible in case that the curve changes - const h = parseInt(out.substr(0, 2), 16); - const mh = sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits([h & mask])); - out = mh + out.substr(2); - const nOut = getBigNumFromHex(out); - return nOut; -} - -/** - * Computes a seed for the PRNG for verifying batch DLEQ proofs - * @param {Object} chkM array of token objects containing blinded curve points - * @param {sjcl.ecc.point[]} chkZ array of signed curve points - * @param {sjcl.ecc.point} pointG curve point - * @param {sjcl.ecc.point} pointH curve point - * @return {string} hex-encoded PRNG seed - */ -function computeSeed(chkM, chkZ, pointG, pointH) { - const compressed = chkZ.compressed; - const h = new CURVE_H2C_HASH(); // we use the h2c hash for convenience - h.update(sec1EncodeToBits(pointG, compressed)); - h.update(sec1EncodeToBits(pointH, compressed)); - for (let i = 0; i < chkM.length; i++) { - h.update(sec1EncodeToBits(chkM[i].point, compressed)); - h.update(sec1EncodeToBits(chkZ.points[i], compressed)); - } - return sjcl.codec.hex.fromBits(h.finalize()); -} - -/** - * hkdf - The HMAC-based Key Derivation Function - * based on https://github.com/mozilla/node-hkdf - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * @param {bitArray} ikm Initial keying material - * @param {integer} length Length of the derived key in bytes - * @param {bitArray} info Key derivation data - * @param {bitArray} salt Salt - * @param {sjcl.hash} hash hash function - * @return {bitArray} - */ -function evaluateHkdf(ikm, length, info, salt, hash) { - const mac = new sjcl.misc.hmac(salt, hash); - mac.update(ikm); - const prk = mac.digest(); - - const hashLength = Math.ceil(sjcl.bitArray.bitLength(prk) / 8); - const numBlocks = Math.ceil(length / hashLength); - if (numBlocks > 255) { - throw new Error( - `[privacy-pass]: HKDF error, number of proposed iterations too large: ${numBlocks}`, - ); - } - - let prev = sjcl.codec.hex.toBits(''); - let output = ''; - for (let i = 0; i < numBlocks; i++) { - const hmac = new sjcl.misc.hmac(prk, hash); - const input = sjcl.bitArray.concat( - sjcl.bitArray.concat(prev, info), - sjcl.codec.utf8String.toBits(String.fromCharCode(i + 1)), - ); - hmac.update(input); - prev = hmac.digest(); - output += sjcl.codec.hex.fromBits(prev); - } - return sjcl.bitArray.clamp(sjcl.codec.hex.toBits(output), length * 8); -} - -/** - * Returns a decoded DLEQ proof as an object that can be verified - * @param {Object} bp batch proof as encoded JSON - * @return {Object} DLEQ proof object - */ -function retrieveProof(bp) { - let dleqProof; - try { - dleqProof = parseDleqProof(atob(bp.P)); - } catch (e) { - console.error(`${PARSE_ERR}: ${e}`); - return; - } - return dleqProof; -} - -/** - * Decode proof string and remove prefix - * @param {string} proof base64-encoded batched DLEQ proof - * @return {Object} JSON batched DLEQ proof - */ -function getMarshaledBatchProof(proof) { - let proofStr = atob(proof); - if (proofStr.indexOf(BATCH_PROOF_PREFIX) === 0) { - proofStr = proofStr.substring(BATCH_PROOF_PREFIX.length); - } - return JSON.parse(proofStr); -} - -/** - * Decode the proof that is sent into an Object - * @param {string} proofStr proof JSON as string - * @return {Object} - */ -function parseDleqProof(proofStr) { - const dleqProofM = JSON.parse(proofStr); - const dleqProof = {}; - dleqProof.R = getBigNumFromB64(dleqProofM.R); - dleqProof.C = getBigNumFromB64(dleqProofM.C); - return dleqProof; -} - -/** - * Return a bignum from a base64-encoded string - * @param {string} b64Str - * @return {sjcl.bn} - */ -function getBigNumFromB64(b64Str) { - const bits = sjcl.codec.base64.toBits(b64Str); - return sjcl.bn.fromBits(bits); -} - -/** - * Return a big number from an array of bytes - * @param {sjcl.codec.bytes} bytes - * @return {sjcl.bn} - */ -export function getBigNumFromBytes(bytes) { - const bits = sjcl.codec.bytes.toBits(bytes); - return sjcl.bn.fromBits(bits); -} - -/** - * Return a big number from hex-encoded string - * @param {string} hex hex-encoded string - * @return {sjcl.bn} - */ -function getBigNumFromHex(hex) { - return sjcl.bn.fromBits(sjcl.codec.hex.toBits(hex)); -} - -const p256Curve = sjcl.ecc.curves.c256; -const precomputedP256 = { - // a=-3, but must be reduced mod p for P256; otherwise, - // inverseMod function loops forever. - A: p256Curve.a.fullReduce(), - B: p256Curve.b, - baseField: p256Curve.field, - c1: p256Curve.b.mul(-1).mul(p256Curve.a.inverseMod(p256Curve.field.modulus)), - c2: p256Curve.field.modulus.sub(1).cnormalize().halveM(), - sqrt: p256Curve.field.modulus.add(1).cnormalize().halveM().halveM(), -}; - -/** - * Converts the number x into a byte array of length n - * @param {Number} x - * @param {Number} n - * @return {sjcl.codec.bytes} - */ -function i2osp(x, n) { - const bytes = []; - for (let i = n - 1; i > -1; i--) { - bytes[i] = x & 0xff; - x = x >> 8; - } - - if (x > 0) { - throw new Error(`[privacy-pass]: number to convert (${x}) is too long for ${n} bytes.`); - } - return bytes; -} - -/** - * hashes bits to the base field (as described in - * draft-irtf-cfrg-hash-to-curve) - * @param {sjcl.bitArray} x bits of element to be translated - * @param {sjcl.ecc.curve} curve elliptic curve - * @param {sjcl.hash} hash hash function object - * @param {string} label context label for domain separation - * @return {int} integer in the base field of curve - */ -function h2Base(x, curve, hash, label) { - const dataLen = sjcl.codec.bytes.fromBits(x).length; - const h = new hash(); - h.update('h2b'); - h.update(label); - h.update(sjcl.codec.bytes.toBits(i2osp(dataLen, 4))); - h.update(x); - const t = h.finalize(); - const y = curve.field.fromBits(t).cnormalize(); - return y; -} - -/** - * hashes bits to the chosen elliptic curve - * @param {sjcl.bitArray} alpha bits to be encoded onto curve - * @param {Object} ecSettings the curve settings being used by the extension - * @return {sjcl.ecc.point} point on curve - */ -function h2Curve(alpha, ecSettings) { - let point; - switch (ecSettings.method) { - case 'swu': - point = simplifiedSWU(alpha, ecSettings.curve, ecSettings.hash, ecSettings.label); - break; - case 'increment': - point = hashAndInc(alpha, ecSettings.hash, ecSettings.label); - break; - default: - throw new Error( - '[privacy-pass]: Incompatible curve chosen for hashing, SJCL chosen curve: ' + - sjcl.ecc.curveName(ecSettings.curve), - ); - } - return point; -} - -/** - * hashes bits onto affine curve point using simplified SWU encoding algorithm - * Not constant-time due to conditional check - * @param {sjcl.bitArray} alpha bits to be encoded - * @param {sjcl.ecc.curve} activeCurve elliptic curve - * @param {sjcl.hash} hash hash function for hashing bytes to base field - * @param {String} label - * @return {sjcl.ecc.point} curve point - */ -function simplifiedSWU(alpha, activeCurve, hash, label) { - const params = getCurveParams(activeCurve); - const u = h2Base(alpha, activeCurve, hash, label); - const { X, Y } = computeSWUCoordinates(u, params); - const point = new sjcl.ecc.point(activeCurve, X, Y); - if (!point.isValid()) { - throw new Error(`[privacy-pass]: Generated point is not on curve, X: ${X}, Y: ${Y}`); - } - return point; -} - -/** - * Compute (X,Y) coordinates from integer u - * Operations taken from draft-irtf-cfrg-hash-to-curve.txt at commit - * cea8485220812a5d371deda25b5eca96bd7e6c0e - * @param {sjcl.bn} u integer to map - * @param {Object} params curve parameters - * @return {Object} curve coordinates - */ -function computeSWUCoordinates(u, params) { - const { A, B, baseField, c1, c2, sqrt } = params; - const p = baseField.modulus; - const t1 = u.square().mul(-1); // steps 2-3 - const t2 = t1.square(); // step 4 - let x1 = t2.add(t1); // step 5 - x1 = x1.inverse(); // step 6 - x1 = x1.add(1); // step 7 - x1 = x1.mul(c1); // step 8 - - let gx1 = x1.square().mod(p); // steps 9-12 - gx1 = gx1.add(A); - gx1 = gx1.mul(x1); - gx1 = gx1.add(B); - gx1 = gx1.mod(p); - - const x2 = t1.mul(x1); // step 13 - let gx2 = x2.square().mod(p); // step 14-17 - gx2 = gx2.add(A); - gx2 = gx2.mul(x2); - gx2 = gx2.add(B); - gx2 = gx2.mod(p); - - const e = new baseField(gx1.powermod(c2, p)).equals(new sjcl.bn(1)); // step 18 - const X = cmov(x2, x1, e, baseField); // step 19 - const gx = cmov(gx2, gx1, e, baseField); // step 20 - let y1 = gx.powermod(sqrt, p); // step 21 - // choose the positive (the smallest) root - const r = c2.greaterEquals(y1); - let y2 = y1.mul(-1).mod(p); - const Y = cmov(y2, y1, r, baseField); - return { X: X, Y: Y }; -} - -/** - * Return the parameters for the active curve - * @param {sjcl.ecc.curve} curve elliptic curve - * @return {p;A;B} - */ -function getCurveParams(curve) { - let curveParams; - switch (sjcl.ecc.curveName(curve)) { - case 'c256': - curveParams = precomputedP256; - break; - default: - throw new Error( - '[privacy-pass]: Incompatible curve chosen for H2C: ' + sjcl.ecc.curveName(curve), - ); - } - return curveParams; -} - -/** - * DEPRECATED: Method for hashing to curve based on the principal of attempting - * to hash the bytes multiple times and recover a curve point. Has non-negligble - * probailistic failure conditions. - * @param {sjcl.bitArray} seed - * @param {sjcl.hash} hash hash function for hashing bytes to base field - * @param {sjcl.bitArray} label - * @return {sjcl.ecc.point} returns a curve point on the active curve - */ -function hashAndInc(seed, hash, label) { - const h = new hash(); - - // Need to match the Go curve hash, so we decode the exact bytes of the - // string "1.2.840.100045.3.1.7 point generation seed" instead of relying - // on the utf8 codec that didn't match. - const separator = label; - - h.update(separator); - - let i = 0; - // Increased increments to decrease chance of failure - for (i = 0; i < 20; i++) { - // little endian uint32 - const ctr = new Uint8Array(4); - // typecast hack: number -> Uint32, bitwise Uint8 - ctr[0] = (i >>> 0) & 0xff; - const ctrBits = sjcl.codec.bytes.toBits(ctr); - - // H(s||ctr) - h.update(seed); - h.update(ctrBits); - - const digestBits = h.finalize(); - const bytes = sjcl.codec.bytes.fromBits(digestBits); - - // attempt to decompress a point with a valid tag (don't need to try - // 0x03 because this is just the negative version) - // curve choice is implicit based on active curve parameters - const point = sec1DecodeFromBytes([2].concat(bytes)); - if (point !== null) { - return point; - } - - seed = digestBits; - h.reset(); - } - - throw new Error('Unable to construct point using hash and increment'); -} - -/** - * Conditional move selects x or y depending on the bit input. - * @param {sjcl.bn} x is a big number - * @param {sjcl.bn} y is a big number - * @param {boolean} b is a bit - * @param {sjcl.bn} field is the prime field used. - * @return {sjcl.bn} returns x is b=0, otherwise return y. - */ -function cmov(x, y, b, field) { - let z = new field(); - const m = z.radixMask; - const m0 = m & (m + b); - const m1 = m & (m + !b); - x.fullReduce(); - y.fullReduce(); - for (let i = Math.max(x.limbs.length, y.limbs.length) - 1; i >= 0; i--) { - z.limbs.unshift((x.getLimb(i) & m0) ^ (y.getLimb(i) & m1)); - } - return z.mod(field.modulus); -} - -export function newBigNum(s) { - return new sjcl.bn(s); -} - -/** - * Derives the shared key used for redemption MACs - * @param {sjcl.ecc.point} N Signed curve point associated with token - * @param {Object} token client-generated token data - * @return {sjcl.codec.bytes} bytes of derived key - */ -export function deriveKey(N, token) { - // the exact bits of the string "hash_derive_key" - const tagBits = sjcl.codec.hex.toBits('686173685f6465726976655f6b6579'); - const hash = getActiveECSettings().hash; - const h = new sjcl.misc.hmac(tagBits, hash); - - // Always compute derived key using uncompressed point bytes - const encodedPoint = sec1Encode(N, false); - const tokenBits = sjcl.codec.bytes.toBits(token); - const pointBits = sjcl.codec.bytes.toBits(encodedPoint); - - h.update(tokenBits); - h.update(pointBits); - - const keyBytes = sjcl.codec.bytes.fromBits(h.digest()); - return keyBytes; -} - -export function getBytesFromString(str) { - const bits = sjcl.codec.utf8String.toBits(str); - const bytes = sjcl.codec.bytes.fromBits(bits); - return bytes; -} - -export function getBase64FromBytes(bytes) { - const bits = sjcl.codec.bytes.toBits(bytes); - const encoded = sjcl.codec.base64.fromBits(bits); - return encoded; -} - -export function getBase64FromString(str) { - const bits = sjcl.codec.utf8String.toBits(str); - const encoded = sjcl.codec.base64.fromBits(bits); - return encoded; -} - -export function createRequestBinding(key, data) { - // the exact bits of the string "hash_request_binding" - const tagBits = sjcl.codec.utf8String.toBits('hash_request_binding'); - const keyBits = sjcl.codec.bytes.toBits(key); - const hash = getActiveECSettings().hash; - - const h = new sjcl.misc.hmac(keyBits, hash); - h.update(tagBits); - - let dataBits = null; - for (let i = 0; i < data.length; i++) { - dataBits = sjcl.codec.bytes.toBits(data[i]); - h.update(dataBits); - } - - return sjcl.codec.base64.fromBits(h.digest()); -} diff --git a/src/background/voprf.test.ts b/src/background/voprf.test.ts deleted file mode 100644 index 2b9b8c5d..00000000 --- a/src/background/voprf.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defaultECSettings, initECSettings, newRandomPoint } from './voprf'; - -test('randomPoint', () => { - initECSettings(defaultECSettings); - const P = newRandomPoint(); - expect(P).toBeDefined(); -}); diff --git a/src/popup/components/App/index.tsx b/src/popup/components/App/index.tsx index 7be54fa7..b7955229 100644 --- a/src/popup/components/App/index.tsx +++ b/src/popup/components/App/index.tsx @@ -1,9 +1,11 @@ -import { Container } from '@popup/components/Container'; -import { ClearButton } from '@popup/components/ClearButton'; +import { Header } from '@popup/components/Header'; +import { Container } from '@popup/components/Container'; import { CloudflareButton } from '@popup/components/CloudflareButton'; -import { HcaptchaButton } from '@popup/components/HcaptchaButton'; -import { GithubButton } from '@popup/components/GithubButton'; -import { Header } from '@popup/components/Header'; +import { HcaptchaButton } from '@popup/components/HcaptchaButton'; +import { BackupButton } from '@popup/components/BackupButton'; +import { RestoreButton } from '@popup/components/RestoreButton'; +import { ClearButton } from '@popup/components/ClearButton'; +import { GithubButton } from '@popup/components/GithubButton'; import React from 'react'; import styles from './styles.module.scss'; @@ -14,6 +16,8 @@ export function App(): JSX.Element { + + diff --git a/src/popup/components/BackupButton/index.tsx b/src/popup/components/BackupButton/index.tsx new file mode 100644 index 00000000..69210635 --- /dev/null +++ b/src/popup/components/BackupButton/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { useDispatch } from 'react-redux'; + +import { Button } from '@popup/components/Button'; + +export function BackupButton(): JSX.Element { + const dispatch = useDispatch(); + + const backupPasses = () => { + dispatch({ type: 'BACKUP_TOKENS' }); + }; + return ; +} diff --git a/src/popup/components/ClearButton/index.tsx b/src/popup/components/ClearButton/index.tsx index d38d6e1c..286cf895 100644 --- a/src/popup/components/ClearButton/index.tsx +++ b/src/popup/components/ClearButton/index.tsx @@ -9,5 +9,5 @@ export function ClearButton(): JSX.Element { const clearPasses = () => { dispatch({ type: 'CLEAR_TOKENS' }); }; - return ; + return ; } diff --git a/src/popup/components/CloudflareButton/index.tsx b/src/popup/components/CloudflareButton/index.tsx index 8503dae8..090a2a04 100644 --- a/src/popup/components/CloudflareButton/index.tsx +++ b/src/popup/components/CloudflareButton/index.tsx @@ -3,12 +3,13 @@ import { useSelector } from 'react-redux'; import { PassButton } from '@popup/components/PassButton'; +const providerID: string = '1'; + export function CloudflareButton(): JSX.Element { - const tokens: string[] = useSelector((state: { ['cf-tokens']?: string[] } | undefined) => { - if (state !== undefined && state['cf-tokens'] !== undefined) { - return state['cf-tokens']; - } - return []; + const tokensCount: number = useSelector((state: {[key: string]: number} | void): number => { + return ((state instanceof Object) && (typeof state[providerID] === 'number')) + ? Number(state[providerID]) + : 0; }); const openHomePage = () => { @@ -16,8 +17,8 @@ export function CloudflareButton(): JSX.Element { }; return ( - - Cloudflare + + {chrome.i18n.getMessage('providerNameCloudflare')} ); } diff --git a/src/popup/components/GithubButton/index.tsx b/src/popup/components/GithubButton/index.tsx index 3d7d8160..614dbf03 100644 --- a/src/popup/components/GithubButton/index.tsx +++ b/src/popup/components/GithubButton/index.tsx @@ -7,5 +7,5 @@ export function GithubButton(): JSX.Element { chrome.tabs.create({ url: 'https://github.com/privacypass/challenge-bypass-extension' }); }; - return ; + return ; } diff --git a/src/popup/components/HcaptchaButton/index.tsx b/src/popup/components/HcaptchaButton/index.tsx index 4c752cc4..41b99b32 100644 --- a/src/popup/components/HcaptchaButton/index.tsx +++ b/src/popup/components/HcaptchaButton/index.tsx @@ -1,15 +1,24 @@ import React from 'react'; +import { useSelector } from 'react-redux'; import { PassButton } from '@popup/components/PassButton'; +const providerID: string = '2'; + export function HcaptchaButton(): JSX.Element { + const tokensCount: number = useSelector((state: {[key: string]: number} | void): number => { + return ((state instanceof Object) && (typeof state[providerID] === 'number')) + ? Number(state[providerID]) + : 0; + }); + const openHomePage = () => { chrome.tabs.create({ url: 'https://www.hcaptcha.com/privacy-pass' }); }; return ( - - hCaptcha + + {chrome.i18n.getMessage('providerNameHcaptcha')} ); } diff --git a/src/popup/components/Header/index.tsx b/src/popup/components/Header/index.tsx index 04dee52b..1107ebd9 100644 --- a/src/popup/components/Header/index.tsx +++ b/src/popup/components/Header/index.tsx @@ -8,8 +8,8 @@ export function Header(): JSX.Element {
-
Privacy Pass
-
Version {packageJson.version}
+
{chrome.i18n.getMessage('appName')}
+
{chrome.i18n.getMessage('labelAppVersion')} {packageJson.version}
); diff --git a/src/popup/components/PassButton/index.tsx b/src/popup/components/PassButton/index.tsx index e56d6b7a..6c64a83a 100644 --- a/src/popup/components/PassButton/index.tsx +++ b/src/popup/components/PassButton/index.tsx @@ -13,7 +13,7 @@ export function PassButton(props: Props): JSX.Element { setMouseover(false); } - const element = mouseover ? 'Get more passes!' : props.children; + const element = mouseover ? chrome.i18n.getMessage('ctaGetMorePasses') : props.children; return (
-
{element}
-
{props.value}
+ + + + + +
+ {element} + + {props.value} +
); } diff --git a/src/popup/components/PassButton/styles.module.scss b/src/popup/components/PassButton/styles.module.scss index 58a4f574..d14b6f26 100644 --- a/src/popup/components/PassButton/styles.module.scss +++ b/src/popup/components/PassButton/styles.module.scss @@ -12,10 +12,18 @@ $_font-weight: 200; font-weight: $_font-weight; } +.table { + width: 100%; + box-sizing: border-box; + border-collapse: collapse; +} + .content { - display: inline; + width: 100%; + text-align: left; + padding-right: 1em; } .value { - float: right; + text-align: right; } diff --git a/src/popup/components/RestoreButton/index.tsx b/src/popup/components/RestoreButton/index.tsx new file mode 100644 index 00000000..3b3cf99b --- /dev/null +++ b/src/popup/components/RestoreButton/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { useDispatch } from 'react-redux'; + +import { Button } from '@popup/components/Button'; + +export function RestoreButton(): JSX.Element { + const dispatch = useDispatch(); + + const restorePasses = () => { + dispatch({ type: 'RESTORE_TOKENS' }); + }; + return ; +} diff --git a/src/popup/index.tsx b/src/popup/index.tsx index d79df56b..6d7dd4e7 100644 --- a/src/popup/index.tsx +++ b/src/popup/index.tsx @@ -13,14 +13,4 @@ ReactDOM.render( document.getElementById('root'), ); -// TODO Using Message passing is dirty. It's better to use chrome.storage for sharing -// common data between the popup and the background script. -chrome.runtime.sendMessage({ key: 'cf-tokens' }, (response) => { - if (response !== undefined && typeof response === 'string') { - store.dispatch({ - type: 'UPDATE_STATE', - key: 'cf-tokens', - value: response, - }); - } -}); +store.dispatch({ type: 'OBTAIN_STATE' }); diff --git a/src/popup/store.ts b/src/popup/store.ts index 3a495131..ff20828d 100644 --- a/src/popup/store.ts +++ b/src/popup/store.ts @@ -1,29 +1,83 @@ import { createStore } from 'redux'; +interface ObtainStateAction { + type: 'OBTAIN_STATE'; +} + interface UpdateStateAction { type: 'UPDATE_STATE'; - key: string; - value: string; + value: {[key: string]: number}; +} + +interface BackupTokensAction { + type: 'BACKUP_TOKENS'; +} + +interface RestoreTokensAction { + type: 'RESTORE_TOKENS'; } interface ClearTokensAction { type: 'CLEAR_TOKENS'; } -type Action = UpdateStateAction | ClearTokensAction; +type Action = ObtainStateAction | UpdateStateAction | BackupTokensAction | RestoreTokensAction | ClearTokensAction; const reducer = (state: any | undefined, action: Action) => { + state = (state instanceof Object) ? state : {}; + switch (action.type) { + case 'OBTAIN_STATE': + chrome.runtime.sendMessage({ tokensCount: true }, (response: any) => { + if ((response !== undefined) && (response !== null) && (response instanceof Object)) { + store.dispatch({ + type: 'UPDATE_STATE', + value: response + }); + } + }); + return state; case 'UPDATE_STATE': return { ...state, - [action.key]: JSON.parse(action.value), + ...action.value, }; + case 'BACKUP_TOKENS': + chrome.runtime.sendMessage({ backup: true }, (response: any) => { + if ((response !== undefined) && (response !== null) && (response instanceof Object)) { + try { + // open save-as dialog + + let url: string; + if (window.Blob === undefined || window.URL === undefined) { + url = JSON.stringify(response, null, 2); + url = btoa(url); + url = `data:application/json;base64,${url}`; + } + else { + const blob = new window.Blob([JSON.stringify(response, null, 2)], {type : 'application/json'}); + url = window.URL.createObjectURL(blob); + } + + const anchor = window.document.createElement('a'); + const timestamp = (new Date()).toISOString().replace(/\.\d+Z$/, '').replace('T', '-T').replace(/[:]/g, '-'); + const filename = (`${chrome.i18n.getMessage('appName')}-${chrome.i18n.getMessage('labelFileBackup')}.${timestamp}.json`).replace(/(?:[\/\\\<\>\|\?\*:"]|[\s\r\n])+/g, ''); + anchor.setAttribute('href', url); + anchor.setAttribute('download', filename); + anchor.click(); + } + catch(e) {} + } + }); + return state; + case 'RESTORE_TOKENS': + chrome.runtime.sendMessage({ restore: true, tab: { open: true } }); + return state; case 'CLEAR_TOKENS': - // TODO Using Message passing is dirty. It's better to use chrome.storage for sharing - // common data between the popup and the background script. chrome.runtime.sendMessage({ clear: true }); return {}; + default: + return state; } }; diff --git a/src/popup/tsconfig.json b/src/popup/tsconfig.json index 745230a4..0adc9e48 100644 --- a/src/popup/tsconfig.json +++ b/src/popup/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "jsx": "react", "baseUrl": ".", "paths": { "@root/*": [ diff --git a/src/restore/index.ts b/src/restore/index.ts new file mode 100644 index 00000000..840113a0 --- /dev/null +++ b/src/restore/index.ts @@ -0,0 +1,78 @@ +function handleBackupFileImport(event: Event): void { + event.stopPropagation(); + event.stopImmediatePropagation(); + + const input: HTMLInputElement = event.target; + const files: FileList | null = input.files; + if (files === null) return; + + let remaining_files = files.length; + + const onFileReadComplete = () => { + remaining_files--; + + if (remaining_files <= 0) { + chrome.runtime.sendMessage({ restore: true, tab: { close: true } }); + } + } + + for (let file_index=0; file_index < files.length; file_index++) { + const reader = new FileReader(); + + reader.onload = function(){ + try { + if ((typeof reader.result === 'string') && (reader.result.length > 0)) { + const backupJSON: string = reader.result; + const backup: {[key: string]: string[]} = JSON.parse(backupJSON); + + chrome.runtime.sendMessage({ restore: true, backup }); + } + } + catch(e) {} + onFileReadComplete(); + }; + + reader.onerror = onFileReadComplete; + reader.onabort = onFileReadComplete; + + reader.readAsText( + files[file_index] + ); + } +} + + +window.addEventListener('DOMContentLoaded', (event) => { + event.stopPropagation(); + event.stopImmediatePropagation(); + + const appName = chrome.i18n.getMessage('appName'); + const ctaRestorePasses = chrome.i18n.getMessage('ctaRestorePasses'); + + window.document.title = appName + ': ' + ctaRestorePasses; + + const input = window.document.createElement('input'); + input.setAttribute('type', 'file'); + input.setAttribute('accept', 'text/plain, application/json, .txt, .json'); + input.setAttribute('multiple', ''); + input.addEventListener('change', handleBackupFileImport); + + const root = window.document.getElementById('root'); + if (root !== null) { + const heading = window.document.createElement('h2'); + heading.appendChild( + window.document.createTextNode(appName) + ); + + const subheading = window.document.createElement('h3'); + subheading.appendChild( + window.document.createTextNode(ctaRestorePasses) + ); + + root.appendChild(heading); + root.appendChild(subheading); + root.appendChild(input); + } + + input.click(); +}); diff --git a/src/restore/tsconfig.json b/src/restore/tsconfig.json new file mode 100644 index 00000000..f7ea8933 --- /dev/null +++ b/src/restore/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "isolatedModules": false + }, + "extends": "../../tsconfig.json", + "include": [ + "." + ] +} diff --git a/tsconfig.json b/tsconfig.json index 209346bc..bac37265 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,8 @@ { "compilerOptions": { - "target": "es2020", - "module": "es2020", + "module": "ESNext", + "target": "ES5", + "downlevelIteration": true, "declaration": true, "declarationMap": true, "sourceMap": true, @@ -9,20 +10,23 @@ "incremental": true, "removeComments": true, "isolatedModules": true, - "strict": true, - "strictNullChecks": true, + "allowJs": true, + "checkJs": false, + "jsx": "react", + "outDir": "lib", + "rootDir": "./", "noEmitOnError": true, + "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "moduleResolution": "node", + "allowSyntheticDefaultImports": true, "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "allowSyntheticDefaultImports": true, - "rootDir": ".", - "outDir": "lib" + "declarationDir": "lib" }, "files": [], "include": [], @@ -32,6 +36,9 @@ }, { "path": "./src/popup" + }, + { + "path": "./src/restore" } ] } diff --git a/webpack.config.js b/webpack.config.js index 14422530..f1b0dcd4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,17 +1,16 @@ +import webpack from 'webpack'; import CopyWebpackPlugin from 'copy-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; import path from 'path'; +import { fileURLToPath } from 'url'; -// import buffer from "buffer"; -// import streamBrowserify from "stream-browserify"; - -const __dirname = path.dirname(new URL(import.meta.url).pathname); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); const tsloader = { - test: /\.tsx?$/, - exclude: /node_modules/, + test: /\.[jt]sx?$/, + exclude: /node_modules(?![\/\\](?:buffer|keccak))/, loader: 'ts-loader', options: { projectReferences: true, @@ -20,12 +19,13 @@ const tsloader = { const common = { output: { - path: path.resolve('dist'), + path: path.resolve('dist/PrivacyPass'), }, context: __dirname, mode: 'production', + target: ['web', 'es5'], optimization: { - minimize: false, + minimize: (process.env.NODE_ENV === 'production'), }, }; @@ -34,17 +34,23 @@ const background = { entry: { background: path.resolve('src/background/index.ts'), }, - externals: { crypto: 'null' }, + externals: { + crypto: 'null', + }, module: { rules: [tsloader], }, resolve: { extensions: ['.tsx', '.ts', '.js'], fallback: { - // 'buffer': buffer, - // 'stream': streamBrowserify, + buffer: 'buffer/', }, }, + plugins: [ + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + }), + ], }; const popup = { @@ -73,7 +79,7 @@ const popup = { }, plugins: [ new CopyWebpackPlugin({ - patterns: [{ from: 'public/icons', to: 'icons' }, { from: 'public/manifest.json' }], + patterns: [{ from: 'public/_locales', to: '_locales' }, { from: 'public/icons', to: 'icons' }, { from: 'public/manifest.json' }], }), new HtmlWebpackPlugin({ chunks: ['popup'], @@ -84,5 +90,25 @@ const popup = { ], }; +const restore = { + ...common, + entry: { + restore: path.resolve('src/restore/index.ts'), + }, + module: { + rules: [tsloader], + }, + resolve: { + extensions: ['.ts', '.js'], + }, + plugins: [ + new HtmlWebpackPlugin({ + chunks: ['restore'], + filename: 'restore.html', + template: 'public/restore.html', + }), + ], +}; + // Mutiple targets for webpack: https://webpack.js.org/concepts/targets/#multiple-targets -export default [background, popup]; +export default [background, popup, restore];