修复好多 BUG,添加web-api部分功能
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Qumolama.d 2022-05-30 02:12:54 +08:00
parent 877e1e4587
commit e143d3aa6c
Signed by: Lama3L9R
GPG Key ID: 1762AFC05157CE18
11 changed files with 547 additions and 23 deletions

4
.gitignore vendored
View File

@ -2,4 +2,6 @@ yarn-error.log
node_modules
production
**/*.key
**/*.pem
**/*.pem
# My own launch script which should NEVER upload since there is secrets!
launch.ps1

View File

@ -12,8 +12,6 @@
具体有多快呢?登录处理从数据包发出到接收到服务端响应仅需要 __***6ms***__根据机器不同可能会有浮动以实际情况为准
**暂时别管这个 build 是不是 failed。因为某些原因 ci 跑不了,每次提交之前我会在本地进行测试直到修复**
---

View File

@ -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",

View File

@ -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',
}
}

View File

@ -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: "请求内容不正确",

View File

@ -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'
},

View File

@ -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: [
{

View File

@ -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"

View File

@ -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 = {

View File

@ -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': '<token>'`,
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: '<token>',
textures: {
skin: '<url>',
cape: '<url>'
},
username: '<username>',
uuid: '<uuid>'
},
properties: {
identifier: {
type: 'string',
description: 'identifier后面请求必须带 X-LSP-Idenitifier: <token> 请求头',
example: '<token>'
},
textures: {
type: 'object',
description: '用户皮肤和披风',
example: {
skin: '<url>',
cape: '<url>'
},
properties: {
skin: {
type: 'string',
description: '用户皮肤',
example: '<url>',
optional: true,
},
cape: {
type: 'string',
description: '用户披风',
example: '<url>',
optional: true,
}
},
},
username: {
type: 'string',
description: '用户名',
example: '<username>'
},
uuid: {
type: 'string',
description: '用户唯一标识',
example: '<uuid>'
}
}
}
}
},
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': '<token>'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: '',
})
}
}

View File

@ -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"