diff --git a/.env.example b/.env.example index 73eab092..3fdfdd86 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,11 @@ DATABASE_NAME=staging DATABASE_URL=mysql://username:password@hostname:port/database TWILIO_ACCOUNT_SID=ACCOUNT_ID TWILIO_AUTH_TOKEN=ACCOUNT_TOKEN -TWILIO_SERVICE_SID=XXX +TWILIO_SERVICE_SID=VAXXX +TWILIO_RATE_LIMIT_SID=RKxxx +TWILIO_RATE_LIMIT_BUCKET_SID=BLxxx +TWILIO_RATE_LIMIT_BUCKET_MAX=4 +TWILIO_RATE_LIMIT_BUCKET_INTERVAL=60 RECAPTCHA_SITE_KEY=RECAPTCHA_KEY RECAPTCHA_SECRET=RECAPTCHA_SECRET CONVEYOR_POSTING_WIF=CONVEYOR_KEY diff --git a/helpers/services.js b/helpers/services.js index 09b428b5..a84d289b 100644 --- a/helpers/services.js +++ b/helpers/services.js @@ -65,12 +65,13 @@ async function sendSMS(to, body) { /** * Send a SMS Code. * @param to Message recipient, e.g. +1234567890. + * @param client_ip the client ip, e.g. 1.1.1.1 */ -async function sendSMSCode(to) { +async function sendSMSCode(to, client_ip) { if (DEBUG_MODE) { - logger.warn('Send SMS to %s', to); + logger.warn('Send SMS to %s, client_ip: %s', to, client_ip); } else { - return twilio.sendAuthCode(to); + return twilio.sendAuthCode(to, client_ip); } } @@ -571,6 +572,30 @@ async function getPendingClaimedAccountsAsync() { }); } +async function createTwilioRateLimit() { + if (DEBUG_MODE) { + twilio = require('./twilio'); + return twilio.createTwilioRateLimit(); + } + return {}; +} + +async function createTwilioRateLimitBucket() { + if (DEBUG_MODE) { + twilio = require('./twilio'); + return twilio.createTwilioRateLimitBucket(); + } + return {}; +} + +async function updateTwilioRateLimitBucket() { + if (DEBUG_MODE) { + twilio = require('./twilio'); + return twilio.updateTwilioRateLimitBucket(); + } + return {}; +} + module.exports = { checkUsername, condenserTransfer, @@ -596,4 +621,7 @@ module.exports = { recordSmsTracker, recordSource, getPendingClaimedAccountsAsync, + createTwilioRateLimit, + createTwilioRateLimitBucket, + updateTwilioRateLimitBucket, }; diff --git a/helpers/twilio.js b/helpers/twilio.js index dc68b15e..d3f807a6 100644 --- a/helpers/twilio.js +++ b/helpers/twilio.js @@ -4,6 +4,10 @@ const accountSid = process.env.TWILIO_ACCOUNT_SID; const authToken = process.env.TWILIO_AUTH_TOKEN; const fromNumber = process.env.TWILIO_PHONE_NUMBER; const serviceSid = process.env.TWILIO_SERVICE_SID; +const rateLimitSid = process.env.TWILIO_RATE_LIMIT_SID; +const rateLimitBucketSid = process.env.TWILIO_RATE_LIMIT_BUCKET_SID; +const rateLimitBucketMax = process.env.TWILIO_RATE_LIMIT_BUCKET_MAX; +const rateLimitBucketInterval = process.env.TWILIO_RATE_LIMIT_BUCKET_INTERVAL; const authCodeServiceSid = process.env.TWILIO_AUTH_CODE_SERVICE_SID; if (!accountSid || !authToken) { @@ -16,6 +20,10 @@ if (!fromNumber && !serviceSid && !authCodeServiceSid) { ); } +if (!rateLimitSid) { + throw new Error('Misconfiguration: Missing twilio rate limit config'); +} + const client = new Twilio(accountSid, authToken); async function sendMessage(to, body) { @@ -28,20 +36,49 @@ async function sendMessage(to, body) { return client.messages.create(payload); } -async function sendAuthCode(to) { - return client.verify - .services(authCodeServiceSid) - .verifications.create({ to, channel: 'sms' }); +async function sendAuthCode(to, client_ip) { + return client.verify.v2.services(authCodeServiceSid).verifications.create({ + to, + channel: 'sms', + rateLimits: { + end_user_ip_address: client_ip, + }, + }); } async function checkAuthCode(to, code) { - return client.verify + return client.verify.v2 .services(authCodeServiceSid) .verificationChecks.create({ to, code }); } async function isValidNumber(numberE164) { - return client.lookups.v1.phoneNumbers(numberE164).fetch(); + return client.lookups.v2.phoneNumbers(numberE164).fetch(); +} + +async function createTwilioRateLimit() { + return client.verify.v2.services(authCodeServiceSid).rateLimits.create({ + description: 'Limit on end user IP Address', + uniqueName: 'end_user_ip_address', + }); +} + +async function createTwilioRateLimitBucket() { + return client.verify.v2 + .services(authCodeServiceSid) + .rateLimits(rateLimitSid) + .buckets.create({ + max: rateLimitBucketMax, + interval: rateLimitBucketInterval, + }); +} + +async function updateTwilioRateLimitBucket() { + return client.verify.v2 + .services(authCodeServiceSid) + .rateLimits(rateLimitSid) + .buckets(rateLimitBucketSid) + .update({ max: rateLimitBucketMax, interval: rateLimitBucketInterval }); } module.exports = { @@ -49,4 +86,7 @@ module.exports = { sendAuthCode, checkAuthCode, isValidNumber, + createTwilioRateLimit, + createTwilioRateLimitBucket, + updateTwilioRateLimitBucket, }; diff --git a/package.json b/package.json index 69e121a4..172f028d 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "sequelize": "5.2.4", "serve-favicon": "2.4.5", "tronweb": "^3.0.0", - "twilio": "^3.64.0", + "twilio": "^5.2.0", "validator": "9.2.0" }, "devDependencies": { diff --git a/routes/api.js b/routes/api.js index d539fbe8..209de90f 100644 --- a/routes/api.js +++ b/routes/api.js @@ -121,4 +121,19 @@ router.get( apiMiddleware(apiHandlers.handleCreateTronAddr) ); +router.get( + '/create_twilio_rate_limit', + apiMiddleware(apiHandlers.handleCreateTwilioRateLimit) +); + +router.get( + '/create_twilio_rate_limit_bucket', + apiMiddleware(apiHandlers.handleCreateTwilioRateLimitBucket) +); + +router.get( + '/update_twilio_rate_limit_bucket', + apiMiddleware(apiHandlers.handleUpdateTwilioRateLimitBucket) +); + module.exports = router; diff --git a/routes/apiHandlers.js b/routes/apiHandlers.js index 2046a5e4..33468140 100644 --- a/routes/apiHandlers.js +++ b/routes/apiHandlers.js @@ -1396,7 +1396,7 @@ async function handleRequestSmsNew(req) { }); req.log.info( { response, ip: req.ip, req: req.body }, - 'sms_response_info_in_country_code_list' + 'sms_message_send_in_country_code_list' ); if (response && response.status !== 'pending') { throw new ApiError({ @@ -1406,7 +1406,7 @@ async function handleRequestSmsNew(req) { }); } } else { - const response = await services.sendSMSCode(phoneNumber); + const response = await services.sendSMSCode(phoneNumber, req.ip); services.recordSmsTracker({ sendType: 'after_send_sms_2', countryCode: req.body.prefix, @@ -1414,7 +1414,7 @@ async function handleRequestSmsNew(req) { }); req.log.info( { response, ip: req.ip, req: req.body }, - 'sms_response_info' + 'sms_verify_sent' ); if (response && response.status !== 'pending') { throw new ApiError({ @@ -1600,6 +1600,10 @@ async function handleConfirmSmsNew(req) { req.body.phoneNumber, req.body.code ); + req.log.info( + { response, ip: req.ip, req: req.body }, + 'sms_verify_apply' + ); if (response === true) { record.phone_code = req.body.code; record.save(); @@ -2099,6 +2103,24 @@ async function handleCreateTronAddr() { return tronUser; } +async function handleCreateTwilioRateLimit() { + if (process.env.DEBUG_MODE) { + return services.createTwilioRateLimit(); + } +} + +async function handleCreateTwilioRateLimitBucket() { + if (process.env.DEBUG_MODE) { + return services.createTwilioRateLimitBucket(); + } +} + +async function handleUpdateTwilioRateLimitBucket() { + if (process.env.DEBUG_MODE) { + return services.updateTwilioRateLimitBucket(); + } +} + module.exports = { handleRequestEmail, handleRequestSms, @@ -2116,4 +2138,7 @@ module.exports = { handleConfirmEmailCode, handleCreateAccountNew, handleCreateTronAddr, + handleCreateTwilioRateLimit, + handleCreateTwilioRateLimitBucket, + handleUpdateTwilioRateLimitBucket, }; diff --git a/yarn.lock b/yarn.lock index db5da004..88ed7d0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -497,7 +497,7 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@^2.0.0, asap@~2.0.3: +asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -647,12 +647,14 @@ axios@^0.20.0: dependencies: follow-redirects "^1.10.0" -axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== +axios@^1.6.8: + version "1.7.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" + integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" axobject-query@^0.1.0: version "0.1.0" @@ -2387,7 +2389,7 @@ colors@~1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -2889,10 +2891,10 @@ date-fns@^1.27.2: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== -dayjs@^1.8.29: - version "1.10.5" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986" - integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g== +dayjs@^1.11.9: + version "1.11.11" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" + integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" @@ -4275,6 +4277,11 @@ follow-redirects@^1.10.0: resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.0.tgz?cache=0&sync_timestamp=1597057997789&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha1-tC6Nk6Kn7qXtiGM2dtZZe8jjhNs= +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -4306,6 +4313,15 @@ form-data@^2.5.0: combined-stream "^1.0.6" mime-types "^2.1.12" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -6125,10 +6141,10 @@ jsonwebtoken@8.1.1: ms "^2.1.1" xtend "^4.0.1" -jsonwebtoken@^8.5.1: - version "8.5.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" - integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== dependencies: jws "^3.2.2" lodash.includes "^4.3.0" @@ -6139,7 +6155,7 @@ jsonwebtoken@^8.5.1: lodash.isstring "^4.0.1" lodash.once "^4.0.0" ms "^2.1.1" - semver "^5.6.0" + semver "^7.5.4" jspdf@^2.1.0: version "2.1.0" @@ -6629,11 +6645,6 @@ lodash@^4.1.0, lodash@^4.13.1, lodash@^4.16.4, lodash@^4.16.5, lodash@^4.17.11, resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - log-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" @@ -7713,11 +7724,6 @@ pn@^1.1.0: resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== -pop-iterate@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pop-iterate/-/pop-iterate-1.0.1.tgz#ceacfdab4abf353d7a0f2aaa2c1fc7b3f9413ba3" - integrity sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M= - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -8135,6 +8141,11 @@ proxy-addr@~2.0.2, proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -8184,15 +8195,6 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -q@2.0.x: - version "2.0.3" - resolved "https://registry.yarnpkg.com/q/-/q-2.0.3.tgz#75b8db0255a1a5af82f58c3f3aaa1efec7d0d134" - integrity sha1-dbjbAlWhpa+C9Yw/Oqoe/sfQ0TQ= - dependencies: - asap "^2.0.0" - pop-iterate "^1.0.1" - weak-map "^1.0.5" - q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -9367,11 +9369,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rootpath@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/rootpath/-/rootpath-0.1.2.tgz#5b379a87dca906e9b91d690a599439bef267ea6b" - integrity sha1-Wzeah9ypBum5HWkKWZQ5vvJn6ms= - rsvp@^3.3.3: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" @@ -9493,6 +9490,11 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -10477,21 +10479,17 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -twilio@^3.64.0: - version "3.64.0" - resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.64.0.tgz#93c5b338ef24669c3db918ee59e89f6971ef853a" - integrity sha512-pTTjj0HH3EiN0+nF1VeGIgw85tm6u+WA7yHBaBRxXN7QaBWNMyA+ozA0H9+YVgE1oin7ZdJz8WDshnQ6aYYfGg== +twilio@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/twilio/-/twilio-5.2.0.tgz#756f3699101e4b04aa0c3008feb98e7821aac469" + integrity sha512-v58OiasUj9ckZpdkLAJWZ6KJIjM7GM57onM93xxqq7YVJRgLG0jS0nZY3X+Lm6dF2f653BUkTn6R6kmky7pLYw== dependencies: - axios "^0.21.1" - dayjs "^1.8.29" + axios "^1.6.8" + dayjs "^1.11.9" https-proxy-agent "^5.0.0" - jsonwebtoken "^8.5.1" - lodash "^4.17.21" - q "2.0.x" + jsonwebtoken "^9.0.2" qs "^6.9.4" - rootpath "^0.1.2" scmp "^2.1.0" - url-parse "^1.5.0" xmlbuilder "^13.0.2" type-check@~0.3.2: @@ -10708,14 +10706,6 @@ url-parse@^1.4.3: querystringify "^2.1.1" requires-port "^1.0.0" -url-parse@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -10881,11 +10871,6 @@ watchpack@^1.4.0: chokidar "^3.4.0" watchpack-chokidar2 "^2.0.0" -weak-map@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.5.tgz#79691584d98607f5070bd3b70a40e6bb22e401eb" - integrity sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes= - webidl-conversions@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-2.0.1.tgz#3bf8258f7d318c7443c36f2e169402a1a6703506"