diff --git a/package-lock.json b/package-lock.json index f17615e944..0dc4c1a57e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -558,7 +558,7 @@ }, "@types/firebase-token-generator": { "version": "2.0.28", - "resolved": "http://registry.npmjs.org/@types/firebase-token-generator/-/firebase-token-generator-2.0.28.tgz", + "resolved": "https://registry.npmjs.org/@types/firebase-token-generator/-/firebase-token-generator-2.0.28.tgz", "integrity": "sha1-Z1VIHZMk4mt6XItFXWgUg3aCw5Y=", "dev": true }, @@ -878,6 +878,17 @@ "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "append-buffer": { @@ -1284,7 +1295,7 @@ }, "binaryextensions": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz", "integrity": "sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U=", "dev": true }, @@ -1563,12 +1574,6 @@ } } } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true } } }, @@ -2317,9 +2322,9 @@ } }, "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -2327,8 +2332,9 @@ "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", "object-keys": "^1.1.1", "object.assign": "^4.1.0", "string.prototype.trimend": "^1.0.1", @@ -2541,9 +2547,9 @@ } }, "strip-json-comments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", - "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { @@ -2558,12 +2564,12 @@ } }, "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, @@ -2609,20 +2615,28 @@ }, "dependencies": { "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { @@ -2712,9 +2726,9 @@ }, "dependencies": { "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==", "dev": true } } @@ -2990,7 +3004,7 @@ }, "firebase-token-generator": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/firebase-token-generator/-/firebase-token-generator-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/firebase-token-generator/-/firebase-token-generator-2.0.0.tgz", "integrity": "sha1-l2fXWewTq9yZuhFf1eqZ2Lk9EgY=", "dev": true }, @@ -3117,18 +3131,6 @@ "requires": { "graceful-fs": "^4.1.11", "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } } }, "fs.realpath": { @@ -3176,9 +3178,9 @@ } }, "gaxios": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.3.tgz", - "integrity": "sha512-PkzQludeIFhd535/yucALT/Wxyj/y2zLyrMwPcJmnLHDugmV49NvAi/vb+VUq/eWztATZCNcb8ue+ywPG+oLuw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -3189,13 +3191,13 @@ } }, "gcp-metadata": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", - "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", "optional": true, "requires": { "gaxios": "^3.0.0", - "json-bigint": "^0.3.0" + "json-bigint": "^1.0.0" } }, "gcs-resumable-upload": { @@ -3330,9 +3332,9 @@ } }, "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -3340,6 +3342,7 @@ "chokidar": "^2.0.0", "is-negated-glob": "^1.0.0", "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", "object.defaults": "^1.1.0" } }, @@ -3408,9 +3411,9 @@ } }, "google-auth-library": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.3.tgz", - "integrity": "sha512-2Np6ojPmaJGXHSMsBhtTQEKfSMdLc8hefoihv7N2cwEr8E5bq39fhoat6TcXHwa0XoGO5Guh9sp3nxHFPmibMw==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -3421,13 +3424,13 @@ "gcp-metadata": "^4.1.0", "gtoken": "^5.0.0", "jws": "^4.0.0", - "lru-cache": "^5.0.0" + "lru-cache": "^6.0.0" } }, "google-gax": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.6.2.tgz", - "integrity": "sha512-Q5IydUQ+7sF072E72Cl1KDxHaQIa1a5CVqG80OHk3NXdT5ZvKAveBFp/f78E3HjVHGTgUDB16R4M2wDt0ia9mQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.8.0.tgz", + "integrity": "sha512-MPaADY/FHittX5xfOUU2EVqIoE850e+OZ1ys8aO2GnUMaP4U0Bde2wop6kw5sp4fIOjKNlan4GATKAURsYbxSw==", "optional": true, "requires": { "@grpc/grpc-js": "~1.1.1", @@ -3447,18 +3450,18 @@ } }, "google-p12-pem": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.1.tgz", - "integrity": "sha512-VlQgtozgNVVVcYTXS36eQz4PXPt9gIPqLOhHN0QiV6W6h4qSCNVKPtKC5INtJsaHHF2r7+nOIa26MJeJMTaZEQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "optional": true, "requires": { - "node-forge": "^0.9.0" + "node-forge": "^0.10.0" }, "dependencies": { "node-forge": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz", - "integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", "optional": true } } @@ -3475,9 +3478,9 @@ "dev": true }, "gtoken": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.1.tgz", - "integrity": "sha512-33w4FNDkUcyIOq/TqyC+drnKdI4PdXmWp9lZzssyEQKuvu9ZFN3KttaSnDKo52U3E51oujVGop93mKxmqO8HHg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -3579,18 +3582,6 @@ "concat-with-sourcemaps": "*", "lodash.template": "^4.4.0", "through2": "^2.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } } }, "gulp-replace": { @@ -3629,6 +3620,16 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } } } }, @@ -3709,16 +3710,6 @@ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", "dev": true }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "vinyl": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", @@ -3769,12 +3760,12 @@ "dev": true }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "dev": true, "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, @@ -3885,9 +3876,9 @@ "dev": true }, "highlight.js": { - "version": "9.18.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", - "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", + "version": "9.18.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz", + "integrity": "sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ==", "dev": true }, "homedir-polyfill": { @@ -4051,9 +4042,9 @@ "dev": true }, "inquirer": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.0.tgz", - "integrity": "sha512-K+LZp6L/6eE5swqIcVXrxl21aGDU4S50gKH0/d96OMQnSBCyGyZl/oZhbkVmdp5sBoINHd4xZvFSARh2dk6DWA==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -4062,7 +4053,7 @@ "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", - "lodash": "^4.17.15", + "lodash": "^4.17.19", "mute-stream": "0.0.8", "run-async": "^2.4.0", "rxjs": "^6.6.0", @@ -4145,9 +4136,9 @@ } }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -4231,9 +4222,9 @@ "dev": true }, "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", "dev": true }, "is-data-descriptor": { @@ -4317,6 +4308,12 @@ "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", "dev": true }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -4377,9 +4374,9 @@ } }, "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", "dev": true, "requires": { "has-symbols": "^1.0.1" @@ -4598,7 +4595,7 @@ }, "istextorbinary": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz", "integrity": "sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=", "dev": true, "requires": { @@ -4675,9 +4672,9 @@ "dev": true }, "json-bigint": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.1.tgz", - "integrity": "sha512-DGWnSzmusIreWlEupsUelHrhwmPPE+FiQvg+drKfk2p+bdEYa5mp4PJ8JsCWqae0M2jQNb0HPvnwvf1qOTThzQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "optional": true, "requires": { "bignumber.js": "^9.0.0" @@ -4784,9 +4781,9 @@ "dev": true }, "just-extend": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", - "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", "dev": true }, "jwa": { @@ -4911,9 +4908,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, "lodash._basecopy": { @@ -5105,18 +5102,18 @@ "optional": true }, "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "optional": true, "requires": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" } }, "lunr": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", - "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==", + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, "make-dir": { @@ -5290,6 +5287,14 @@ "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } } }, "minizlib": { @@ -5470,9 +5475,9 @@ } }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", "dev": true, "optional": true }, @@ -5502,9 +5507,9 @@ "dev": true }, "needle": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz", - "integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", + "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==", "dev": true, "requires": { "debug": "^3.2.6", @@ -5674,13 +5679,10 @@ } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "now-and-later": { "version": "2.0.1", @@ -5903,7 +5905,7 @@ }, "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "resolved": false, "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { @@ -6007,6 +6009,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "object-keys": { @@ -6025,15 +6048,15 @@ } }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "object.defaults": { @@ -6086,9 +6109,9 @@ } }, "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "requires": { "mimic-fn": "^2.1.0" } @@ -6263,7 +6286,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -6419,7 +6442,7 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, @@ -6447,9 +6470,9 @@ "dev": true }, "protobufjs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.9.0.tgz", - "integrity": "sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.2", @@ -6468,9 +6491,9 @@ }, "dependencies": { "@types/node": { - "version": "13.13.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.13.tgz", - "integrity": "sha512-UfvBE9oRCAJVzfR+3eWm/sdLFe/qroAPEXP3GPJ1SehQiEVgZT6NQZWYbPMiJ3UdcKM06v4j+S1lTcdWCmw+3g==", + "version": "13.13.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.19.tgz", + "integrity": "sha512-IVsULCpTdafcHhBDLYEPnV5l15xV0q065zvOHC1ZmzFYaBCMzku078eXnazoSG8907vZjRgEN/EQjku7GwwFyQ==", "optional": true } } @@ -6637,6 +6660,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "regexpp": { @@ -6673,18 +6717,6 @@ "remove-bom-buffer": "^3.0.0", "safe-buffer": "^5.1.0", "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } } }, "remove-trailing-separator": { @@ -6791,13 +6823,13 @@ } }, "request-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", - "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", "dev": true, "requires": { "bluebird": "^3.5.0", - "request-promise-core": "1.1.3", + "request-promise-core": "1.1.4", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" }, @@ -6815,21 +6847,21 @@ } }, "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", "dev": true, "requires": { - "lodash": "^4.17.15" + "lodash": "^4.17.19" } }, "request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", "dev": true, "requires": { - "request-promise-core": "1.1.3", + "request-promise-core": "1.1.4", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" }, @@ -6915,13 +6947,12 @@ "dev": true }, "retry-request": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", - "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.3.tgz", + "integrity": "sha512-QnRZUpuPNgX0+D1xVxul6DbJ9slvo4Rm6iV/dn63e048MvGbUZiKySVt6Tenp04JqmchxjiLltGerOJys7kJYQ==", "optional": true, "requires": { - "debug": "^4.1.1", - "through2": "^3.0.1" + "debug": "^4.1.1" } }, "rimraf": { @@ -6950,9 +6981,9 @@ } }, "rxjs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", - "integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -6965,7 +6996,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -7074,20 +7105,31 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "sinon": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", - "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.3.tgz", + "integrity": "sha512-IKo9MIM111+smz9JGwLmw5U1075n1YXeAq8YeSFlndCLhAL5KGn6bLgu7b/4AYHTV/LcEMcRm2wU2YiL55/6Pg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.2", "@sinonjs/fake-timers": "^6.0.1", "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.0.3", + "@sinonjs/samsam": "^5.1.0", "diff": "^4.0.2", - "nise": "^4.0.1", + "nise": "^4.0.4", "supports-color": "^7.1.0" }, "dependencies": { + "@sinonjs/samsam": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.1.0.tgz", + "integrity": "sha512-42nyaQOVunX5Pm6GRJobmzbS7iLI+fhERITnETXzzwDZh+TtDr/Au3yAvXVjFmZ4wEUaE4Y3NFZfKv0bV0cbtg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -7101,9 +7143,9 @@ "dev": true }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -7496,6 +7538,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "string.prototype.trimend": { @@ -7506,6 +7569,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "string.prototype.trimstart": { @@ -7516,6 +7600,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "string_decoder": { @@ -7650,6 +7755,14 @@ "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", "yallist": "^3.0.3" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } } }, "teeny-request": { @@ -7766,7 +7879,7 @@ }, "textextensions": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz", "integrity": "sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=", "dev": true }, @@ -7795,12 +7908,13 @@ "dev": true }, "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, "through2-filter": { @@ -7811,18 +7925,6 @@ "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } } }, "time-stamp": { @@ -7905,18 +8007,6 @@ "dev": true, "requires": { "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } } }, "tough-cookie": { @@ -8122,15 +8212,15 @@ } }, "typescript": { - "version": "3.9.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz", - "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", "dev": true }, "uglify-js": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", - "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.4.tgz", + "integrity": "sha512-kBFT3U4Dcj4/pJ52vfjCSfyLyvG9VYYuGYPmrPvAxRw/i7xHiT4VvCev+uiEMcEEiu6UNB6KgWmGtSUYIWScbw==", "dev": true, "optional": true }, @@ -8141,15 +8231,15 @@ "dev": true }, "underscore": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", - "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz", + "integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==", "dev": true }, "undertaker": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", "dev": true, "requires": { "arr-flatten": "^1.0.1", @@ -8157,10 +8247,19 @@ "bach": "^1.0.0", "collection-map": "^1.0.0", "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", "last-run": "^1.1.0", "object.defaults": "^1.0.0", "object.reduce": "^1.0.0", "undertaker-registry": "^1.0.0" + }, + "dependencies": { + "fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "dev": true + } } }, "undertaker-registry": { @@ -8253,9 +8352,9 @@ "dev": true }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -8385,16 +8484,6 @@ "inherits": "^2.0.3", "pump": "^2.0.0" } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } } } }, @@ -8411,6 +8500,17 @@ "now-and-later": "^2.0.0", "remove-bom-buffer": "^3.0.0", "vinyl": "^2.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "w3c-hr-time": { @@ -8601,9 +8701,10 @@ "dev": true }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true }, "yargs": { "version": "13.3.2", diff --git a/src/auth.d.ts b/src/auth.d.ts index 312f2c49f7..1735034baa 100644 --- a/src/auth.d.ts +++ b/src/auth.d.ts @@ -570,9 +570,11 @@ export namespace admin.auth { pageToken?: string; } + type HashInputOrderType = 'SALT_FIRST' | 'PASSWORD_FIRST'; + type HashAlgorithmType = 'SCRYPT' | 'STANDARD_SCRYPT' | 'HMAC_SHA512' | - 'HMAC_SHA256' | 'HMAC_SHA1' | 'HMAC_MD5' | 'MD5' | 'PBKDF_SHA1' | 'BCRYPT' | - 'PBKDF2_SHA256' | 'SHA512' | 'SHA256' | 'SHA1'; + 'HMAC_SHA256' | 'HMAC_SHA1' | 'HMAC_MD5' | 'MD5' | 'PBKDF_SHA1' | 'BCRYPT' | + 'PBKDF2_SHA256' | 'SHA512' | 'SHA256' | 'SHA1'; /** * Interface representing the user import options needed for @@ -632,11 +634,21 @@ export namespace admin.auth { * `STANDARD_SCRYPT` algorithm. */ blockSize?: number; + /** * The derived key length of the hashing algorithm. Required for the * `STANDARD_SCRYPT` algorithm. */ derivedKeyLength?: number; + + /** + * The hash input order for certain hashing algorithms. The following + * orders are supported: + * 'SALT_FIRST', 'PASSWORD_FIRST'. + * Optional for `HMAC_SHA512`, `HMAC_SHA256`, `HMAC_SHA1`, + * `HMAC_MD5`, `SHA512`, `SHA256` and `SHA1`. + */ + inputOrder?: HashInputOrderType; }; } diff --git a/src/auth/user-import-builder.ts b/src/auth/user-import-builder.ts index 1f1b784a03..ea39776ad0 100644 --- a/src/auth/user-import-builder.ts +++ b/src/auth/user-import-builder.ts @@ -20,6 +20,12 @@ import * as validator from '../utils/validator'; import { AuthClientErrorCode, FirebaseAuthError, FirebaseArrayIndexError } from '../utils/error'; /** Firebase Auth supported hashing algorithms for import operations. */ +/** Client side values for password hash order types. **/ +export type HashInputOrderType = 'SALT_FIRST' | 'PASSWORD_FIRST'; + +/** Server side values for password hash order types. **/ +export type PasswordHashOrderType = 'SALT_AND_PASSWORD' | 'PASSWORD_AND_SALT'; + export type HashAlgorithmType = 'SCRYPT' | 'STANDARD_SCRYPT' | 'HMAC_SHA512' | 'HMAC_SHA256' | 'HMAC_SHA1' | 'HMAC_MD5' | 'MD5' | 'PBKDF_SHA1' | 'BCRYPT' | 'PBKDF2_SHA256' | 'SHA512' | 'SHA256' | 'SHA1'; @@ -36,6 +42,7 @@ export interface UserImportOptions { parallelization?: number; blockSize?: number; derivedKeyLength?: number; + inputOrder?: HashInputOrderType; }; } @@ -129,6 +136,7 @@ export interface UploadAccountOptions { parallelization?: number; blockSize?: number; dkLen?: number; + passwordHashOrder?: PasswordHashOrderType; } @@ -370,6 +378,26 @@ export class UserImportBuilder { return importResult; } + /** + * Checks whether hash input order is supported by the provided hashing algorithm. + * @param hashAlgorithmType Hash algorithm type. + * @return Whether hash input order is supported. + */ + private hashInputOrderSupported(hashAlgorithmType: HashAlgorithmType): boolean { + switch (hashAlgorithmType) { + case 'HMAC_SHA512': + case 'HMAC_SHA256': + case 'HMAC_SHA1': + case 'HMAC_MD5': + case 'SHA512': + case 'SHA256': + case 'SHA1': + return true; + default: + return false; + } + } + /** * Validates and returns the hashing options of the uploadAccount request. * Throws an error whenever an invalid or missing options is detected. @@ -404,6 +432,7 @@ export class UserImportBuilder { } let rounds: number; + let minRounds: number; switch (options.hash.algorithm) { case 'HMAC_SHA512': case 'HMAC_SHA256': @@ -423,12 +452,33 @@ export class UserImportBuilder { break; case 'MD5': + // MD5 is [0,8192] + rounds = getNumberField(options.hash, 'rounds'); + minRounds = 0; + if (isNaN(rounds) || rounds < 0 || rounds > 8192) { + throw new FirebaseAuthError( + AuthClientErrorCode.INVALID_HASH_ROUNDS, + `A valid "hash.rounds" number between ${minRounds} and 8192 must be provided for ` + + `hash algorithm ${options.hash.algorithm}.`, + ); + } + if (options.hash.inputOrder) { + throw new FirebaseAuthError( + AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${options.hash.algorithm} algorithm does not support specifying hash input order.`, + ); + } + populatedOptions = { + hashAlgorithm: options.hash.algorithm, + rounds, + }; + break; case 'SHA1': case 'SHA256': case 'SHA512': { - // MD5 is [0,8192] but SHA1, SHA256, and SHA512 are [1,8192] + // SHA1, SHA256, and SHA512 are [1,8192] rounds = getNumberField(options.hash, 'rounds'); - const minRounds = options.hash.algorithm === 'MD5' ? 0 : 1; + minRounds = 1; if (isNaN(rounds) || rounds < minRounds || rounds > 8192) { throw new FirebaseAuthError( AuthClientErrorCode.INVALID_HASH_ROUNDS, @@ -452,6 +502,12 @@ export class UserImportBuilder { `hash algorithm ${options.hash.algorithm}.`, ); } + if (options.hash.inputOrder) { + throw new FirebaseAuthError( + AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${options.hash.algorithm} algorithm does not support specifying hash input order.`, + ); + } populatedOptions = { hashAlgorithm: options.hash.algorithm, rounds, @@ -489,6 +545,12 @@ export class UserImportBuilder { `"hash.saltSeparator" must be a byte buffer.`, ); } + if (options.hash.inputOrder) { + throw new FirebaseAuthError( + AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${options.hash.algorithm} algorithm does not support specifying hash input order.`, + ); + } populatedOptions = { hashAlgorithm: options.hash.algorithm, signerKey: utils.toWebSafeBase64(options.hash.key), @@ -499,6 +561,12 @@ export class UserImportBuilder { break; } case 'BCRYPT': + if (options.hash.inputOrder) { + throw new FirebaseAuthError( + AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${options.hash.algorithm} algorithm does not support specifying hash input order.`, + ); + } populatedOptions = { hashAlgorithm: options.hash.algorithm, }; @@ -537,6 +605,12 @@ export class UserImportBuilder { `hash algorithm ${options.hash.algorithm}.`, ); } + if (options.hash.inputOrder) { + throw new FirebaseAuthError( + AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${options.hash.algorithm} algorithm does not support specifying hash input order.`, + ); + } populatedOptions = { hashAlgorithm: options.hash.algorithm, cpuMemCost, @@ -552,9 +626,40 @@ export class UserImportBuilder { `Unsupported hash algorithm provider "${options.hash.algorithm}".`, ); } + + if (this.hashInputOrderSupported(options.hash.algorithm)) { + populatedOptions = this.populateInputOrderOption(populatedOptions, options.hash.inputOrder); + } + return populatedOptions; } + /** + * Adds a new hash order field to the populated account options, if provided. + * @param {UploadAccountOptions} populatedOptions The already populated account options. + * @param {HashInputOrderType=} inputOrder The optional hash input order. + * @return {UploadAccountOptions} A copy of populated options with a new field if the provided + * input order was provided. + */ + private populateInputOrderOption( + populatedOptions: UploadAccountOptions, + inputOrder?: HashInputOrderType, + ): UploadAccountOptions { + const populatedOptionsCopy = { ...populatedOptions }; + + if (typeof inputOrder !== 'undefined') { + if (inputOrder !== 'SALT_FIRST' && inputOrder !== 'PASSWORD_FIRST') { + throw new FirebaseAuthError(AuthClientErrorCode.INVALID_HASH_INPUT_ORDER); + } + + populatedOptionsCopy.passwordHashOrder = + inputOrder === 'SALT_FIRST' ? 'SALT_AND_PASSWORD' : 'PASSWORD_AND_SALT'; + } + + return populatedOptionsCopy; + } + + /** * Validates and returns the users list of the uploadAccount request. * Whenever a user with an error is detected, the error is cached and will later be diff --git a/src/index.d.ts b/src/index.d.ts index 997fcb8779..7950ff1ca1 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -562,6 +562,7 @@ declare namespace admin.auth { export import CreateRequest = _auth.admin.auth.CreateRequest; export import DecodedIdToken = _auth.admin.auth.DecodedIdToken; export import ListUsersResult = _auth.admin.auth.ListUsersResult; + export import HashInputOrderType = _auth.admin.auth.HashInputOrderType; export import HashAlgorithmType = _auth.admin.auth.HashAlgorithmType; export import UserImportOptions = _auth.admin.auth.UserImportOptions; export import UserImportResult = _auth.admin.auth.UserImportResult; diff --git a/src/utils/error.ts b/src/utils/error.ts index a894accc76..cd8dea53c4 100644 --- a/src/utils/error.ts +++ b/src/utils/error.ts @@ -373,6 +373,10 @@ export class AuthClientErrorCode { code: 'invalid-config', message: 'The provided configuration is invalid.', }; + public static INVALID_HASH_INPUT_ORDER = { + code: 'invalid-hash-input-order', + message: 'The hash input order must be either "SALT_FIRST" or "PASSWORD_FIRST".', + }; public static EMAIL_ALREADY_EXISTS = { code: 'email-already-exists', message: 'The email address is already in use by another account.', @@ -670,6 +674,10 @@ export class AuthClientErrorCode { message: 'The domain of the continue URL is not whitelisted. Whitelist the domain in the ' + 'Firebase console.', }; + public static UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER = { + code: 'unsupported_algorithm_for_hash_input_order', + message: 'The algorithm does not support specifying hash input order.', + }; public static UNSUPPORTED_FIRST_FACTOR = { code: 'unsupported-first-factor', message: 'A multi-factor user requires a supported first factor.', @@ -867,6 +875,8 @@ const AUTH_SERVER_TO_CLIENT_CODE: ServerToClientCode = { INVALID_EMAIL: 'INVALID_EMAIL', // Invalid tenant display name. This can be thrown on CreateTenant and UpdateTenant. INVALID_DISPLAY_NAME: 'INVALID_DISPLAY_NAME', + // Invalid hash input order name. + INVALID_HASH_INPUT_ORDER: 'INVALID_HASH_INPUT_ORDER', // Invalid ID token provided. INVALID_ID_TOKEN: 'INVALID_ID_TOKEN', // Invalid tenant/parent resource name. @@ -932,6 +942,8 @@ const AUTH_SERVER_TO_CLIENT_CODE: ServerToClientCode = { TOKEN_EXPIRED: 'ID_TOKEN_EXPIRED', // Continue URL provided in ActionCodeSettings has a domain that is not whitelisted. UNAUTHORIZED_DOMAIN: 'UNAUTHORIZED_DOMAIN', + // Algorithms do not support hash input order. + UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER: 'UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER', // A multi-factor user requires a supported first factor. UNSUPPORTED_FIRST_FACTOR: 'UNSUPPORTED_FIRST_FACTOR', // The request specified an unsupported type of second factor. diff --git a/test/integration/auth.spec.ts b/test/integration/auth.spec.ts index 805e0393cf..82d0b93685 100644 --- a/test/integration/auth.spec.ts +++ b/test/integration/auth.spec.ts @@ -1688,12 +1688,57 @@ describe('admin.auth', () => { }); const fixtures: UserImportTest[] = [ + { + name: 'HMAC_MD5', + importOptions: { + hash: { + algorithm: 'HMAC_MD5', + key: Buffer.from('secret'), + inputOrder: 'SALT_FIRST', + }, + } as any, + computePasswordHash: (userImportTest: UserImportTest): Buffer => { + expect(userImportTest.importOptions.hash.key).to.exist; + const currentHashKey = userImportTest.importOptions.hash.key!.toString('utf8'); + const currentRawPassword = userImportTest.rawPassword; + const currentRawSalt = userImportTest.rawSalt; + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHmac('md5', currentHashKey).update(stringToHash).digest(); + }, + rawPassword, + rawSalt, + }, + { + name: 'HMAC_SHA1', + importOptions: { + hash: { + algorithm: 'HMAC_SHA1', + key: Buffer.from('secret'), + inputOrder: 'SALT_FIRST', + }, + } as any, + computePasswordHash: (userImportTest: UserImportTest): Buffer => { + expect(userImportTest.importOptions.hash.key).to.exist; + const currentHashKey = userImportTest.importOptions.hash.key!.toString('utf8'); + const currentRawPassword = userImportTest.rawPassword; + const currentRawSalt = userImportTest.rawSalt; + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHmac('sha1', currentHashKey).update(stringToHash).digest(); + }, + rawPassword, + rawSalt, + }, { name: 'HMAC_SHA256', importOptions: { hash: { algorithm: 'HMAC_SHA256', key: Buffer.from('secret'), + inputOrder: 'SALT_FIRST', }, } as any, computePasswordHash: (userImportTest: UserImportTest): Buffer => { @@ -1701,24 +1746,32 @@ describe('admin.auth', () => { const currentHashKey = userImportTest.importOptions.hash.key!.toString('utf8'); const currentRawPassword = userImportTest.rawPassword; const currentRawSalt = userImportTest.rawSalt; - return crypto.createHmac('sha256', currentHashKey) - .update(currentRawPassword + currentRawSalt).digest(); + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHmac('sha256', currentHashKey).update(stringToHash).digest(); }, rawPassword, rawSalt, }, { - name: 'SHA256', + name: 'HMAC_SHA512', importOptions: { hash: { - algorithm: 'SHA256', - rounds: 1, + algorithm: 'HMAC_SHA512', + key: Buffer.from('secret'), + inputOrder: 'SALT_FIRST', }, } as any, computePasswordHash: (userImportTest: UserImportTest): Buffer => { + expect(userImportTest.importOptions.hash.key).to.exist; + const currentHashKey = userImportTest.importOptions.hash.key!.toString('utf8'); const currentRawPassword = userImportTest.rawPassword; const currentRawSalt = userImportTest.rawSalt; - return crypto.createHash('sha256').update(currentRawSalt + currentRawPassword).digest(); + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHmac('sha512', currentHashKey).update(stringToHash).digest(); }, rawPassword, rawSalt, @@ -1740,6 +1793,66 @@ describe('admin.auth', () => { rawPassword, rawSalt, }, + { + name: 'SHA1', + importOptions: { + hash: { + algorithm: 'SHA1', + rounds: 1, + inputOrder: 'SALT_FIRST', + }, + } as any, + computePasswordHash: (userImportTest: UserImportTest): Buffer => { + const currentRawPassword = userImportTest.rawPassword; + const currentRawSalt = userImportTest.rawSalt; + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHash('sha1').update(stringToHash).digest(); + }, + rawPassword, + rawSalt, + }, + { + name: 'SHA256', + importOptions: { + hash: { + algorithm: 'SHA256', + rounds: 1, + inputOrder: 'SALT_FIRST', + }, + } as any, + computePasswordHash: (userImportTest: UserImportTest): Buffer => { + const currentRawPassword = userImportTest.rawPassword; + const currentRawSalt = userImportTest.rawSalt; + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHash('sha256').update(stringToHash).digest(); + }, + rawPassword, + rawSalt, + }, + { + name: 'SHA512', + importOptions: { + hash: { + algorithm: 'SHA512', + rounds: 1, + inputOrder: 'SALT_FIRST', + }, + } as any, + computePasswordHash: (userImportTest: UserImportTest): Buffer => { + const currentRawPassword = userImportTest.rawPassword; + const currentRawSalt = userImportTest.rawSalt; + const stringToHash = + userImportTest.importOptions.hash.inputOrder === 'SALT_FIRST' ? + currentRawSalt + currentRawPassword : currentRawPassword + currentRawSalt; + return crypto.createHash('sha512').update(stringToHash).digest(); + }, + rawPassword, + rawSalt, + }, { name: 'BCRYPT', importOptions: { @@ -1825,20 +1938,59 @@ describe('admin.auth', () => { ]; fixtures.forEach((fixture) => { - it(`successfully imports users with ${fixture.name} to Firebase Auth.`, () => { - importUserRecord = { - uid: randomUid, - email: randomUid + '@example.com', - }; - importUserRecord.passwordHash = fixture.computePasswordHash(fixture); - if (typeof fixture.rawSalt !== 'undefined') { - importUserRecord.passwordSalt = Buffer.from(fixture.rawSalt); - } - return testImportAndSignInUser( - importUserRecord, fixture.importOptions, fixture.rawPassword) - .should.eventually.be.fulfilled; + if (fixture.importOptions && fixture.importOptions.hash && fixture.importOptions.hash.inputOrder) { + it(`successfully imports users with ${fixture.name} to Firebase Auth w/ explicit salt-first hash.`, () => { + importUserRecord = { + uid: randomUid, + email: randomUid + '@example.com', + }; + importUserRecord.passwordHash = fixture.computePasswordHash!(fixture); + if (typeof fixture.rawSalt !== 'undefined') { + importUserRecord.passwordSalt = Buffer.from(fixture.rawSalt); + } + const importOptions = { + ...fixture.importOptions, + }; + importOptions.hash.inputOrder = 'SALT_FIRST'; + return testImportAndSignInUser( + importUserRecord, importOptions, fixture.rawPassword) + .should.eventually.be.fulfilled; + }); - }); + it(`successfully imports users with ${fixture.name} to Firebase Auth w/ explicit password-first hash.`, () => { + importUserRecord = { + uid: randomUid, + email: randomUid + '@example.com', + }; + // Update input order in import options. + fixture.importOptions.hash.inputOrder = 'PASSWORD_FIRST'; + importUserRecord.passwordHash = fixture.computePasswordHash!(fixture); + if (typeof fixture.rawSalt !== 'undefined') { + importUserRecord.passwordSalt = Buffer.from(fixture.rawSalt); + } + const importOptions = { + ...fixture.importOptions, + }; + importOptions.hash.inputOrder = 'PASSWORD_FIRST'; + return testImportAndSignInUser( + importUserRecord, importOptions, fixture.rawPassword) + .should.eventually.be.fulfilled; + }); + } else { + it(`successfully imports users with ${fixture.name} to Firebase Auth.`, () => { + importUserRecord = { + uid: randomUid, + email: randomUid + '@example.com', + }; + importUserRecord.passwordHash = fixture.computePasswordHash(fixture); + if (typeof fixture.rawSalt !== 'undefined') { + importUserRecord.passwordSalt = Buffer.from(fixture.rawSalt); + } + return testImportAndSignInUser( + importUserRecord, fixture.importOptions, fixture.rawPassword) + .should.eventually.be.fulfilled; + }); + } }); it('successfully imports users with multiple OAuth providers', () => { diff --git a/test/unit/auth/user-import-builder.spec.ts b/test/unit/auth/user-import-builder.spec.ts index ab1eab477e..62d984b4a8 100644 --- a/test/unit/auth/user-import-builder.spec.ts +++ b/test/unit/auth/user-import-builder.spec.ts @@ -167,9 +167,7 @@ describe('UserImportBuilder', () => { ]; const hmacAlgorithms = ['HMAC_SHA512', 'HMAC_SHA256', 'HMAC_SHA1', 'HMAC_MD5']; - const md5ShaPbkdfAlgorithms = [ - 'MD5', 'SHA1', 'SHA256', 'SHA512', 'PBKDF_SHA1', 'PBKDF2_SHA256', - ]; + const md5ShaPbkdfAlgorithms = ['MD5', 'SHA1', 'SHA256', 'SHA512', 'PBKDF_SHA1', 'PBKDF2_SHA256']; describe('constructor', () => { const invalidUserImportOptions = [10, 'invalid', undefined, null, true, ['a']]; invalidUserImportOptions.forEach((invalidOption) => { @@ -241,15 +239,50 @@ describe('UserImportBuilder', () => { }); }); - it('should not throw with valid options and should generate expected request', () => { + it('should throw when an invalid hash input order option is provided', () => { + const expectedError = new FirebaseAuthError(AuthClientErrorCode.INVALID_HASH_INPUT_ORDER); + const invalidOptions = { + hash: { + algorithm, + inputOrder: 'INVALID_HASH_INPUT_ORDER', + key: Buffer.from('secret'), + }, + }; + expect(() => { + return new UserImportBuilder(users, invalidOptions as any, userRequestValidator); + }).to.throw(expectedError.message); + }); + + it('should not throw with valid PASSWORD_FIRST options and should generate expected request', () => { + const validOptions = { + hash: { + algorithm, + inputOrder: 'PASSWORD_FIRST', + key: Buffer.from('secret'), + }, + }; + const expectedRequest = { + hashAlgorithm: algorithm, + passwordHashOrder: 'PASSWORD_AND_SALT', + signerKey: toWebSafeBase64(Buffer.from('secret')), + users: expectedUsersRequest, + }; + const userImportBuilder = + new UserImportBuilder(users, validOptions as any, userRequestValidator); + expect(userImportBuilder.buildRequest()).to.deep.equal(expectedRequest); + }); + + it('should not throw with valid SALT_FIRST options and should generate expected request', () => { const validOptions = { hash: { algorithm, + inputOrder: "SALT_FIRST", key: Buffer.from('secret'), }, }; const expectedRequest = { hashAlgorithm: algorithm, + passwordHashOrder: 'SALT_AND_PASSWORD', signerKey: toWebSafeBase64(Buffer.from('secret')), users: expectedUsersRequest, }; @@ -257,6 +290,7 @@ describe('UserImportBuilder', () => { new UserImportBuilder(users, validOptions as any, userRequestValidator); expect(userImportBuilder.buildRequest()).to.deep.equal(expectedRequest); }); + }); }); @@ -303,24 +337,77 @@ describe('UserImportBuilder', () => { }).to.throw(expectedError.message); }); }); + + // Algorithms 'PBKDF_SHA1', 'PBKDF2_SHA256', and 'MD5' don't supported hash input order. + if (algorithm !== 'PBKDF_SHA1' && algorithm !== 'PBKDF2_SHA256' && algorithm !== 'MD5') { + it('should throw when invalid hash input order options is provided', () => { + const expectedError = new FirebaseAuthError(AuthClientErrorCode.INVALID_HASH_INPUT_ORDER); + const invalidOptions = { + hash: { + algorithm, + inputOrder: 'INVALID_HASH_INPUT_ORDER', + rounds: maxRounds, + }, + }; + expect(() => { + return new UserImportBuilder(users, invalidOptions as any, userRequestValidator); + }).to.throw(expectedError.message); + }); - it('should not throw with valid options and should generate expected request', () => { - const validOptions = { - hash: { - algorithm, + it('should not throw with valid SALT_FIRST options and should generate expected request', () => { + const validOptions = { + hash: { + algorithm, + inputOrder: 'SALT_FIRST', + rounds: maxRounds, + }, + }; + const expectedRequest = { + hashAlgorithm: algorithm, + passwordHashOrder: 'SALT_AND_PASSWORD', rounds: maxRounds, - }, - }; - const expectedRequest = { - hashAlgorithm: algorithm, - rounds: maxRounds, - users: expectedUsersRequest, - }; - const userImportBuilder = - new UserImportBuilder(users, validOptions as any, userRequestValidator); - expect(userImportBuilder.buildRequest()).to.deep.equal(expectedRequest); - }); + users: expectedUsersRequest, + }; + const userImportBuilder = + new UserImportBuilder(users, validOptions as any, userRequestValidator); + expect(userImportBuilder.buildRequest()).to.deep.equal(expectedRequest); + }); + it('should not throw with valid PASSWORD_FIRST options and should generate expected request', () => { + const validOptions = { + hash: { + algorithm, + inputOrder: 'PASSWORD_FIRST', + rounds: maxRounds, + }, + }; + const expectedRequest = { + hashAlgorithm: algorithm, + passwordHashOrder: 'PASSWORD_AND_SALT', + rounds: maxRounds, + users: expectedUsersRequest, + }; + const userImportBuilder = + new UserImportBuilder(users, validOptions as any, userRequestValidator); + expect(userImportBuilder.buildRequest()).to.deep.equal(expectedRequest); + }); + } else { + it('should throw when algorithms do not support specifying hash input order', () => { + const expectedError = new FirebaseAuthError(AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${algorithm} algorithm does not support specifying hash input order.`, + ); + const invalidOptions = { + hash: { + algorithm, + inputOrder: 'SALT_FIRST', + rounds: maxRounds, + }, + }; + expect(() => { + return new UserImportBuilder(users, invalidOptions as any, userRequestValidator); + }).to.throw(expectedError.message); + }); + } }); }); @@ -414,6 +501,24 @@ describe('UserImportBuilder', () => { }); }); + it('should throw because ‘SCRYPT’ do not support specifying hash input order', () => { + const expectedError = new FirebaseAuthError(AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${algorithm} algorithm does not support specifying hash input order.`, + ); + const invalidOptions = { + hash: { + algorithm, + key: Buffer.from('secret'), + rounds: 4, + memoryCost: 12, + inputOrder: 'SALT_FIRST', + }, + }; + expect(() => { + return new UserImportBuilder(users, invalidOptions as any, userRequestValidator); + }).to.throw(expectedError.message); + }); + it('should not throw with valid options and should generate expected request', () => { const validOptions = { hash: { @@ -439,6 +544,21 @@ describe('UserImportBuilder', () => { describe('BCRYPT', () => { const algorithm = 'BCRYPT'; + it('should throw because ‘BCRYPT’ do not support specifying hash input order', () => { + const expectedError = new FirebaseAuthError(AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${algorithm} algorithm does not support specifying hash input order.`, + ); + const invalidOptions = { + hash: { + algorithm, + inputOrder: 'SALT_FIRST', + }, + }; + expect(() => { + return new UserImportBuilder(users, invalidOptions as any, userRequestValidator); + }).to.throw(expectedError.message); + }); + it('should not throw with valid options and should generate expected request', () => { const validOptions = { hash: { @@ -549,6 +669,25 @@ describe('UserImportBuilder', () => { }); }); + it('should throw because ‘STANDARD_SCRYPT’ do not support specifying hash input order', () => { + const expectedError = new FirebaseAuthError(AuthClientErrorCode.UNSUPPORTED_ALGORITHM_FOR_HASH_INPUT_ORDER, + `The ${algorithm} algorithm does not support specifying hash input order.`, + ); + const invalidOptions = { + hash: { + algorithm, + memoryCost : 1024, + parallelization: 16, + blockSize: 8, + derivedKeyLength: 64, + inputOrder: 'SALT_FIRST', + }, + }; + expect(() => { + return new UserImportBuilder(users, invalidOptions as any, userRequestValidator); + }).to.throw(expectedError.message); + }); + it('should not throw with valid options and should generate expected request', () => { const validOptions = { hash: {