diff --git a/hydro/entry/common.js b/hydro/entry/common.js index f452b9b9c..7a15e6fde 100644 --- a/hydro/entry/common.js +++ b/hydro/entry/common.js @@ -5,7 +5,7 @@ const fs = require('fs'); const yaml = require('js-yaml'); const builtinLib = [ - 'axios', 'download', 'i18n', 'mail', 'markdown', + 'jwt', 'download', 'i18n', 'mail', 'markdown', 'md5', 'misc', 'paginate', 'hash.hydro', 'rank', 'template', 'validator', 'nav', 'sysinfo', 'testdata.convert.ini', 'readConfig', 'logger', 'useragent', diff --git a/hydro/handler/user.js b/hydro/handler/user.js index fadfb5d09..24ea3862a 100644 --- a/hydro/handler/user.js +++ b/hydro/handler/user.js @@ -1,4 +1,4 @@ -const axios = require('axios'); +const superagent = require('superagent'); const { Route, Handler } = require('../service/server.js'); const user = require('../model/user'); const token = require('../model/token'); @@ -162,67 +162,127 @@ class UserSearchHandler extends Handler { } class OauthHandler extends Handler { + async github() { + const [appid, [state]] = await Promise.all([ + system.get('oauth.githubappid'), + token.add(token.TYPE_OAUTH, 600, { redirect: this.request.referer }), + ]); + this.response.redirect = `https://github.com/login/oauth/authorize?client_id=${appid}&state=${state}`; + } + + async google() { + const [appid, url, [state]] = await Promise.all([ + system.get('oauth.googleappid'), + system.get('server.url'), + token.add(token.TYPE_OAUTH, 600, { redirect: this.request.referer }), + ]); + this.response.redirect = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${appid}&response_type=code&redirect_uri=${url}oauth/google/callback&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile&state=${state}`; + } + async get({ type }) { - if (type === 'github') { - const [appid, [state]] = await Promise.all([ - system.get('oauth.githubappid'), - token.add(token.TYPE_OAUTH, 600, { redirect: this.request.referer }), - ]); - this.response.redirect = `https://github.com/login/oauth/authorize?client_id=${appid}&state=${state}`; - } + if (type === 'github') await this.github(); + else if (type === 'google') await this.google(); } } class OauthCallbackHandler extends Handler { - async get({ type, state, code }) { - if (type === 'github') { - const [appid, secret, url, s] = await Promise.all([ - system.get('oauth.githubappid'), - system.get('oauth.githubsecret'), - system.get('server.url'), - token.get(state, token.TYPE_OAUTH), - ]); - const res = await axios.post('https://github.com/login/oauth/access_token', { + async github({ state, code }) { + const [appid, secret, url, s] = await Promise.all([ + system.get('oauth.githubappid'), + system.get('oauth.githubsecret'), + system.get('server.url'), + token.get(state, token.TYPE_OAUTH), + ]); + const res = await superagent.post('https://github.com/login/oauth/access_token') + .send({ client_id: appid, client_secret: secret, code, redirect_uri: `${url}oauth/github/callback`, state, - }, { headers: { accept: 'application/json' } }); - if (res.data.error) { - throw new UserFacingError( - res.data.error, res.data.error_description, res.data.error_uri, - ); - } - const t = res.data.access_token; - const userInfo = await axios.get('https://api.github.com/user', { - headers: { - Authorization: `token ${t}`, - }, + }) + .set('accept', 'application/json'); + if (res.body.error) { + throw new UserFacingError( + res.body.error, res.body.error_description, res.body.error_uri, + ); + } + const t = res.body.access_token; + const userInfo = await superagent.get('https://api.github.com/user') + .set('Authorization', `token ${t}`); + const ret = { + email: userInfo.body.mail, + bio: userInfo.body.bio, + uname: [userInfo.body.name, userInfo.body.login], + }; + this.response.redirect = s.redirect; + await token.del(s, token.TYPE_OAUTH); + return ret; + } + + async google({ + code, scope, authuser, prompt, error, state, + }) { + if (error) throw new UserFacingError(error); + console.log(scope, authuser, prompt); + const [ + [appid, secret, url, proxy], + s, + ] = await Promise.all([ + system.getMany([ + 'oauth.googleappid', 'oauth.googlesecret', 'server.url', 'proxy', + ]), + token.get(state, token.TYPE_OAUTH), + ]); + const res = await superagent.post('https://oauth2.googleapis.com/token') + .proxy(proxy) + .send({ + client_id: appid, + client_secret: secret, + code, + grant_type: 'authorization_code', + redirect_uri: `${url}oauth/google/callback`, }); - const { - email: mail, bio, name, login, - } = userInfo.data; - const udoc = await user.getByEmail('system', mail, true); - if (udoc) { - this.session.uid = udoc._id; - await token.del(s, token.TYPE_OAUTH); - } else { - let uname; - const nudoc = await user.getByUname('system', name, true); - if (!nudoc) uname = name; - else { - const ludoc = await user.getByUname('system', login, true); - if (!ludoc) uname = login; - else uname = String.random(16); + const payload = global.Hydro.lib.jwt.decode(res.body.id_token); + await token.del(state, token.TYPE_OAUTH); + this.response.redirect = s.redirect; + return { + email: payload.email, + uname: [payload.given_name, payload.name, payload.family_name], + viewLang: payload.locale.replace('-', '_'), + }; + } + + async get(args) { + let r; + if (args.type === 'github') r = await this.github(args); + else if (args.type === 'google') r = await this.google(args); + else throw new UserFacingError('Oauth type'); + const udoc = await user.getByEmail('system', r.email, true); + if (udoc) { + this.session.uid = udoc._id; + } else { + let username = ''; + r.uname = r.uname || []; + r.uname.push(String.random(16)); + for (const uname of r.uname) { + // eslint-disable-next-line no-await-in-loop + const nudoc = await user.getByUname('system', uname, true); + if (!nudoc) { + username = uname; + break; } - const uid = await user.create({ - mail, uname, password: String.random(32), regip: this.request.ip, - }); - await user.setById(uid, { bio, oauth: 'github' }); - this.session.uid = uid; } - this.response.redirect = s.redirect; + const uid = await user.create({ + mail: r.email, uname: username, password: String.random(32), regip: this.request.ip, + }); + const $set = { + oauth: args.type, + }; + if (r.bio) $set.bio = r.bio; + if (r.viewLang) $set.viewLang = r.viewLang; + await user.setById(uid, $set); + this.session.uid = uid; } } } diff --git a/hydro/lib/axios.js b/hydro/lib/axios.js deleted file mode 100644 index c3c65b353..000000000 --- a/hydro/lib/axios.js +++ /dev/null @@ -1,23 +0,0 @@ -const axios = require('axios'); - -async function get(url, options) { - let res; - try { - res = await axios.get(url, options); - } catch (e) { - res = e; - } - return res; -} - -async function post(url, data, options) { - let res; - try { - res = await axios.post(url, data, options); - } catch (e) { - res = e; - } - return res; -} - -global.Hydro.lib.axios = module.exports = { get, post }; diff --git a/hydro/lib/download.js b/hydro/lib/download.js index 033ec1b3c..cffb5d43e 100644 --- a/hydro/lib/download.js +++ b/hydro/lib/download.js @@ -1,23 +1,17 @@ -const axios = require('axios'); +const superagent = require('superagent'); const fs = require('fs'); async function download(url, path, retry = 3) { - let r; - try { - const res = await axios.get(url, { responseType: 'stream' }); - if (path) { - const w = await fs.createWriteStream(path); - res.data.pipe(w); - await new Promise((resolve, reject) => { - w.on('finish', resolve); - w.on('error', reject); - }); - } else r = res.data; - } catch (e) { - if (retry) r = await download(url, path, retry - 1); - else throw e; + if (path) { + const w = await fs.createWriteStream(path); + await superagent.get(url).retry(retry).pipe(w); + await new Promise((resolve, reject) => { + w.on('finish', resolve); + w.on('error', reject); + }); + return path; } - return r; + return superagent.get(url); } global.Hydro.lib.download = module.exports = download; diff --git a/hydro/lib/jwt.js b/hydro/lib/jwt.js new file mode 100644 index 000000000..609c7f851 --- /dev/null +++ b/hydro/lib/jwt.js @@ -0,0 +1,35 @@ +function decodeBase64WithUriEncoding(encodedText) { + return Buffer.from(encodedText, 'base64').toString('utf8'); +} + +function unescapedString(escapedString) { + escapedString += new Array(5 - escapedString.length % 4).join('='); + return escapedString.replace(/\-/g, '+').replace(/_/g, '/'); +} + +function decodeJWT(idToken) { + const token = idToken.split('.'); + if (token.length !== 3) { + throw new Error('Invalid idToken'); + } + try { + const headerSegment = JSON.parse(decodeBase64WithUriEncoding(token[0])); + const payloadSegment = JSON.parse(decodeBase64WithUriEncoding(token[1])); + const signature = unescapedString(token[2]); + return { + dataToSign: [token[0], token[1]].join('.'), + header: headerSegment, + payload: payloadSegment, + signature, + }; + } catch (e) { + throw new Error('Invalid payload'); + } +} + +function decode(idToken) { + const decodedJWT = decodeJWT(idToken); + return decodedJWT.payload; +} + +global.Hydro.lib.jwt = module.exports = { decode }; diff --git a/hydro/loader.js b/hydro/loader.js index 1ecb220cb..a026bd9e0 100644 --- a/hydro/loader.js +++ b/hydro/loader.js @@ -75,8 +75,8 @@ async function messageHandler(worker, msg) { async function load() { global.nodeModules = { 'adm-zip': require('adm-zip'), - axios: require('axios'), bson: require('bson'), + superagent: require('superagent'), 'js-yaml': require('js-yaml'), mongodb: require('mongodb'), }; diff --git a/hydro/model/setting.js b/hydro/model/setting.js index bacbec2d8..bc3d8d32e 100644 --- a/hydro/model/setting.js +++ b/hydro/model/setting.js @@ -104,6 +104,9 @@ SystemSetting( Setting('setting_server', 'server.port', null, 8888, 'number', 'Server Port'), Setting('setting_oauth', 'oauth.githubappid', null, null, 'text', 'Github Oauth AppID'), Setting('setting_oauth', 'oauth.githubsecret', null, null, 'text', 'Github Oauth Secret'), + Setting('setting_oauth', 'oauth.googleappid', null, null, 'text', 'Google Oauth ClientID'), + Setting('setting_oauth', 'oauth.googlesecret', null, null, 'text', 'Google Oauth Secret'), + Setting('setting_proxy', 'proxy', null, null, 'text', 'Proxy Server URL'), Setting('setting_constant', 'PROBLEM_PER_PAGE', null, 100, 'number', 'Problems per Page'), Setting('setting_constant', 'CONTEST_PER_PAGE', null, 20, 'number', 'Contests per Page'), Setting('setting_constant', 'DISCUSSION_PER_PAGE', null, 50, 'number', 'Discussion per Page'), diff --git a/hydro/model/system.js b/hydro/model/system.js index e93e502c9..12dde20b5 100644 --- a/hydro/model/system.js +++ b/hydro/model/system.js @@ -7,10 +7,25 @@ async function get(_id) { if (doc) return doc.value; return null; } + +async function getMany(keys) { + const docs = await coll.find({ _id: { $in: keys } }).toArray(); + const dict = {}; + const res = []; + for (const doc of docs) { + dict[doc._id] = doc.value; + } + for (const key of keys) { + res.push(dict[key] || null); + } + return res; +} + async function update(_id, operation, config) { await coll.findOneAndUpdate({ _id }, operation, config); return get(_id); } + async function set(_id, value) { await coll.findOneAndUpdate({ _id }, { $set: { value } }, { upsert: true }); return get(_id); @@ -25,6 +40,7 @@ function inc(field) { global.Hydro.model.system = module.exports = { get, + getMany, update, inc, set, diff --git a/hydro/utils.js b/hydro/utils.js index 717a252e1..47f3a8400 100644 --- a/hydro/utils.js +++ b/hydro/utils.js @@ -1,3 +1,8 @@ +const superagent = require('superagent'); +const proxy = require('superagent-proxy'); + +proxy(superagent); + const dict = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; String.random = function random(digit = 32) { diff --git a/module/problem-import-syzoj/lib.js b/module/problem-import-syzoj/lib.js index c9bc700e3..bf880d106 100644 --- a/module/problem-import-syzoj/lib.js +++ b/module/problem-import-syzoj/lib.js @@ -1,6 +1,7 @@ const assert = require('assert'); -const { download, axios } = global.Hydro.lib; +const { download } = global.Hydro.lib; +const { superagent } = global.nodeModules; const { ValidationError, RemoteOnlineJudgeError } = global.Hydro.error; async function syzoj(url, handler) { @@ -8,7 +9,7 @@ async function syzoj(url, handler) { assert(url.match(RE_SYZOJ), new ValidationError('url')); if (!url.endsWith('/')) url += '/'; const [, host, pid] = RE_SYZOJ.exec(url); - const res = await axios.get(`${url}export`); + const res = await superagent.get(`${url}export`); assert(res.status === 200, new RemoteOnlineJudgeError('Cannot connect to target server')); assert(res.data.success, new RemoteOnlineJudgeError((res.data.error || {}).message)); const p = res.data.obj; diff --git a/package.json b/package.json index db42f6846..5c1e10cef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.3.0", + "version": "2.4.0", "main": "hydro/loader.js", "repository": "https://github.com/hydro-dev/Hydro.git", "author": "masnn", @@ -8,7 +8,6 @@ "dependencies": { "adm-zip": "^0.4.14", "ansi_up": "^4.0.4", - "axios": "^0.19.0", "bson": "^4.0.2", "detect-browser": "^5.1.1", "eslint": "7.2.0", @@ -32,10 +31,12 @@ "nodemailer": "^6.4.10", "nunjucks": "^3.2.1", "prismjs": "^1.20.0", + "snyk": "^1.346.0", "sockjs": "^0.3.20", + "superagent": "^5.2.2", + "superagent-proxy": "^2.0.0", "systeminformation": "^4.26.5", - "yargs": "^15.3.1", - "snyk": "^1.346.0" + "yargs": "^15.3.1" }, "devDependencies": { "eslint-config-airbnb-base": "^14.2.0", @@ -63,4 +64,4 @@ ] }, "snyk": true -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3fec359fb..9468d1073 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,18 +709,16 @@ async@^1.4.0: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -axios@^0.19.0: - version "0.19.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" - integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== - dependencies: - follow-redirects "1.5.10" - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1277,6 +1275,13 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -1292,7 +1297,7 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -component-emitter@^1.2.1: +component-emitter@^1.2.1, component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -1363,6 +1368,11 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +cookiejar@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + cookies@~0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" @@ -1483,7 +1493,7 @@ debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@3.1.0, debug@=3.1.0, debug@~3.1.0: +debug@3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -1579,6 +1589,11 @@ degenerator@^1.0.4: escodegen "1.x.x" esprima "3.x.x" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + delegate@^3.1.2: version "3.2.0" resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" @@ -2129,6 +2144,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-safe-stringify@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -2237,19 +2257,21 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -formidable@^1.1.1: +form-data@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" + integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formidable@^1.1.1, formidable@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== @@ -3538,13 +3560,18 @@ mime-db@1.44.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== -mime-types@^2.1.18, mime-types@^2.1.8, mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.8, mime-types@~2.1.24: version "2.1.27" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== dependencies: mime-db "1.44.0" +mime@^2.4.4: + version "2.4.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" + integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -4314,7 +4341,7 @@ promise-inflight@^1.0.1: dependencies: asap "~2.0.3" -proxy-agent@^3.1.1: +proxy-agent@3, proxy-agent@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-3.1.1.tgz#7e04e06bf36afa624a1540be247b47c970bd3014" integrity sha512-WudaR0eTsDx33O3EJE16PjBRZWcX8GqCEeERw1W3hZJgH/F2a46g7jty6UGty6NeJ4CKQy8ds2CJPMiyeqaTvw== @@ -4402,7 +4429,7 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" -qs@^6.4.0: +qs@^6.4.0, qs@^6.9.1: version "6.9.4" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== @@ -5460,6 +5487,31 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +superagent-proxy@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/superagent-proxy/-/superagent-proxy-2.0.0.tgz#9f57515cd660e2e9ce55c0e6bd70f92eb07c3ee0" + integrity sha512-TktJma5jPdiH1BNN+reF/RMW3b8aBTCV7KlLFV0uYcREgNf3pvo7Rdt564OcFHwkGb3mYEhHuWPBhSbOwiNaYw== + dependencies: + debug "^3.1.0" + proxy-agent "3" + +superagent@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-5.2.2.tgz#6ff726c5642795b2c27009e92687c8e69a6bb07d" + integrity sha512-pMWBUnIllK4ZTw7p/UaobiQPwAO5w/1NRRTDpV0FTVNmECztsxKspj3ZWEordVEaqpZtmOQJJna4yTLyC/q7PQ== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.2" + debug "^4.1.1" + fast-safe-stringify "^2.0.7" + form-data "^3.0.0" + formidable "^1.2.1" + methods "^1.1.2" + mime "^2.4.4" + qs "^6.9.1" + readable-stream "^3.4.0" + semver "^6.3.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"