From e143d3aa6c281b853003a0debcd16641e399e980 Mon Sep 17 00:00:00 2001 From: "Qumolama.d" Date: Mon, 30 May 2022 02:12:54 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A5=BD=E5=A4=9A=20BUG?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0web-api=E9=83=A8=E5=88=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- README.MD | 2 - package.json | 1 + src/config.js | 16 +- src/hooks.js | 6 +- src/index.js | 56 +++++- src/models/player.js | 19 ++- src/routes/advanced.js | 18 +- src/routes/authenticate.js | 15 +- src/routes/web-api.js | 339 +++++++++++++++++++++++++++++++++++++ yarn.lock | 94 +++++++++- 11 files changed, 547 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 4f8f1f2..508c27f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ yarn-error.log node_modules production **/*.key -**/*.pem \ No newline at end of file +**/*.pem +# My own launch script which should NEVER upload since there is secrets! +launch.ps1 \ No newline at end of file diff --git a/README.MD b/README.MD index 2d243d9..70319b6 100644 --- a/README.MD +++ b/README.MD @@ -12,8 +12,6 @@ 具体有多快呢?登录处理从数据包发出到接收到服务端响应仅需要 __***6ms***__(根据机器不同可能会有浮动,以实际情况为准)! -**暂时别管这个 build 是不是 failed。因为某些原因 ci 跑不了,每次提交之前我会在本地进行测试直到修复** - --- diff --git a/package.json b/package.json index ec4f460..8f02a84 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@fastify/swagger": "^6.0.1", + "aws-sdk": "^2.1140.0", "axios": "^0.27.2", "fastify": "^3.29.0", "hex-to-uuid": "^1.1.1", diff --git a/src/config.js b/src/config.js index 8b4d810..db5c957 100644 --- a/src/config.js +++ b/src/config.js @@ -1,10 +1,10 @@ export const config = { database: { // MONGODB IS THE BEST DATABASE - url: 'mongodb://localhost:27017/yggdrasil?readPreference=primary&appname=MongoDB%20Compass&directConnection=true&ssl=false', + url: '您的mongodb链接', }, server: { port: 3000, - skinDomain: [ "assets.lama.icu" ], + skinDomain: [ "assets.lama.icu", 'textures.minecraft.net' ], serverName: "老色批世界树", advanced: { // 详情可见 -> https://github.com/yushijinhun/authlib-injector/wiki/Yggdrasil-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#meta-%E4%B8%AD%E7%9A%84%E5%85%83%E6%95%B0%E6%8D%AE links: { @@ -12,12 +12,17 @@ export const config = { register: "" }, "feature.non_email_login": false, - "feature.legacy_skin_api": false, - "feature.no_mojang_namespace": false, + "feature.legojang_namespace": false, "feature.enable_mojang_anti_features": false, "feature.enable_profile_key": false } }, + storage: { + endpoint: "", + bucket: "", + key: "", + + }, signing: { // 签名材质信息使用 public: 'public.pem', private: 'private.key' @@ -41,7 +46,8 @@ export const config = { postRouting: (fastify) => {}, // 我也不知道你在这里写了有啥用... }, telegram: { - token: '5161996862:AAHY79HdmI9A9Xoumv4E8hzi5UUrY38n5h0', + disable: undefined, // 设置为任意非null、undefined、false、0、""等值(可以设置为true就禁用了),则禁用telegram功能 + token: '你的telegrambot的apitoken', } } diff --git a/src/hooks.js b/src/hooks.js index 5f43047..390edee 100644 --- a/src/hooks.js +++ b/src/hooks.js @@ -5,8 +5,12 @@ export async function headerValidation(req, rep) { } if(Object.keys(req.headers).some(key => { - return key.toLowerCase() === "content-type" && req.headers[key].toLowerCase() !== "application/json" + req.log.info(key.toLowerCase() === "content-type") + req.log.info(req.headers[key].toLowerCase()) + return key.toLowerCase() === "content-type" && req.headers[key].toLowerCase().indexOf("application/json") === -1 })) { + req.log.info(JSON.stringify(req.headers)) + return rep.code(400).send({ error: "IllegalArgumentException", errorMessage: "请求内容不正确", diff --git a/src/index.js b/src/index.js index fc85a84..f29549f 100644 --- a/src/index.js +++ b/src/index.js @@ -5,12 +5,54 @@ import * as AuthenticateRoutings from './routes/authenticate.js' import * as SessionServerRoutings from './routes/session.js' import * as AdvancedRoutings from './routes/advanced.js' import * as APIRoutings from './routes/api.js' +import * as WebAPIRoutings from './routes/web-api.js' import { config } from './config.js' import { readFileSync } from 'fs' import { Scenes, session, Telegraf } from 'telegraf' -import { allScenes, registerAllPlayerCommands } from './telegram/player-commands.js'; +import { allScenes, registerAllPlayerCommands } from './telegram/player-commands.js' import { Player } from './models/player.js' import fastifySwagger from '@fastify/swagger' +import S3 from 'aws-sdk/clients/s3.js' + +String.prototype._split = String.prototype.split + +String.prototype.split = function(separator, limit) { + if (separator === undefined && limit === 0) return [] + + if(limit === undefined) { + return String.prototype._split.call(this, separator, limit) + } + + const arr = [] + let lastBegin = -1 + for(let i = 0; i < limit - 1; i++) { + const end = String.prototype.indexOf.call(this, separator, ++lastBegin) + if(end == -1) { + arr.push(undefined) + continue + } + arr.push(String.prototype.substring.call(this, lastBegin, end)) + lastBegin = end + } + arr.push(String.prototype.substring.call(this, ++lastBegin)) + + return arr +} + +for(let i = 0; i < process.argv.length; i++) { + const curr = process.argv[i] + if(curr.startsWith('--')) { + switch(curr.substring(2)){ + case 'override': + const [next, value] = process.argv[i + 1].split(":", 2) + if(!next || next.startsWith('--')) { + continue + } else { + eval(`config.${next} = '${value}'`) + } + } + } +} export const server = fastify({ logger: { @@ -21,6 +63,11 @@ export const server = fastify({ export const telegraf = new Telegraf(config.telegram.token) +export const s3Instance = new S3({ + accessKeyId: config.storage.key, + endpoint: config.storage.endpoint, +}) + export const setup = async () => { server.log.info("老色批世界树 > 初始化中...") @@ -29,6 +76,8 @@ export const setup = async () => { const privateKey = readFileSync(config.signing.private).toString() server.decorate('keys', { publicKey, privateKey }) + + s3Instance.putObject() config.custom.preHooks(server) server.addHook('preHandler', Hooks.headerValidation) @@ -65,6 +114,9 @@ export const setup = async () => { server.route(APIRoutings.profiles) + server.route(WebAPIRoutings.login) + server.route(WebAPIRoutings.register) + config.custom.postRouting(server) if(process.env["UNIT_TEST"] || process.env["DEVEL_FIRST_RUN"]) { @@ -74,7 +126,7 @@ export const setup = async () => { password: '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', email: 'i@lama.icu', uuid: '098f6bcd-4621-3373-8ade-4e832627b4f6', - texture: { + textures: { skin: 'assets.lama.icu/textures/skin/steve.png', cape: 'assets.lama.icu/textures/cape/default.png' }, diff --git a/src/models/player.js b/src/models/player.js index 0c4428d..35f7c04 100644 --- a/src/models/player.js +++ b/src/models/player.js @@ -1,6 +1,7 @@ import mongoose from 'mongoose' import { uuidToNoSymboUUID } from '../generator.js' import { ImageSecurity } from '../secure.js' +import { server } from '../index.js' export const Player = mongoose.model("Player", new mongoose.Schema({ username: String, // 有符号 UUID @@ -81,11 +82,11 @@ export function getPlayerSerialization(player) { if(player.textures.skin && player.textures.skin != 0) { // Must be '!=' if this change to '!==' will never works textures.textures.SKIN = { - url: player.textures.skin, + url: player.textures.skin } } - if(player.textures.skin && player.textures.skin != 0) { // Must be '!=' if this change to '!==' will never works + if(player.textures.cape && player.textures.cape != 0) { // Must be '!=' if this change to '!==' will never works textures.textures.CAPE = { url: player.textures.cape, } @@ -93,8 +94,20 @@ export function getPlayerSerialization(player) { const val = Buffer.from(JSON.stringify(textures)).toString('base64') + server.log.info({ + id: uuidToNoSymboUUID(player.uuid), + name: player.username, + properties: [ + { + name: "texturs", + value: val, + signature: ImageSecurity.sign(val), + } + ] + }) + return { - uuid: uuidToNoSymboUUID(player.uuid), + id: uuidToNoSymboUUID(player.uuid), name: player.username, properties: [ { diff --git a/src/routes/advanced.js b/src/routes/advanced.js index 39a2f31..d6225dd 100644 --- a/src/routes/advanced.js +++ b/src/routes/advanced.js @@ -26,7 +26,10 @@ export const meta = { } }, "skinDomains": { - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "signaturePublickey": { "type": "string" @@ -69,7 +72,17 @@ export const status = { }, "api": { "type": "object", - + "properties": { + "yggdrasil": { + "type": "string" + }, + "webapi": { + "type": "string" + } + } + }, + "name": { + "type": "string" }, "server": { "type": "string" @@ -100,6 +113,7 @@ export const status = { rep.code(200).send({ public: this.keys.publicKey, version: "1.0", + name: config.server.serverName, api: { yggdrasil: "authlib-injector", webapi: "standard-1.0" diff --git a/src/routes/authenticate.js b/src/routes/authenticate.js index fcb9fc1..ae3d884 100644 --- a/src/routes/authenticate.js +++ b/src/routes/authenticate.js @@ -101,13 +101,16 @@ export const authenticate = { id: uuidToNoSymboUUID(player.uuid), properties: [ { - preferredLanguage: "zh_CN" + name: "preferredLanguage", + value: "zh_CN" } ] } const profile = PlayerModel.getPlayerSerialization(player) + await Token.deleteMany({ player: player.uuid }).exec() + new Token({ uuid: player.uuid, token: token, @@ -115,14 +118,16 @@ export const authenticate = { expireDate: Date.now() + 1000 * 60 * 60 * 24 * 15, deadDate: Date.now() + 1000 * 60 * 60 * 24 * 30, }).save() - - return await rep.send({ + + const response = { accessToken: token, clientToken: clientToken, availableProfiles: [ profile ], selectedProfile: profile, user: account - }) + } + req.log.info("响应请求中: " + JSON.stringify(response)) + return await rep.send(response) } } @@ -170,7 +175,7 @@ export const refresh = { } }, preHandler: getOverridePreHandler("/authserver/refresh"), - handler: getOverrideHandler("/authserver/authenticate") ?? async function (req, rep) { + handler: getOverrideHandler("/authserver/refresh") ?? async function (req, rep) { const { accessToken, clientToken, requestUser, selectedProfile } = req.body const query = { diff --git a/src/routes/web-api.js b/src/routes/web-api.js index e69de29..20f96e7 100644 --- a/src/routes/web-api.js +++ b/src/routes/web-api.js @@ -0,0 +1,339 @@ +import { getOverrideHandler, getOverridePreHandler } from "../config.js" +import { Player } from "../models/player.js" +import { createHash } from "crypto" +import { generateToken, uuid } from "../generator.js" +import { Token } from "../models/token.js" + +const BASE_RESPONSE = { + err: { + type: "number", + description: "错误类型, 1.048596代表无错误", + example: 1.048596 + }, + msg: { + type: "string", + description: "错误信息,如果有错误则返回错误信息,否则返回空字符串 << 感谢 Copilot 的补全", + example: "你号被ban了" + } +} + +const identifiers = new Map() + +async function identifierValidator(req, rep) { + const identifier = req.headers['X-LSP-Idenitifier'] + if(!identifier) { + return await rep.code(401).send({ + err: 1.143688, + }) + } +} + +export const login = { + method: 'POST', + url: '/api/login', + schema: { + summary: "登录", + description: `登录到 webapi,后续请求需要携带请求头 'X-LSP-Idenitifier': ''`, + tags: [ 'webapi' ], + body: { + type: 'object', + properties: { + username: { + type: 'string', + description: '用户名', + example: 'test' + }, + password: { + type: 'string', + description: '密码', + example: '123456' + }, + createToken: { + type: 'boolean', + description: '是否创建一个 accessToken', + example: false + } + } + }, + response: { + 200: { + type: 'object', + properties: { + ...BASE_RESPONSE, + extra: { + type: 'object', + description: '额外信息', + example: { + identifier: '', + textures: { + skin: '', + cape: '' + }, + username: '', + uuid: '' + }, + properties: { + identifier: { + type: 'string', + description: 'identifier,后面请求必须带 X-LSP-Idenitifier: 请求头', + example: '' + }, + textures: { + type: 'object', + description: '用户皮肤和披风', + example: { + skin: '', + cape: '' + }, + properties: { + skin: { + type: 'string', + description: '用户皮肤', + example: '', + optional: true, + }, + cape: { + type: 'string', + description: '用户披风', + example: '', + optional: true, + } + }, + }, + username: { + type: 'string', + description: '用户名', + example: '' + }, + uuid: { + type: 'string', + description: '用户唯一标识', + example: '' + } + } + } + } + }, + 401: { + type: 'object', + properties: { + err: { + type: 'number', + description: '错误类型', + example: 1.048596 + }, + msg: { + type: 'string', + description: '错误内容,展示给用户看的', + example: "您输入的密码似乎是用户 lama 的,请确保用户名没有打错!" + }, + } + + } + }, + }, + preHandler: getOverridePreHandler('/api/login'), + handler: getOverrideHandler('/api/login') ?? async function(req, rep) { + const { username, password, createToken } = req.body; + const user = await Player.findOne({ email: username, password: createHash("sha256").update(password).digest('hex') }); + if (!user) { + return rep.code(401).send({ + err: 1.143688, + msg: "用户名或密码错误" + }); + } + + if(!user.permissions.some((it) => { s + return it.node === 'login' && it.allowed && (it.duration === 0 || it.startDate + it.duration > Date.now()) + })) { + return await rep.code(401).send({ + err: 0.337187, + msg: "泻药,宁滴账号已被封禁" + }); + } + + const [token, key] = generateToken(`webapi:${user.username}`) + this.log.info(`/api/login > 为玩家 webapi:${user.username} 生成令牌: ${token} | 随机 key = ${key}`) + + identifiers.set(token, { + uuid: user.uuid, + t: Date.now() + 1000 * 60 * 60 * 24 * 1, + }) + + if(createToken) { + new Token({ + uuid: user.uuid, + token: token, + clientToken: `${req.headers['x-forwarded-for'] || req.ip}:${token.substring(3, 8)}`, + expireDate: Date.now() + 1000 * 60 * 60 * 24 * 15, + deadDate: Date.now() + 1000 * 60 * 60 * 24 * 30, + }).save() + } + + return await rep.code(200).send(JSON.stringify({ + err: 1.048596, + msg: '', + extra: { + identifier: token, + textures: user.textures, + username: user.username, + uuid: user.uuid, + } + })) + } +} + +export const register = { + method: 'POST', + url: '/api/register', + schema: { + summary: "注册", + description: `注册到 webapi,后续请求需要先登录获取identifier,然后携带请求头 'X-LSP-Idenitifier': '',200正确返回 <<< Copilot自己补全的`, + tags: [ 'webapi' ], + body: { + type: 'object', + properties: { + username: { + type: 'string', + description: '用户名', + example: 'test' + }, + password: { + type: 'string', + description: '密码', + example: '123456' + }, + email: { + type: 'string', + description: '邮箱', + example: '' + }, + telegramId: { + type: 'string', + description: 'telegramId', + example: '' + }, + textureMigrations: { + type: 'object', + description: '纹理迁移', + optional: true, + properties: { + skin: { + type: 'string', + description: '皮肤', + optional: true, + example: 'https://assets.lama.icu/textures/skin/steve.png' + }, + cape: { + type: 'string', + description: '披风', + optional: true, + example: 'https://assets.lama.icu/textures/cape/steve.png' + } + } + } + } + }, + response: { + 200: { + type: 'object', + properties: { + ...BASE_RESPONSE, + extra: { + username: { + type: 'string', + description: '用户名', + example: 'test' + }, + password: { + type: 'string', + description: '密码', + example: '123456' + }, + email: { + type: 'string', + description: '邮箱', + example: '' + }, + telegramId: { + type: 'string', + description: 'telegramId', + example: '' + }, + textureMigrations: { + type: 'object', + description: '纹理迁移', + optional: true, + properties: { + skin: { + type: 'string', + description: '皮肤', + optional: true, + example: 'https://assets.lama.icu/textures/skin/steve.png' + }, + cape: { + type: 'string', + description: '披风', + optional: true, + example: 'https://assets.lama.icu/textures/cape/steve.png' + } + } + } + } + } + }, + }, + }, + preHandler: getOverridePreHandler('/api/register'), + handler: getOverrideHandler('/api/register') ?? async function(req, rep) { + const { username, password, email, telegramId, textureMigrations } = req.body + const user = await Player.findOne({ $or: [ + { email: email }, { username: username } + ] }) + if (user) { + return await rep.code(401).send({ + err: 1, + msg: "用户名已存在" + }) + } + + if(username == 0 || password == 0 || email == 0 || telegramId == 0) { + return await rep.code(401).send({ + err: 1, + msg: "用户名/密码/邮箱/telegramId不能为空" + }) + } + + const textues = { } + + if(textureMigrations) { + if(textureMigrations.skin != 0 && textureMigrations.skin) { + textues.skin = textureMigrations.skin + } + + if(textureMigrations.cape != 0 && textureMigrations.cape) { + textues.cape = textureMigrations.cape + } + } + + const newUser = new Player({ + username, + password: createHash("sha256").update(password).digest('hex'), + email, + uuid: uuid('LSPlayer:' + email), + textues, + registerDate: Date.now(), + permissions: [{ node: 'login', allowed: true, duration: -1, startDate: Date.now(), highPriority: false }], + telegramBind: { + username: telegramId, + verified: false + } + }); + await newUser.save() + + return await rep.code(200).send({ + err: 1.048596, + msg: '', + }) + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 020068f..01b1efb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -821,6 +821,21 @@ avvio@^7.1.2: fastq "^1.6.1" queue-microtask "^1.1.2" +aws-sdk@^2.1140.0: + version "2.1140.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1140.0.tgz#7f19b821aac87dc6edf4d5ce256d496106779dfe" + integrity sha512-cNdq56UQrUzXmCgwo0/J5GGLmfHn+Vp38qgcK/Xd86Sch8P9v2o8tNv7J82mYU98YY2vO007BMxRylA4Sd8PkQ== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.16.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + axios@^0.27.2: version "0.27.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" @@ -894,7 +909,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1: +base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -981,6 +996,15 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -1518,6 +1542,11 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +events@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -1836,7 +1865,12 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -ieee754@^1.1.13: +ieee754@1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -1988,6 +2022,11 @@ is-yarn-global@^0.3.0: resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== +isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2392,6 +2431,11 @@ jest@^28.0.3: import-local "^3.0.2" jest-cli "^28.0.3" +jmespath@0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" + integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== + joycon@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" @@ -2960,6 +3004,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -2972,6 +3021,11 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + queue-microtask@^1.1.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -3133,6 +3187,16 @@ saslprep@^1.0.3: dependencies: sparse-bitfield "^3.0.3" +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + secure-json-parse@^2.0.0, secure-json-parse@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" @@ -3559,6 +3623,14 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -3569,6 +3641,11 @@ uuid-parse@^1.1.0: resolved "https://registry.yarnpkg.com/uuid-parse/-/uuid-parse-1.1.0.tgz#7061c5a1384ae0e1f943c538094597e1b5f3a65b" integrity sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A== +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + v8-to-istanbul@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz#be0dae58719fc53cb97e5c7ac1d7e6d4f5b19511" @@ -3667,6 +3744,19 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"