diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..6a65709a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + "env": { + "commonjs": true, + "es2021": true, + "node": true + }, + "extends": "eslint:recommended", + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 12 + }, + "rules": { + "indent": [ + "error", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ], + "no-empty": [ + "error", + { "allowEmptyCatch": true } + ], + "no-unused-vars": "warn", + "no-redeclare": "warn", + "no-constant-condition": "warn", + "no-useless-escape": "warn", + "no-case-declarations": "warn", + } +}; diff --git a/.gitignore b/.gitignore index d19f09f4..3afd8ec9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules .vscode -data \ No newline at end of file +data diff --git a/client.js b/client.js index 7a270da6..1478e3fc 100644 --- a/client.js +++ b/client.js @@ -4,11 +4,11 @@ const net = require("net"); const fs = require("fs"); const path = require("path"); const os = require("os"); -const {exec} = require("child_process"); -const {randomBytes} = require("crypto"); +const { exec } = require("child_process"); +const { randomBytes } = require("crypto"); const log4js = require("log4js"); -const {getApkInfo, getDeviceInfo} = require("./device"); -const {checkUin, timestamp, md5} = require("./lib/common"); +const { getApkInfo, getDeviceInfo } = require("./device"); +const { checkUin, timestamp, md5 } = require("./lib/common"); const core = require("./lib/core"); const frdlst = require("./lib/friendlist"); const sysmsg = require("./lib/sysmsg"); @@ -16,13 +16,13 @@ const wt = require("./lib/wtlogin/wt"); const chat = require("./lib/message/chat"); const indi = require("./lib/individual"); const troop = require("./lib/troop"); -const {getErrorMessage, TimeoutError} = require("./exception"); +const { getErrorMessage, TimeoutError } = require("./exception"); const BUF0 = Buffer.alloc(0); function buildApiRet(retcode, data = null, error = null) { data = data ? data : null; error = error ? error : null; - const status = retcode ? (retcode===1?"async":"failed") : "ok"; + const status = retcode ? (retcode === 1 ? "async" : "failed") : "ok"; return { retcode, data, status, error }; @@ -108,10 +108,10 @@ class AndroidClient extends Client { this.logger = log4js.getLogger(`[BOT:${uin}]`); this.logger.level = config.log_level; - this.logger.info(`----------`); + this.logger.info("----------"); this.logger.info(`Package Version: oicq@${version.version} (Released on ${version.upday})`); this.logger.info("View Changelogs:https://github.com/takayama-lily/oicq/releases"); - this.logger.info(`----------`); + this.logger.info("----------"); const filepath = path.join(this.dir, `device-${uin}.json`); if (!fs.existsSync(filepath)) @@ -120,10 +120,10 @@ class AndroidClient extends Client { this.apk = getApkInfo(config.platform); this.ksid = Buffer.from(`|${this.device.imei}|` + this.apk.name); - this.on("error", (err)=>{ + this.on("error", (err) => { this.logger.error(err.message); }); - this.on("close", ()=>{ + this.on("close", () => { this.read(); if (this.remoteAddress) this.logger.info(`${this.remoteAddress}:${this.remotePort} closed`); @@ -133,13 +133,13 @@ class AndroidClient extends Client { } else if (this.status === Client.ONLINE) { ++this.stat.lost_times; this.logining = true; - setTimeout(()=>{ + setTimeout(() => { this._connect(this.register.bind(this)); }, 50); } this.status = Client.OFFLINE; }); - this.on("readable", ()=>{ + this.on("readable", () => { while (this.readableLength > 4) { let len_buf = this.read(4); let len = len_buf.readInt32BE(); @@ -160,7 +160,7 @@ class AndroidClient extends Client { } }); - this.on("internal.login", async()=>{ + this.on("internal.login", async () => { this.logger.info(`Welcome, ${this.nickname} ! 开始初始化资源...`); this.sync_finished = false; await this.register(); @@ -177,7 +177,7 @@ class AndroidClient extends Client { this.em("system.online"); }); - this.on("internal.wt.failed", (message)=>{ + this.on("internal.wt.failed", (message) => { this.logining = false; this.logger.error(message); if (this.status !== Client.OFFLINE) @@ -186,11 +186,11 @@ class AndroidClient extends Client { this.logger.warn(this.config.reconn_interval + "秒后重新连接。"); setTimeout(this.login.bind(this), this.config.reconn_interval * 1000); } - this.em("system.offline.network", {message}); + this.em("system.offline.network", { message }); }); } - _connect(callback = ()=>{}) { + _connect(callback = () => { }) { if (this.status !== Client.OFFLINE) { return callback(); } @@ -201,7 +201,7 @@ class AndroidClient extends Client { port = this.config.remote_port; this.logger.info(`connecting to ${ip}:${port}`); this.removeAllListeners("connect"); - this.connect(port, ip, ()=>{ + this.connect(port, ip, () => { this.status = Client.INIT; this.logger.info(`${this.remoteAddress}:${this.remotePort} connected`); this.resume(); @@ -218,15 +218,15 @@ class AndroidClient extends Client { async send(packet, timeout = 5000) { ++this.stat.sent_pkt_cnt; const seq_id = this.seq_id; - return new Promise((resolve, reject)=>{ - this.write(packet, ()=>{ - const id = setTimeout(()=>{ + return new Promise((resolve, reject) => { + this.write(packet, () => { + const id = setTimeout(() => { this.handlers.delete(seq_id); ++this.stat.lost_pkt_cnt; reject(new TimeoutError()); - this.em("internal.timeout", {seq_id}); + this.em("internal.timeout", { seq_id }); }, timeout); - this.handlers.set(seq_id, (data)=>{ + this.handlers.set(seq_id, (data) => { clearTimeout(id); this.handlers.delete(seq_id); resolve(data); @@ -245,7 +245,7 @@ class AndroidClient extends Client { startHeartbeat() { if (this.heartbeat) return; - this.heartbeat = setInterval(async()=>{ + this.heartbeat = setInterval(async () => { this.doCircle(); try { if (!this.isOnline()) @@ -294,7 +294,7 @@ class AndroidClient extends Client { this.setOnlineStatus(this.online_status); this.startHeartbeat(); if (!this.listenerCount("internal.kickoff")) { - this.once("internal.kickoff", (data)=>{ + this.once("internal.kickoff", (data) => { this.status = Client.INIT; this.stopHeartbeat(); this.logger.warn(data.info); @@ -318,7 +318,7 @@ class AndroidClient extends Client { this.logger.warn("3秒后重新连接.."); setTimeout(this.login.bind(this), 3000); } - this.em("system.offline." + sub_type, {message: data.info}); + this.em("system.offline." + sub_type, { message: data.info }); }); } await core.getMsg.call(this); @@ -330,7 +330,7 @@ class AndroidClient extends Client { */ async useProtocol(fn, params) { if (!this.isOnline() || !this.sync_finished) - return buildApiRet(104, null, {code: -1, message: "bot not online"}); + return buildApiRet(104, null, { code: -1, message: "bot not online" }); try { const rsp = await fn.apply(this, params); if (!rsp) @@ -339,16 +339,16 @@ class AndroidClient extends Client { return buildApiRet(102, null, { code: rsp.result, - message: rsp.emsg?rsp.emsg:getErrorMessage(fn, rsp.result) + message: rsp.emsg ? rsp.emsg : getErrorMessage(fn, rsp.result) } ); else return buildApiRet(0, rsp.data); } catch (e) { if (e instanceof TimeoutError) - return buildApiRet(103, null, {code: -1, message: "packet timeout"}); + return buildApiRet(103, null, { code: -1, message: "packet timeout" }); this.logger.debug(e); - return buildApiRet(100, null, {code: -1, message: e.message}); + return buildApiRet(100, null, { code: -1, message: e.message }); } } @@ -356,9 +356,9 @@ class AndroidClient extends Client { const slice = name.split("."); const post_type = slice[0], sub_type = slice[2]; const param = { - self_id: this.uin, - time: timestamp(), - post_type: post_type + self_id: this.uin, + time: timestamp(), + post_type: post_type }; const type_name = slice[0] + "_type"; param[type_name] = slice[1]; @@ -389,7 +389,7 @@ class AndroidClient extends Client { } doCircle() { wt.exchangeEMP.call(this); - if (this.config.platform != 2 && this.config.platform != 3 &&this.var4++ > 10) { + if (this.config.platform != 2 && this.config.platform != 3 && this.var4++ > 10) { this.setOnlineStatus(this.online_status); this.var4 = 0; } @@ -428,7 +428,7 @@ class AndroidClient extends Client { else this.password_md5 = md5(String(password)); } - this._connect(()=>{ + this._connect(() => { wt.passwordLogin.call(this); }); } @@ -436,7 +436,7 @@ class AndroidClient extends Client { captchaLogin(captcha) { if (!this.captcha_sign) return this.logger.warn("未收到图片验证码或已过期,你不能调用captchaLogin函数。"); - this._connect(()=>{ + this._connect(() => { wt.captchaLogin.call(this, captcha); }); } @@ -444,7 +444,7 @@ class AndroidClient extends Client { sliderLogin(ticket) { if (!this.t104) return this.logger.warn("未收到滑动验证码或已过期,你不能调用sliderLogin函数。"); - this._connect(()=>{ + this._connect(() => { wt.sliderLogin.call(this, ticket); }); } @@ -459,7 +459,7 @@ class AndroidClient extends Client { if (this.isOnline()) { try { await wt.register.call(this, true); - } catch {} + } catch { } } this.terminate(); } @@ -535,7 +535,7 @@ class AndroidClient extends Client { return await this.useProtocol(troop.setAnonymous, arguments); } async setGroupWholeBan(group_id, enable = true) { - return await this.setGroupSetting(group_id, "shutupTime", enable?0xffffffff:0); + return await this.setGroupSetting(group_id, "shutupTime", enable ? 0xffffffff : 0); } async setGroupName(group_id, group_name) { return await this.setGroupSetting(group_id, "ingGroupName", String(group_name)); @@ -601,7 +601,7 @@ class AndroidClient extends Client { } async setGender(gender) { gender = parseInt(gender); - if (![0,1,2].includes(gender)) + if (![0, 1, 2].includes(gender)) return buildApiRet(100); return await this.useProtocol(indi.setProfile, [0x14E29, Buffer.from([gender])]); } @@ -632,11 +632,11 @@ class AndroidClient extends Client { async getCookies(domain) { await wt.exchangeEMP.call(this); if (domain && !this.cookies[domain]) - return buildApiRet(100, null, {code: -1, message: "unknown domain"}); + return buildApiRet(100, null, { code: -1, message: "unknown domain" }); let cookies = `uin=o${this.uin}; skey=${this.sig.skey};`; if (domain) cookies = `${cookies} p_uin=o${this.uin}; p_skey=${this.cookies[domain]};`; - return buildApiRet(0, {cookies}); + return buildApiRet(0, { cookies }); } async getCsrfToken() { @@ -645,7 +645,7 @@ class AndroidClient extends Client { for (let v of this.sig.skey) token = token + (token << 5) + v; token &= 2147483647; - return buildApiRet(0, {token}); + return buildApiRet(0, { token }); } /** @@ -653,33 +653,33 @@ class AndroidClient extends Client { */ async cleanCache(type = "") { switch (type) { - case "image": - case "record": - const file = path.join(this.dir, "..", type, "*"); - const cmd = os.platform().includes("win") ? `del /q ` : `rm -f `; - exec(cmd + file, (err, stdout, stderr)=>{ - if (err) - return this.logger.error(err); - if (stderr) - return this.logger.error(stderr); - this.logger.info(type + " cache clear"); - }); - break; - case "": - this.cleanCache("image"); - this.cleanCache("record"); - break; - default: - return buildApiRet(100, null, {code:-1, message:"unknown type (image, record, or undefined)"}); + case "image": + case "record": + const file = path.join(this.dir, "..", type, "*"); + const cmd = os.platform().includes("win") ? "del /q " : "rm -f "; + exec(cmd + file, (err, stdout, stderr) => { + if (err) + return this.logger.error(err); + if (stderr) + return this.logger.error(stderr); + this.logger.info(type + " cache clear"); + }); + break; + case "": + this.cleanCache("image"); + this.cleanCache("record"); + break; + default: + return buildApiRet(100, null, { code: -1, message: "unknown type (image, record, or undefined)" }); } return buildApiRet(1); } canSendImage() { - return buildApiRet(0, {yes: true}); + return buildApiRet(0, { yes: true }); } canSendRecord() { - return buildApiRet(0, {yes: true}); + return buildApiRet(0, { yes: true }); } getVersionInfo() { return buildApiRet(0, version); @@ -693,14 +693,14 @@ class AndroidClient extends Client { msg_cnt_per_min: this.calcMsgCnt(), statistics: this.stat, config: this.config - }) + }); } getLoginInfo() { return buildApiRet(0, { user_id: this.uin, nickname: this.nickname, age: this.age, sex: this.sex - }) + }); } } @@ -715,7 +715,7 @@ process.OICQ = { function createDataDir(dir, uin) { if (!fs.existsSync(dir)) - fs.mkdirSync(dir, {mode: 0o755, recursive: true}); + fs.mkdirSync(dir, { mode: 0o755, recursive: true }); const img_path = path.join(dir, "image"); const ptt_path = path.join(dir, "record"); const uin_path = path.join(dir, String(uin)); @@ -724,14 +724,14 @@ function createDataDir(dir, uin) { if (!fs.existsSync(ptt_path)) fs.mkdirSync(ptt_path); if (!fs.existsSync(uin_path)) - fs.mkdirSync(uin_path, {mode: 0o755}); + fs.mkdirSync(uin_path, { mode: 0o755 }); return uin_path; } /** * @deprecated */ -function setGlobalConfig() {} +function setGlobalConfig() { } //---------------------------------------------------------------------------------------------------- diff --git a/device.js b/device.js index b4b2c981..d3c9ba92 100644 --- a/device.js +++ b/device.js @@ -3,12 +3,12 @@ const fs = require("fs"); const path = require("path"); const os = require("os"); const crypto = require("crypto"); -const {uuid, md5} = require("./lib/common"); +const { uuid, md5 } = require("./lib/common"); function rand(n = 9) { - const max = 10**n - n; - const min = 10**(n-1) + n; - return parseInt(Math.random()*(max-min)+min); + const max = 10 ** n - n; + const min = 10 ** (n - 1) + n; + return parseInt(Math.random() * (max - min) + min); } function getMac() { @@ -61,7 +61,7 @@ function genDevice(filepath) { }`; const dir = path.dirname(filepath); if (!fs.existsSync(dir)) - fs.mkdirSync(dir, {recursive: true, mode: 0o755}); + fs.mkdirSync(dir, { recursive: true, mode: 0o755 }); fs.writeFileSync(filepath, device); return JSON.parse(device); } @@ -78,38 +78,38 @@ function getDeviceInfo(filepath) { d = genDevice(filepath); } const device = { - display: d.android_id, - product: d.product, - device: d.device, - board: d.board, - brand: d.brand, - model: d.model, - bootloader: d.bootloader, - fingerprint: `${d.brand}/${d.product}/${d.device}:10/${d.android_id}/${d.incremental}:user/release-keys`, - boot_id: d.boot_id, + display: d.android_id, + product: d.product, + device: d.device, + board: d.board, + brand: d.brand, + model: d.model, + bootloader: d.bootloader, + fingerprint: `${d.brand}/${d.product}/${d.device}:10/${d.android_id}/${d.incremental}:user/release-keys`, + boot_id: d.boot_id, proc_version: d.proc_version, - baseband: "", - sim: "T-Mobile", - os_type: "android", - mac_address: d.mac_address, - ip_address: d.ip_address, - wifi_bssid: d.mac_address, - wifi_ssid: d.wifi_ssid, - imei: d.imei, - android_id: d.android_id, - apn: "wifi", + baseband: "", + sim: "T-Mobile", + os_type: "android", + mac_address: d.mac_address, + ip_address: d.ip_address, + wifi_bssid: d.mac_address, + wifi_ssid: d.wifi_ssid, + imei: d.imei, + android_id: d.android_id, + apn: "wifi", version: { incremental: d.incremental, - release: "10", - codename: "REL", - sdk: 29 + release: "10", + codename: "REL", + sdk: 29 } }; device.imsi = crypto.randomBytes(16); device.tgtgt = crypto.randomBytes(16); device.guid = md5(Buffer.concat([Buffer.from(device.imei), Buffer.from(device.mac_address)])); return device; -}; +} const apk = { //android phone @@ -141,18 +141,18 @@ const apk = { sigmap: 1970400, sdkver: "6.0.0.2433", } -} +}; //android watch -apk[3] = {...apk[1]}; +apk[3] = { ...apk[1] }; apk[3].subid = 537061176; //mac (experimental) -apk[4] = {...apk[2]}; +apk[4] = { ...apk[2] }; apk[4].subid = 537064315; //ipad (experimental) -apk[5] = {...apk[2]}; +apk[5] = { ...apk[2] }; apk[5].subid = 537065739; /** @@ -165,4 +165,4 @@ function getApkInfo(platform) { module.exports = { getDeviceInfo, getApkInfo -} +}; diff --git a/docs/demo.js b/docs/demo.js index e49caa81..ce5bcbb0 100644 --- a/docs/demo.js +++ b/docs/demo.js @@ -1,8 +1,8 @@ "use strict"; try { - var {createClient} = require("../client"); + var { createClient } = require("../client"); } catch { - var {createClient} = require("oicq"); + var { createClient } = require("oicq"); } // your account @@ -13,54 +13,54 @@ const bot = createClient(uin, { }); //监听并输入滑动验证码ticket(同一地点只需验证一次) -bot.on("system.login.slider", ()=>{ - process.stdin.once("data", (input)=>{ +bot.on("system.login.slider", () => { + process.stdin.once("data", (input) => { bot.sliderLogin(input); }); }); //监听设备锁验证(同一设备只需验证一次) -bot.on("system.login.device", ()=>{ - bot.logger.info("验证完成后敲击Enter继续..") - process.stdin.once("data", ()=>{ +bot.on("system.login.device", () => { + bot.logger.info("验证完成后敲击Enter继续.."); + process.stdin.once("data", () => { bot.login(); }); }); //监听上线事件 -bot.on("system.online", ()=>{ +bot.on("system.online", () => { console.log(`Logged in as ${bot.nickname}!`); }); //自动同意好友申请 -bot.on("request.friend.add", (data)=>{ +bot.on("request.friend.add", (data) => { bot.setFriendAddRequest(data.flag); }); //自动同意群邀请 -bot.on("request.group.invite", (data)=>{ +bot.on("request.group.invite", (data) => { bot.setGroupAddRequest(data.flag); }); //监听私聊 -bot.on("message.private", (data)=>{ +bot.on("message.private", (data) => { // console.log(data); bot.sendPrivateMsg(data.user_id, "hello"); }); //监听群聊 -bot.on("message.group", (data)=>{ +bot.on("message.group", (data) => { // console.log(data); bot.sendGroupMsg(data.group_id, "hello"); }); //监听群员入群事件 -bot.on("notice.group.increase", (data)=>{ +bot.on("notice.group.increase", (data) => { bot.sendGroupMsg(data.group_id, data.nickname + " 加入了群"); }); // login with your password or password_md5 -bot.login("password"); +bot.login("password"); //同一事件可以多次监听 //更多api和事件请参考文档或client.d.ts文件 diff --git a/exception.js b/exception.js index ee0232cb..98be406b 100644 --- a/exception.js +++ b/exception.js @@ -29,7 +29,7 @@ const exceptions = new Map([ }], ]); -class TimeoutError extends Error {} +class TimeoutError extends Error { } /** * @param {Function} fn @@ -45,7 +45,6 @@ function getErrorMessage(fn, code) { return e[code]; } - module.exports = { getErrorMessage, TimeoutError -} +}; diff --git a/lib/common.js b/lib/common.js index 8e837e12..b68b0d1d 100644 --- a/lib/common.js +++ b/lib/common.js @@ -4,13 +4,13 @@ const util = require("util"); const pb = require("./pb"); function uuid() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c)=>{ - const r = Math.random()*16|0, v = c === "x" ? r : (r&0x3|0x8); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = Math.random() * 16 | 0, v = c === "x" ? r : (r & 0x3 | 0x8); return v.toString(16); }); } -const timestamp = ()=>parseInt(Date.now()/1000); -const md5 = (data)=>crypto.createHash("md5").update(data).digest(); +const timestamp = () => parseInt(Date.now() / 1000); +const md5 = (data) => crypto.createHash("md5").update(data).digest(); function checkUin(uin) { return uin >= 10000 && uin <= 0xffffffff; @@ -64,15 +64,15 @@ function uin2code(groupUin) { } function log(any) { - console.log(util.inspect(any, {depth: 20, showHidden: false, maxArrayLength: 1000, maxStringLength: 5000})); + console.log(util.inspect(any, { depth: 20, showHidden: false, maxArrayLength: 1000, maxStringLength: 5000 })); } function genC2CMessageId(user_id, seq, random, time) { const buf = Buffer.allocUnsafe(16); - buf.writeUInt32BE(user_id), - buf.writeInt32BE(seq&0xffffffff, 4), - buf.writeInt32BE(random&0xffffffff, 8), - buf.writeUInt32BE(time, 12); + buf.writeUInt32BE(user_id); + buf.writeInt32BE(seq & 0xffffffff, 4); + buf.writeInt32BE(random & 0xffffffff, 8); + buf.writeUInt32BE(time, 12); return buf.toString("base64"); } function parseC2CMessageId(message_id) { @@ -81,16 +81,16 @@ function parseC2CMessageId(message_id) { seq = buf.readUInt32BE(4), random = buf.readUInt32BE(8), time = buf.readUInt32BE(12); - return {user_id, seq, random, time}; + return { user_id, seq, random, time }; } function genGroupMessageId(group_id, user_id, seq, random, time, pktnum = 1) { const buf = Buffer.allocUnsafe(21); - buf.writeUInt32BE(group_id), - buf.writeUInt32BE(user_id, 4), - buf.writeInt32BE(seq&0xffffffff, 8), - buf.writeInt32BE(random&0xffffffff, 12), - buf.writeUInt32BE(time, 16), - buf.writeUInt8(pktnum>1?pktnum:1, 20); + buf.writeUInt32BE(group_id); + buf.writeUInt32BE(user_id, 4); + buf.writeInt32BE(seq & 0xffffffff, 8); + buf.writeInt32BE(random & 0xffffffff, 12); + buf.writeUInt32BE(time, 16); + buf.writeUInt8(pktnum > 1 ? pktnum : 1, 20); return buf.toString("base64"); } function parseGroupMessageId(message_id) { @@ -101,7 +101,7 @@ function parseGroupMessageId(message_id) { random = buf.readUInt32BE(12), time = buf.readUInt32BE(16), pktnum = buf.length === 21 ? buf.readUInt8(20) : 1; - return {group_id, user_id, seq, random, time, pktnum}; + return { group_id, user_id, seq, random, time, pktnum }; } function genMessageUuid(random) { return 16777216n << 32n | BigInt(random); @@ -118,7 +118,7 @@ function parseFunString(buf) { if (v[2]) res += String(v[2].raw); } - } catch {} + } catch { } return res; } else { return String(buf); diff --git a/lib/core.js b/lib/core.js index 4f5f77b4..6a06f131 100644 --- a/lib/core.js +++ b/lib/core.js @@ -7,8 +7,8 @@ const Readable = require("stream").Readable; const common = require("./common"); const pb = require("./pb"); const jce = require("./jce"); -const {buildSyncCookie} = require("./message/chat"); -const {parsePrivateMsg} = require("./message/recv"); +const { buildSyncCookie } = require("./message/chat"); +const { parsePrivateMsg } = require("./message/recv"); const push = require("./online-push"); const sysmsg = require("./sysmsg"); const BUF0 = Buffer.alloc(0); @@ -26,11 +26,11 @@ function onPushReq(blob, seq) { null, parent[1], parent[3], parent[1] === 3 ? parent[2] : null ]); const extra = { - req_id: seq, + req_id: seq, service: "QQService.ConfigPushSvc.MainServant", - method: "PushResp", + method: "PushResp", }; - const body = jce.encodeWrapper({PushResp}, extra); + const body = jce.encodeWrapper({ PushResp }, extra); this.writeUNI("ConfigPushSvc.PushResp", body); } @@ -43,23 +43,23 @@ function onPushNotify(blob) { const nested = jce.decodeWrapper(blob.slice(15)); const parent = jce.decode(nested); switch (parent[5]) { - case 33: - case 141: - case 166: - case 167: - case 208: - case 529: - return getMsg.call(this); - case 84: - case 87: - case 525: - if (parent[5] === 525) { - this.lock525 = !this.lock525; - if (this.lock525) return; - } - return sysmsg.getNewGroup.call(this, parent[5]); - case 187: - return sysmsg.getNewFriend.call(this); + case 33: + case 141: + case 166: + case 167: + case 208: + case 529: + return getMsg.call(this); + case 84: + case 87: + case 525: + if (parent[5] === 525) { + this.lock525 = !this.lock525; + if (this.lock525) return; + } + return sysmsg.getNewGroup.call(this, parent[5]); + case 187: + return sysmsg.getNewFriend.call(this); } } @@ -112,7 +112,7 @@ async function getMsg(sync_flag = 0) { //群员入群 if (type === 33) { - (async()=>{ + (async () => { const group_id = common.uin2code(uin); const user_id = head[15]; const ginfo = (await this.getGroupInfo(group_id)).data; @@ -127,19 +127,19 @@ async function getMsg(sync_flag = 0) { try { if (this.gml.get(group_id).size) ginfo.member_count = this.gml.get(group_id).size; - } catch {} + } catch { } } this.em("notice.group.increase", { group_id, user_id, nickname: String(head[16].raw) }); })(); - } + } //私聊消息 else { ++this.stat.recv_msg_cnt; - (async()=>{ + (async () => { try { const m = await parsePrivateMsg.call(this, type, head, msg[2], msg[3]); if (m && m.raw_message) { @@ -155,7 +155,7 @@ async function getMsg(sync_flag = 0) { } if (items.length) { - this.writeUNI("MessageSvc.PbDeleteMsg", pb.encode({1:items})); + this.writeUNI("MessageSvc.PbDeleteMsg", pb.encode({ 1: items })); } if (rsp[4] !== 2) getMsg.call(this, rsp[4]); @@ -171,7 +171,7 @@ async function getMsg(sync_flag = 0) { * 强制下线通知(通常是被另一个相同端末挤掉了) */ function onForceOffline(blob) { - fs.unlink(path.join(this.dir, "token"), ()=>{}); + fs.unlink(path.join(this.dir, "token"), () => { }); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); this.em("internal.kickoff", { @@ -184,7 +184,7 @@ function onForceOffline(blob) { * 强制下线通知(通常是冻结等特殊事件) */ function onMSFOffline(blob) { - fs.unlink(path.join(this.dir, "token"), ()=>{}); + fs.unlink(path.join(this.dir, "token"), () => { }); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); // if (parent[3].includes("如非本人操作,则密码可能已泄露")) @@ -208,7 +208,7 @@ function onPushDomain(blob, seq) { } function parseSSO(buf) { - const stream = Readable.from(buf, {objectMode:false}); + const stream = Readable.from(buf, { objectMode: false }); stream.read(0); if (stream.read(4).readInt32BE() - 4 > stream.readableLength) { throw new Error("dropped"); @@ -220,7 +220,7 @@ function parseSSO(buf) { } stream.read(stream.read(4).readInt32BE() - 4); const cmd = stream.read(stream.read(4).readInt32BE() - 4).toString(); - const session_id = stream.read(stream.read(4).readInt32BE() - 4); //? + const session_id = stream.read(stream.read(4).readInt32BE() - 4); if (cmd === "Heartbeat.Alive") { return { seq, cmd, payload: BUF0 @@ -238,7 +238,7 @@ function parseSSO(buf) { } else if (compressed === 8) { payload = stream.read(); } else - throw new Error("unknown compressed flag: " + compressed) + throw new Error("unknown compressed flag: " + compressed); return { seq, cmd, payload }; @@ -252,7 +252,7 @@ const events = { "OnlinePush.PbC2CMsgSync": push.onC2CMsgSync, "ConfigPushSvc.PushReq": onPushReq, "MessageSvc.PushNotify": onPushNotify, - "MessageSvc.PushForceOffline": onForceOffline, + "MessageSvc.PushForceOffline": onForceOffline, "StatSvc.ReqMSFOffline": onMSFOffline, "QualityTest.PushList": onQualityTest, "OnlinePush.SidTicketExpired": onSidTicketExpired, @@ -270,7 +270,7 @@ const events = { * @param {Buffer} packet */ function parseIncomingPacket(packet) { - const stream = Readable.from(packet, {objectMode:false}); + const stream = Readable.from(packet, { objectMode: false }); const flag1 = stream.read(4).readInt32BE(); if (flag1 !== 0x0A && flag1 !== 0x0B) throw new Error("decrypt failed"); @@ -281,16 +281,16 @@ function parseIncomingPacket(packet) { stream.read(stream.read(4).readInt32BE() - 4); let decrypted = stream.read(); switch (flag2) { - case 0: - break; - case 1: - decrypted = tea.decrypt(decrypted, this.sig.d2key); - break; - case 2: - decrypted = tea.decrypt(decrypted, Buffer.alloc(16)); - break; - default: - throw new Error("decrypt failed"); + case 0: + break; + case 1: + decrypted = tea.decrypt(decrypted, this.sig.d2key); + break; + case 2: + decrypted = tea.decrypt(decrypted, Buffer.alloc(16)); + break; + default: + throw new Error("decrypt failed"); } const sso = parseSSO(decrypted); this.logger.trace(`recv:${sso.cmd} seq:${sso.seq}`); diff --git a/lib/friendlist.js b/lib/friendlist.js index 5ca344a7..a319452a 100644 --- a/lib/friendlist.js +++ b/lib/friendlist.js @@ -4,13 +4,13 @@ const pb = require("./pb"); const jce = require("./jce"); const friend_sex_map = { - "0":"unknown", "1":"male", "2":"female" + "0": "unknown", "1": "male", "2": "female" }; const group_sex_map = { - "-1":"unknown", "0":"male", "1":"female" + "-1": "unknown", "0": "male", "1": "female" }; const group_role_map = { - "1":"member", "2":"admin", "3":"owner" + "1": "member", "2": "admin", "3": "owner" }; /** @@ -21,8 +21,8 @@ const group_role_map = { */ async function _initFL(start, limit) { const d50 = pb.encode({ - 1: 10002, - 91001: 1, + 1: 10002, + 91001: 1, 101001: 1, 151001: 1, 181001: 1, @@ -34,24 +34,24 @@ async function _initFL(start, limit) { 31, null, 0, 0, 0, d50, null, [13580, 13581, 13582] ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "GetFriendListReq", + method: "GetFriendListReq", }; - const body = jce.encodeWrapper({FL}, extra); + const body = jce.encodeWrapper({ FL }, extra); const blob = await this.sendUNI("friendlist.getFriendGroupList", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); for (let v of parent[7]) { v = jce.decode(v); this.fl.set(v[0], { - user_id: v[0], - nickname: v[14], - sex: friend_sex_map[v[31]], - age: 0, - area: "unknown", - remark: v[3], - }) + user_id: v[0], + nickname: v[14], + sex: friend_sex_map[v[31]], + age: 0, + area: "unknown", + remark: v[3], + }); } return parent[5]; } @@ -73,10 +73,10 @@ async function initFL() { } catch (e) { this.logger.debug(e); this.logger.warn("加载好友列表出现异常,未加载完成。"); - return {result: -1}; + return { result: -1 }; } } - return {result: 0}; + return { result: 0 }; } /** @@ -90,11 +90,11 @@ async function initGL() { this.uin, 0, null, [], 1, 8, 0, 1, 1 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "GetTroopListReqV2Simplify", + method: "GetTroopListReqV2Simplify", }; - const body = jce.encodeWrapper({GetTroopListReqV2Simplify}, extra); + const body = jce.encodeWrapper({ GetTroopListReqV2Simplify }, extra); try { const blob = await this.sendUNI("friendlist.GetTroopListReqV2", body); const nested = jce.decodeWrapper(blob); @@ -103,28 +103,28 @@ async function initGL() { for (let v of parent[5]) { v = jce.decode(v); this.gl.set(v[1], { - group_id: v[1], - group_name: v[4], - member_count: v[19], - max_member_count: v[29], - owner_id: v[23], - last_join_time: v[27], - last_sent_time: 0, - shutup_time_whole: v[9]?0xffffffff:0, - shutup_time_me: v[10]*1000>Date.now()?v[10]:0, - create_time: 0, - grade: 0, - max_admin_count: 0, - active_member_count:0, - update_time: 0, + group_id: v[1], + group_name: v[4], + member_count: v[19], + max_member_count: v[29], + owner_id: v[23], + last_join_time: v[27], + last_sent_time: 0, + shutup_time_whole: v[9] ? 0xffffffff : 0, + shutup_time_me: v[10] * 1000 > Date.now() ? v[10] : 0, + create_time: 0, + grade: 0, + max_admin_count: 0, + active_member_count: 0, + update_time: 0, }); } } catch (e) { this.logger.debug(e); this.logger.warn("加载群列表出现异常,未加载完成。"); - return {result: -1}; + return { result: -1 }; } - return {result: 0}; + return { result: 0 }; } /** @@ -135,11 +135,11 @@ async function __getGML(group_id, next_uin) { this.uin, group_id, next_uin, common.code2uin(group_id), 2, 0, 0, 0 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "GetTroopMemberListReq", + method: "GetTroopMemberListReq", }; - const body = jce.encodeWrapper({GTML}, extra); + const body = jce.encodeWrapper({ GTML }, extra); const blob = await this.sendUNI("friendlist.GetTroopMemberListReq", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); @@ -147,31 +147,31 @@ async function __getGML(group_id, next_uin) { for (let v of parent[3]) { v = jce.decode(v); map.set(v[0], { - group_id: group_id, - user_id: v[0], - nickname: v[4], - card: v[8], - sex: group_sex_map[v[3]], - age: v[2], - area: "unknown", - join_time: v[15], - last_sent_time: v[16], - level: v[14], - rank: "", - role: v[18] ? "admin" : "member", - unfriendly: false, - title: v[23], - title_expire_time: v[24]&0xffffffff, - card_changeable: true, - shutup_time: v[30]*1000>Date.now()?v[30]:0, - update_time: 0, + group_id: group_id, + user_id: v[0], + nickname: v[4], + card: v[8], + sex: group_sex_map[v[3]], + age: v[2], + area: "unknown", + join_time: v[15], + last_sent_time: v[16], + level: v[14], + rank: "", + role: v[18] ? "admin" : "member", + unfriendly: false, + title: v[23], + title_expire_time: v[24] & 0xffffffff, + card_changeable: true, + shutup_time: v[30] * 1000 > Date.now() ? v[30] : 0, + update_time: 0, }); } try { const owner = this.gl.get(group_id).owner_id; map.get(owner).role = "owner"; - } catch (e) {} - return {map, next}; + } catch (e) { } + return { map, next }; } /** * @this {import("./ref").Client} @@ -181,11 +181,11 @@ async function _getGML(group_id) { try { var next = 0; while (1) { - var {map, next} = await __getGML.call(this, group_id, next); + var { map, next } = await __getGML.call(this, group_id, next); mlist = new Map([...mlist, ...map]); if (!next) break; } - } catch (e) {} + } catch (e) { } if (!mlist.size) { this.gml.delete(group_id); return null; @@ -200,7 +200,7 @@ async function _getGML(group_id) { * @returns {import("./ref").ProtocolResponse} */ async function getGML(group_id, no_cache = false) { - var [group_id] = common.uinAutoCheck(group_id); + [group_id] = common.uinAutoCheck(group_id); let mlist = this.gml.get(group_id); if (!mlist || (no_cache && mlist instanceof Map)) { mlist = _getGML.call(this, group_id); @@ -209,8 +209,8 @@ async function getGML(group_id, no_cache = false) { if (mlist instanceof Promise) mlist = await mlist; if (mlist) - return {result: 0, data: mlist}; - return {result: -1, emsg: "未加入的群"}; + return { result: 0, data: mlist }; + return { result: -1, emsg: "未加入的群" }; } const gi_buf = pb.encode({ @@ -235,11 +235,11 @@ const gi_buf = pb.encode({ * @returns {import("./ref").ProtocolResponse} */ async function getGI(group_id, no_cache = false) { - var [group_id] = common.uinAutoCheck(group_id); + [group_id] = common.uinAutoCheck(group_id); let ginfo = this.gl.get(group_id); if (!no_cache && ginfo && common.timestamp() - ginfo.update_time <= 3600) - return {result: 0, data: ginfo}; + return { result: 0, data: ginfo }; const body = pb.encode({ 1: this.apk.subid, @@ -250,32 +250,32 @@ async function getGI(group_id, no_cache = false) { }); try { this.gl.get(group_id).update_time = common.timestamp(); - } catch (e) {} + } catch (e) { } const blob = await this.sendUNI("OidbSvc.0x88d_0", body); - const o = pb.decode(blob)[4][1][3]; + const o = pb.decode(blob)[4][1][3]; if (!o) { this.gl.delete(group_id); this.gml.delete(group_id); - return {result: -1, emsg: "未加入的群"}; + return { result: -1, emsg: "未加入的群" }; } ginfo = { - group_id: group_id, - group_name: o[89] ? String(o[89].raw) : String(o[15].raw), - member_count: o[6], - max_member_count: o[5], - owner_id: o[1], - last_join_time: o[49], - last_sent_time: o[54], - shutup_time_whole: o[45] ? 0xffffffff : 0, - shutup_time_me: o[46]*1000 > Date.now() ? o[46] : 0, - create_time: o[2], - grade: o[36], - max_admin_count: o[29], - active_member_count:o[37], - update_time: common.timestamp(), + group_id: group_id, + group_name: o[89] ? String(o[89].raw) : String(o[15].raw), + member_count: o[6], + max_member_count: o[5], + owner_id: o[1], + last_join_time: o[49], + last_sent_time: o[54], + shutup_time_whole: o[45] ? 0xffffffff : 0, + shutup_time_me: o[46] * 1000 > Date.now() ? o[46] : 0, + create_time: o[2], + grade: o[36], + max_admin_count: o[29], + active_member_count: o[37], + update_time: common.timestamp(), }; this.gl.set(group_id, ginfo); - return {result: 0, data: ginfo}; + return { result: 0, data: ginfo }; } /** @@ -284,15 +284,15 @@ async function getGI(group_id, no_cache = false) { * @returns {import("./ref").ProtocolResponse} */ async function getGMI(group_id, user_id, no_cache = false) { - var [group_id, user_id] = common.uinAutoCheck(group_id, user_id); + [group_id, user_id] = common.uinAutoCheck(group_id, user_id); if (!this.gml.has(group_id)) this.getGroupMemberList(group_id); let minfo; try { minfo = this.gml.get(group_id).get(user_id); - } catch (e) {} + } catch (e) { } if (!no_cache && minfo && common.timestamp() - minfo.update_time <= 3600) - return {result: 0, data: minfo}; + return { result: 0, data: minfo }; const body = pb.encode({ 1: group_id, @@ -303,44 +303,44 @@ async function getGMI(group_id, user_id, no_cache = false) { }); try { this.gml.get(group_id).get(user_id).update_time = common.timestamp(); - } catch (e) {} + } catch (e) { } const blob = await this.sendUNI("group_member_card.get_group_member_card_info", body); const o = pb.decode(blob)[3]; if (!o[27]) { try { this.gml.get(group_id).delete(user_id); - } catch (e) {} - return {result: -1, emsg: "幽灵群员"}; - }; + } catch (e) { } + return { result: -1, emsg: "幽灵群员" }; + } if (o[9] === undefined) o[9] = -1; const card = common.parseFunString(o[8].raw); minfo = { - group_id: group_id, - user_id: user_id, - nickname: String(o[11].raw), - card: card, - sex: Reflect.has(o, "9") ? group_sex_map[o[9]&0xffffffff] : "unknown", - age: o[12], - area: Reflect.has(o, "10") ? String(o[10].raw) : "unknown", - join_time: o[14], - last_sent_time: o[15], - level: o[39], - rank: Reflect.has(o, "13") ? String(o[13].raw) : undefined, - role: group_role_map[o[27]], - unfriendly: false, - title: Reflect.has(o, "31") ? String(o[31].raw) : "", - title_expire_time: Reflect.has(o, "32") ? o[32] : 0xffffffff, - card_changeable: true, - shutup_time: 0, - update_time: common.timestamp(), + group_id: group_id, + user_id: user_id, + nickname: String(o[11].raw), + card: card, + sex: Reflect.has(o, "9") ? group_sex_map[o[9] & 0xffffffff] : "unknown", + age: o[12], + area: Reflect.has(o, "10") ? String(o[10].raw) : "unknown", + join_time: o[14], + last_sent_time: o[15], + level: o[39], + rank: Reflect.has(o, "13") ? String(o[13].raw) : undefined, + role: group_role_map[o[27]], + unfriendly: false, + title: Reflect.has(o, "31") ? String(o[31].raw) : "", + title_expire_time: Reflect.has(o, "32") ? o[32] : 0xffffffff, + card_changeable: true, + shutup_time: 0, + update_time: common.timestamp(), }; try { try { minfo.shutup_time = this.gml.get(group_id).get(user_id).shutup_time; - } catch (e) {} + } catch (e) { } this.gml.get(group_id).set(user_id, minfo); - } catch (e) {} - return {result: 0, data: minfo}; + } catch (e) { } + return { result: 0, data: minfo }; } /** @@ -349,34 +349,34 @@ async function getGMI(group_id, user_id, no_cache = false) { * @returns {import("./ref").ProtocolResponse} */ async function getSI(user_id, no_cache = false) { - var [user_id] = common.uinAutoCheck(user_id); + [user_id] = common.uinAutoCheck(user_id); let user = this.sl.get(user_id); if (!no_cache && user) - return {result: 0, data: user}; + return { result: 0, data: user }; const arr = [ null, - 0, "", [user_id], 1,1,0,0,0,1,0,1 + 0, "", [user_id], 1, 1, 0, 0, 0, 1, 0, 1 ]; arr[101] = 1; const req = jce.encodeStruct(arr); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "KQQ.ProfileService.ProfileServantObj", - method: "GetSimpleInfo", + method: "GetSimpleInfo", }; - const body = jce.encodeWrapper({req}, extra); + const body = jce.encodeWrapper({ req }, extra); const blob = await this.sendUNI("ProfileService.GetSimpleInfo", body); const nested = jce.decodeWrapper(blob); for (let v of nested) { v = jce.decode(v); - const area = (v[13]+" "+v[14]+" "+v[15]).trim(); + const area = (v[13] + " " + v[14] + " " + v[15]).trim(); const user = { user_id: v[1], nickname: v[5], sex: group_sex_map[v[3]], age: v[4], - area: area?area:"unknown", + area: area ? area : "unknown", }; let o = this.fl.get(v[1]); if (!o) @@ -388,9 +388,9 @@ async function getSI(user_id, no_cache = false) { if (user.age) o.age = user.age; } - return {result: 0, data: user}; + return { result: 0, data: user }; } - return {result: -1, emsg: "没有这个人"}; + return { result: -1, emsg: "没有这个人" }; } /** @@ -399,7 +399,7 @@ async function getSI(user_id, no_cache = false) { * @returns {import("./ref").ProtocolResponse} */ async function getGAL(group_id) { - var [group_id] = common.uinAutoCheck(group_id); + [group_id] = common.uinAutoCheck(group_id); const body = pb.encode({ 1: group_id, 2: 0, @@ -417,9 +417,9 @@ async function getGAL(group_id) { rsp[4][4] = [rsp[4][4]]; for (let v of rsp[4][4]) data.push(v[1]); - return {result, data}; + return { result, data }; } else { - return {result, emsg: rsp[4][5] ? String(rsp[4][5].raw).trim() : ""}; + return { result, emsg: rsp[4][5] ? String(rsp[4][5].raw).trim() : "" }; } } diff --git a/lib/individual.js b/lib/individual.js index 47e03d63..f3ec8aef 100644 --- a/lib/individual.js +++ b/lib/individual.js @@ -1,7 +1,7 @@ "use strict"; const http = require("http"); -const {uinAutoCheck, md5} = require("./common"); -const {downloadWebImage, highwayUpload, readFile} = require("./service"); +const { uinAutoCheck, md5 } = require("./common"); +const { downloadWebImage, highwayUpload, readFile } = require("./service"); const pb = require("./pb"); const jce = require("./jce"); @@ -12,7 +12,7 @@ const jce = require("./jce"); async function getImgBuf(file) { let buf; if (file instanceof Buffer) { - buf = file; + buf = file; } else { file = String(file).trim(); if (file.startsWith("base64://")) { @@ -49,7 +49,7 @@ async function setPortrait(file) { await highwayUpload.call(this, rsp[3][2][0][2], rsp[3][2][0][3], { buf, md5: md5(buf), key: rsp[1].raw }, 5); - return {result: 0}; + return { result: 0 }; } /** @@ -58,22 +58,22 @@ async function setPortrait(file) { * @param {String|Buffer} file */ async function setGroupPortrait(group_id, file) { - var [group_id] = uinAutoCheck(group_id); + [group_id] = uinAutoCheck(group_id); const buf = await getImgBuf(file); await this.getCookies(); const url = `http://htdata3.qq.com/cgi-bin/httpconn?htcmd=0x6ff0072&ver=5520&ukey=${this.sig.skey}&range=0&uin=${this.uin}&seq=${this.seq_id}&groupuin=${group_id}&filetype=3&imagetype=5&userdata=0&subcmd=1&subver=101&clip=0_0_0_0&filesize=${buf.length}`; try { - await new Promise((resolve, reject)=>{ - http.request(url, {method:"POST"}, (res)=>{ + await new Promise((resolve, reject) => { + http.request(url, { method: "POST" }, (res) => { if (res.statusCode === 200) resolve(); else reject(); - }).on("error", (e)=>reject(e.message)).end(buf); + }).on("error", (e) => reject(e.message)).end(buf); }); - return {result: 0}; + return { result: 0 }; } catch (e) { - return {result: 102, emsg: e}; + return { result: 102, emsg: e }; } } @@ -84,7 +84,7 @@ async function setGroupPortrait(group_id, file) { * @returns {import("./ref").ProtocolResponse} */ async function sendLike(user_id, times = 1) { - var [user_id] = uinAutoCheck(user_id); + [user_id] = uinAutoCheck(user_id); times = parseInt(times); if (!(times > 0 && times <= 20)) times = 1; @@ -95,15 +95,15 @@ async function sendLike(user_id, times = 1) { user_id, 0, 1, times ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "VisitorSvc", - method: "ReqFavorite", + method: "ReqFavorite", }; - const body = jce.encodeWrapper({ReqFavorite}, extra); + const body = jce.encodeWrapper({ ReqFavorite }, extra); const blob = await this.sendUNI("VisitorSvc.ReqFavorite", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); - return {result: jce.decode(parent[0])[3]}; + return { result: jce.decode(parent[0])[3] }; } /** @@ -118,11 +118,11 @@ async function getAddSetting(user_id) { user_id, 3004, 0, null, 1 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "GetUserAddFriendSettingReq", + method: "GetUserAddFriendSettingReq", }; - const body = jce.encodeWrapper({FS}, extra); + const body = jce.encodeWrapper({ FS }, extra); const blob = await this.sendUNI("friendlist.getUserAddFriendSetting", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); @@ -140,28 +140,29 @@ async function getAddSetting(user_id) { async function addFriend(group_id, user_id, comment = "") { if (group_id == 0) { group_id = 0; - var [user_id] = uinAutoCheck(user_id); - } else - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [user_id] = uinAutoCheck(user_id); + } else { + [group_id, user_id] = uinAutoCheck(group_id, user_id); + } const type = await getAddSetting.call(this, user_id); if (![0, 1, 4].includes(type)) - return {result: type}; + return { result: type }; comment = String(comment); const AF = jce.encodeStruct([ this.uin, - user_id, type?1:0, 1, 0, Buffer.byteLength(comment), comment, 0, 1, null, 3004, - 11, null, null, group_id?pb.encode({1:group_id}):null, 0, null, null, 0 + user_id, type ? 1 : 0, 1, 0, Buffer.byteLength(comment), comment, 0, 1, null, 3004, + 11, null, null, group_id ? pb.encode({ 1: group_id }) : null, 0, null, null, 0 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "AddFriendReq", + method: "AddFriendReq", }; - const body = jce.encodeWrapper({AF}, extra); + const body = jce.encodeWrapper({ AF }, extra); const blob = await this.sendUNI("friendlist.addFriend", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); - return {result: parent[6]}; + return { result: parent[6] }; } /** @@ -171,21 +172,21 @@ async function addFriend(group_id, user_id, comment = "") { * @returns {import("./ref").ProtocolResponse} */ async function delFriend(user_id, block = true) { - var [user_id] = uinAutoCheck(user_id); + [user_id] = uinAutoCheck(user_id); const DF = jce.encodeStruct([ this.uin, - user_id, 2, block?1:0 + user_id, 2, block ? 1 : 0 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "DelFriendReq", + method: "DelFriendReq", }; - const body = jce.encodeWrapper({DF}, extra); + const body = jce.encodeWrapper({ DF }, extra); const blob = await this.sendUNI("friendlist.delFriend", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); - return {result: parent[2]}; + return { result: parent[2] }; } /** @@ -205,7 +206,7 @@ async function setProfile(k, v) { const o = pb.decode(blob); if (o[3] === 34) o[3] = 0; - return {result: o[3]}; + return { result: o[3] }; } /** @@ -221,7 +222,7 @@ async function setSign(sign = "") { 2: Date.now(), 3: { 1: 109, - 2: {6: 825110830}, + 2: { 6: 825110830 }, 3: this.apk.ver }, 5: { @@ -229,8 +230,8 @@ async function setSign(sign = "") { 2: 0, 3: 27 + sign.length, 4: Buffer.concat([ - Buffer.from([0x3, sign.length+1, 0x20]), sign, - Buffer.from([0x91,0x04,0x00,0x00,0x00,0x00,0x92,0x04,0x00,0x00,0x00,0x00,0xA2,0x04,0x00,0x00,0x00,0x00,0xA3,0x04,0x00,0x00,0x00,0x00]) + Buffer.from([0x3, sign.length + 1, 0x20]), sign, + Buffer.from([0x91, 0x04, 0x00, 0x00, 0x00, 0x00, 0x92, 0x04, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x04, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x04, 0x00, 0x00, 0x00, 0x00]) ]), 5: 0 }, @@ -238,7 +239,7 @@ async function setSign(sign = "") { }); const blob = await this.sendUNI("Signature.auth", body); const rsp = pb.decode(blob); - return {result: rsp[1], emsg: rsp[2]}; + return { result: rsp[1], emsg: rsp[2] }; } /** @@ -263,11 +264,11 @@ async function setStatus(status) { "", "", null, 1, null, 0, null, sub, 0 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "PushService", - method: "SvcReqRegister", + method: "SvcReqRegister", }; - const body = jce.encodeWrapper({SvcReqRegister}, extra); + const body = jce.encodeWrapper({ SvcReqRegister }, extra); const blob = await this.sendUNI("StatSvc.SetStatusFromClient", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); @@ -276,7 +277,7 @@ async function setStatus(status) { result = 0; this.online_status = status; } - return {result}; + return { result }; } module.exports = { diff --git a/lib/jce.js b/lib/jce.js index 3fc85b12..c72c279e 100644 --- a/lib/jce.js +++ b/lib/jce.js @@ -1,16 +1,16 @@ "use strict"; const jce = require("jce"); const WRAPPER = { - version: 1, + version: 1, pkt_type: 2, msg_type: 3, - req_id: 4, - service: 5, - method: 6, - payload: 7, - timeout: 8, - context: 9, - status: 10, + req_id: 4, + service: 5, + method: 6, + payload: 7, + timeout: 8, + context: 9, + status: 10, }; /** @@ -31,16 +31,16 @@ function decodeWrapper(blob) { */ function encodeWrapper(map, extra) { const body = { - version: 3, + version: 3, pkt_type: 0, msg_type: 0, - req_id: 0, - service: "", - method: "", - payload: jce.encode([map]), - timeout: 0, - context: {}, - status: {}, + req_id: 0, + service: "", + method: "", + payload: jce.encode([map]), + timeout: 0, + context: {}, + status: {}, ...extra }; return jce.encode(body, WRAPPER); diff --git a/lib/message/builder.js b/lib/message/builder.js index 0a0df36f..19cf778b 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -4,15 +4,15 @@ const fs = require("fs"); const path = require("path"); const http = require("http"); const querystring = require("querystring"); -const {exec} = require("child_process"); +const { exec } = require("child_process"); const music = require("./music"); const face = require("./face"); -const {getC2CMsg, getGroupMsg} = require("./history"); -const {downloadWebRecord, int32ip2str, readFile} = require("../service"); -const {ImageBuilder, uploadImages} = require("./image"); +const { getC2CMsg, getGroupMsg } = require("./history"); +const { downloadWebRecord, int32ip2str, readFile } = require("../service"); +const { ImageBuilder, uploadImages } = require("./image"); const pb = require("../pb"); const common = require("../common"); -const {parseC2CMessageId, parseGroupMessageId, genMessageUuid} = common; +const { parseC2CMessageId, parseGroupMessageId, genMessageUuid } = common; const EMOJI_NOT_ENDING = ["\uD83C", "\uD83D", "\uD83E", "\u200D"]; const EMOJI_NOT_STARTING = ["\uFE0F", "\u200D", "\u20E3"]; @@ -28,11 +28,11 @@ function unescapeCQInside(s) { if (s === "&") return "&"; } function escapeXml(str) { - return str.replace(/[&"><]/g, function(s) { + return str.replace(/[&"><]/g, function (s) { if (s === "&") return "&"; if (s === "<") return "<"; if (s === ">") return ">"; - if (s === '"') return """; + if (s === "\"") return """; }); } @@ -53,11 +53,11 @@ async function getAnonInfo(group_id) { const rsp = pb.decode(blob)[11]; if (!rsp[10][1]) anon = rsp; - } catch {} + } catch { } return anon; } -const AT_BUF = Buffer.from([0,1,0,0,0]); +const AT_BUF = Buffer.from([0, 1, 0, 0, 0]); const BUF1 = Buffer.from([1]); const BUF2 = Buffer.alloc(2); const FACE_OLD_BUF = Buffer.from([0x00, 0x01, 0x00, 0x04, 0x52, 0xCC, 0xF5, 0xD0]); @@ -105,14 +105,14 @@ class Builder { n = m; if (text.length > n) { // emoji切割问题 - while (EMOJI_NOT_ENDING.includes(chunk[chunk.length-1]) && text[n]) { + while (EMOJI_NOT_ENDING.includes(chunk[chunk.length - 1]) && text[n]) { chunk += text[n]; ++n; } while (EMOJI_NOT_STARTING.includes(text[n])) { chunk += text[n]; ++n; - while (EMOJI_NOT_ENDING.includes(chunk[chunk.length-1]) && text[n]) { + while (EMOJI_NOT_ENDING.includes(chunk[chunk.length - 1]) && text[n]) { chunk += text[n]; ++n; } @@ -129,7 +129,7 @@ class Builder { } } buildAtElem(cq) { - let {qq, text, dummy} = cq; + let { qq, text, dummy } = cq; if (qq === "all") { var q = 0, flag = 1, display = "@全体成员"; } else { @@ -138,8 +138,8 @@ class Builder { try { const member = this.c.gml.get(this.target).get(q); display = member.card ? member.card : member.nickname; - display = "@" + display - } catch (e) {} + display = "@" + display; + } catch (e) { } } } if (["1", "true", "yes"].includes(String(dummy)) || (!common.checkUin(q) && qq !== "all")) { @@ -154,7 +154,7 @@ class Builder { ++this.stat.at_cnt; } buildFaceElem(cq) { - let {id, text} = cq; + let { id, text } = cq; id = parseInt(id); if (id < 0 || id > 0xffff || isNaN(id)) return this.c.logger.warn("不正确的表情ID:" + id); @@ -189,7 +189,7 @@ class Builder { } } buildSFaceElem(cq) { - let {id, text} = cq; + let { id, text } = cq; if (!text) text = id; text = "[" + text + "]"; @@ -205,9 +205,9 @@ class Builder { } buildBFaceElem(cq) { try { - let {file, text} = cq; + var { file, text } = cq; if (!text) text = "原创表情"; - text = "["+String(text).slice(0, 5)+"]"; + text = "[" + String(text).slice(0, 5) + "]"; const o = { 1: text, 2: 6, @@ -222,7 +222,7 @@ class Builder { }; if (cq.magic && cq.magic instanceof Buffer) o[12] = cq.magic; - this.elems.push({6: o}); + this.elems.push({ 6: o }); ++this.stat.bface_cnt; this.buildTextElem(text); } catch { @@ -230,7 +230,7 @@ class Builder { } } buildMagicFaceElem(type, cq) { - const rand = (a,b)=>Math.floor(Math.random()*(b-a)+a); + const rand = (a, b) => Math.floor(Math.random() * (b - a) + a); if (type === "dice") { cq.text = "骰子"; const id = (cq.id >= 1 && cq.id <= 6) ? (cq.id - 1) : rand(0, 6); @@ -257,7 +257,7 @@ class Builder { const elem = { 53: { 1: 3, - 2: this.type ? {1:img.nested} : {2:img.nested}, + 2: this.type ? { 1: img.nested } : { 2: img.nested }, 3: 0, } }; @@ -270,7 +270,7 @@ class Builder { } ]); } else { - const elem = this.type ? {8:img.nested} : {4:img.nested}; + const elem = this.type ? { 8: img.nested } : { 4: img.nested }; ++this.stat.img_cnt; this.elems.push(elem); } @@ -281,23 +281,23 @@ class Builder { } async buildPttElem(cq) { - let {file, cache, timeout, proxy, headers} = cq; + let { file, cache, timeout, proxy, headers } = cq; if (!file) - return this.c.logger.warn(`file不是有效的音频。`); + return this.c.logger.warn("file不是有效的音频。"); let buf, md5, size, codec, url; try { if (file instanceof Buffer || file instanceof Uint8Array) { - return this.c.logger.warn(`音频暂不支持传递Buffer。`); + return this.c.logger.warn("音频暂不支持传递Buffer。"); } file = String(file).trim().replace(/^file:\/{2,3}/, ""); url = file; - const cache_filename = common.md5(Buffer.from(file, "utf-8")).toString('hex'); + const cache_filename = common.md5(Buffer.from(file, "utf-8")).toString("hex"); const cache_filepath = path.join(this.c.dir, "..", "record", cache_filename); if (!["0", "false", "no"].includes(String(cache))) { try { buf = await fs.promises.readFile(cache_filepath); this.c.logger.debug("使用缓存的amr音频文件"); - } catch (e) {} + } catch (e) { } } if (!buf) { if (file.startsWith("http")) { @@ -321,7 +321,7 @@ class Builder { try { const target = this.type === 1 ? this.target : 1; var fid = await uploadPtt.call(this.c, target, buf, md5, codec); - } catch(e) { + } catch (e) { this.c.logger.debug(e); return this.c.logger.debug("语音上传失败"); } @@ -340,35 +340,35 @@ class Builder { } buildLocationElem(cq) { - let {address, lat, lng, name, id, lon, title, content} = cq; + let { address, lat, lng, name, id, lon, title, content } = cq; if (!lng) lng = lon; if (!address) address = title; if (!name) name = content; if (!address || !lat || !lng) { return this.c.logger.warn("位置分享需要address和lat和lng"); - }; + } name = name ? name : "位置分享"; let obj = { - config: { forward: true, type: 'card', autosize: true }, - prompt: '[应用]地图', + config: { forward: true, type: "card", autosize: true }, + prompt: "[应用]地图", from: 1, - app: 'com.tencent.map', - ver: '1.0.3.5', - view: 'LocationShare', + app: "com.tencent.map", + ver: "1.0.3.5", + view: "LocationShare", meta: { - 'Location.Search': { - from: 'plusPanel', - id: id?id:"", + "Location.Search": { + from: "plusPanel", + id: id ? id : "", lat, lng, name, address } }, - desc: '地图' + desc: "地图" }; this.buildJsonElem(obj, "收到[[应用]地图]消息,请升级QQ版本查看"); } async buildMusicElem(cq) { - const {type, id} = cq; + const { type, id } = cq; try { const buf = await music.build(this.target, type, id, this.type); this.b77.push(buf); @@ -379,7 +379,7 @@ class Builder { } buildShareElem(cq) { - let {url, title, content, image} = cq; + let { url, title, content, image } = cq; if (!url || !title) { return this.c.logger.warn("分享需要title和url"); } @@ -387,7 +387,7 @@ class Builder { title = title.substr(0, 25) + "…"; title = escapeXml(title); const xml = ` - ${image?``:""}${title}${content?escapeXml(content):title}`; + ${image ? `` : ""}${title}${content ? escapeXml(content) : title}`; this.buildXmlElem(xml, 1, url); } @@ -404,7 +404,7 @@ class Builder { 1: { 1: String(text), } - }) + }); } this.jsons.push(elems); } @@ -421,7 +421,7 @@ class Builder { 1: { 1: String(text), } - }) + }); } this.xmls.push(elems); } @@ -433,7 +433,7 @@ class Builder { this.anon = null; return this.c.logger.warn("非群消息无法匿名"); } - const {ignore} = cq; + const { ignore } = cq; const rsp = await getAnonInfo.call(this.c, this.target); if (!rsp) { if (["0", "false", "no"].includes(String(ignore))) { @@ -458,7 +458,7 @@ class Builder { async buildReplyElem(cq) { if (this.reply) return; - var {id} = cq; + var { id } = cq; var source = [{ 1: { 1: "[消息]" @@ -466,14 +466,14 @@ class Builder { }]; try { if (this.type) - var {user_id, seq, random, time} = parseGroupMessageId(id); + var { user_id, seq, random, time } = parseGroupMessageId(id); else - var {user_id, seq, random, time} = parseC2CMessageId(id); + var { user_id, seq, random, time } = parseC2CMessageId(id); } catch { return this.c.logger.warn("incorrect reply id: " + id); } try { - var msg = await (this.type?getGroupMsg:getC2CMsg).call(this.c, id); + var msg = await (this.type ? getGroupMsg : getC2CMsg).call(this.c, id); source = msg[3][1][2]; if (Array.isArray(source)) { const bufs = []; @@ -514,7 +514,7 @@ class Builder { ++this.stat.length; } buildPokeElem(cq) { - let {type} = cq; + let { type } = cq; type = parseInt(type); if (!(type >= 0 && type <= 6)) return this.c.logger.warn("不正确的poke type (只支持0-6)"); @@ -522,7 +522,7 @@ class Builder { 3: 0, 7: 0, 10: 0, - } + }; this.elems.push({ 53: { 1: 2, @@ -534,12 +534,12 @@ class Builder { } buildNodeElem(cq) { - const {id} = cq; - const task = (async()=>{ + const { id } = cq; + const task = (async () => { try { this.nodes.push(null); const index = this.nodes.length - 1; - const msg = await (id.length>24?getGroupMsg:getC2CMsg).call(this.c, id); + const msg = await (id.length > 24 ? getGroupMsg : getC2CMsg).call(this.c, id); this.nodes[index] = msg.raw; } catch { this.c.logger.warn("获取消息节点失败,message_id: " + id); @@ -555,70 +555,70 @@ class Builder { if (!data) data = {}; switch (type) { - case "text": - this.buildTextElem(data.text); - break; - case "at": - this.buildAtElem(data); - break; - case "face": - this.buildFaceElem(data); - break; - case "sface": - this.buildSFaceElem(data); - break; - case "bface": - this.buildBFaceElem(data); - break; - case "dice": - case "rps": - this.buildMagicFaceElem(type, data) - break; - case "image": - await this.buildImageElem(data); - break; - case "flash": - data.type = "flash"; - await this.buildImageElem(data); - break; - case "record": - await this.buildPttElem(data); - break; - case "location": - this.buildLocationElem(data); - break; - case "music": - await this.buildMusicElem(data); - break; - case "share": - this.buildShareElem(data); - break; - case "anonymous": - await this.buildAnonElem(data) - break; - case "reply": - await this.buildReplyElem(data); - break; - case "shake": - this.buildShakeElem(); - break; - case "poke": - this.buildPokeElem(data); - break; - case "json": - if (data.data) - this.buildJsonElem(data.data, data.text); - break; - case "xml": - if (data.data) - this.buildXmlElem(data.data, data.type, data.text); - break; - case "node": - this.buildNodeElem(data); - break; - default: - this.c.logger.warn("未知的元素(CQ码)类型:" + type); - break; + case "text": + this.buildTextElem(data.text); + break; + case "at": + this.buildAtElem(data); + break; + case "face": + this.buildFaceElem(data); + break; + case "sface": + this.buildSFaceElem(data); + break; + case "bface": + this.buildBFaceElem(data); + break; + case "dice": + case "rps": + this.buildMagicFaceElem(type, data); + break; + case "image": + await this.buildImageElem(data); + break; + case "flash": + data.type = "flash"; + await this.buildImageElem(data); + break; + case "record": + await this.buildPttElem(data); + break; + case "location": + this.buildLocationElem(data); + break; + case "music": + await this.buildMusicElem(data); + break; + case "share": + this.buildShareElem(data); + break; + case "anonymous": + await this.buildAnonElem(data); + break; + case "reply": + await this.buildReplyElem(data); + break; + case "shake": + this.buildShakeElem(); + break; + case "poke": + this.buildPokeElem(data); + break; + case "json": + if (data.data) + this.buildJsonElem(data.data, data.text); + break; + case "xml": + if (data.data) + this.buildXmlElem(data.data, data.type, data.text); + break; + case "node": + this.buildNodeElem(data); + break; + default: + this.c.logger.warn("未知的元素(CQ码)类型:" + type); + break; } } @@ -662,12 +662,12 @@ class Builder { } await Promise.all(this.tasks); await uploadImages.call(this.c, this.target, this.imgs, !this.type); - this.length = this.stat.length + + this.length = this.stat.length + this.stat.at_cnt * 22 + this.stat.face_cnt * 23 + this.stat.sface_cnt * 42 + this.stat.bface_cnt * 135 + - this.stat.img_cnt * (this.type?90:295); + this.stat.img_cnt * (this.type ? 90 : 295); } } @@ -677,7 +677,7 @@ function qs(s, sep = ",", equal = "=") { for (let v of split) { const i = v.indexOf(equal); if (i === -1) continue; - ret[v.substring(0, i)] = v.substr(i+1).replace(/,|[|]|&/g, unescapeCQInside);; + ret[v.substring(0, i)] = v.substr(i + 1).replace(/,|[|]|&/g, unescapeCQInside); } return ret; } @@ -695,7 +695,7 @@ async function uploadPtt(target, buf, md5, codec) { 1: 3, 2: 3, 5: [{ - 1: target?target:1, + 1: target ? target : 1, 2: this.uin, 3: 0, 4: md5, @@ -715,8 +715,8 @@ async function uploadPtt(target, buf, md5, codec) { const blob = await this.sendUNI("PttStore.GroupPttUp", body); const rsp = pb.decode(blob)[5]; if (!rsp[4]) { - const ip = Array.isArray(rsp[5])?rsp[5][0]:rsp[5], - port = Array.isArray(rsp[6])?rsp[6][0]:rsp[6]; + const ip = Array.isArray(rsp[5]) ? rsp[5][0] : rsp[5], + port = Array.isArray(rsp[6]) ? rsp[6][0] : rsp[6]; const ukey = rsp[7].raw.toString("hex"), filekey = rsp[11].raw.toString("hex"); const params = { ver: 4679, @@ -725,18 +725,18 @@ async function uploadPtt(target, buf, md5, codec) { bmd5: md5.toString("hex"), mType: "pttDu", voice_encodec: codec - } + }; const url = `http://${int32ip2str(ip)}:${port}/?` + querystring.stringify(params); const headers = { "User-Agent": `QQ/${this.apk.version} CFNetwork/1126`, "Net-Type": "Wifi" }; this.logger.debug("开始上传语音到tx服务器。"); - await new Promise((resolve)=>{ - http.request(url, {method: 'POST', headers}, resolve) + await new Promise((resolve) => { + http.request(url, { method: "POST", headers }, resolve) .on("error", resolve) .end(buf); - }) + }); this.logger.debug("语音上传结束。"); } return rsp[11].raw; @@ -761,25 +761,25 @@ async function audioTrans(cache_filepath, file) { const head = file.slice(0, 7).toString(); if (head.includes("SILK") || head.includes("AMR")) { if (tmp) - fs.rename(filepath, cache_filepath, ()=>{}) + fs.rename(filepath, cache_filepath, () => { }); return file; } - return new Promise((resolve, reject)=>{ - exec(`ffmpeg -y -i ${filepath} -ac 1 -ar 8000 -f amr ${cache_filepath}`, async(error, stdout, stderr)=>{ + return new Promise((resolve, reject) => { + exec(`ffmpeg -y -i ${filepath} -ac 1 -ar 8000 -f amr ${cache_filepath}`, async (error, stdout, stderr) => { this.logger.debug("ffmpeg error: " + error); this.logger.debug("ffmpeg output: " + stdout + stderr); if (tmp) - fs.unlink(filepath, ()=>{}); + fs.unlink(filepath, () => { }); try { const amr = await fs.promises.readFile(cache_filepath); - this.logger.info(`ffmpeg成功转换了一个音频。`); + this.logger.info("ffmpeg成功转换了一个音频。"); resolve(amr); } catch (e) { - this.logger.warn(`音频转码到amr失败,请确认你的ffmpeg可以处理此转换。`); + this.logger.warn("音频转码到amr失败,请确认你的ffmpeg可以处理此转换。"); reject(); } - }) - }) + }); + }); } module.exports = { diff --git a/lib/message/chat.js b/lib/message/chat.js index 3c7cdf01..f68c7960 100644 --- a/lib/message/chat.js +++ b/lib/message/chat.js @@ -1,15 +1,15 @@ "use strict"; const zlib = require("zlib"); const crypto = require("crypto"); -const {Builder} = require("./builder"); -const {getC2CMsg, getGroupMsg} = require("./history"); -const {parsePrivateMsg, parseGroupMsg} = require("./recv"); -const {highwayUpload} = require("../service"); +const { Builder } = require("./builder"); +const { getC2CMsg, getGroupMsg } = require("./history"); +const { parsePrivateMsg, parseGroupMsg } = require("./recv"); +const { highwayUpload } = require("../service"); const common = require("../common"); const pb = require("../pb"); -const {genC2CMessageId, parseC2CMessageId, parseGroupMessageId, genMessageUuid} = common; +const { genC2CMessageId, parseC2CMessageId, parseGroupMessageId, genMessageUuid } = common; const BUF1 = Buffer.from([1]); -const PB_CONTENT = pb.encode({1:1, 2:0, 3:0}); +const PB_CONTENT = pb.encode({ 1: 1, 2: 0, 3: 0 }); const PB_RESERVER = pb.encode({ 17: 0, 19: { @@ -30,11 +30,11 @@ const PB_RESERVER = pb.encode({ * @returns {import("../ref").ProtocolResponse} */ async function sendMsg(target, message, escape, type) { - var [target] = common.uinAutoCheck(target); + [target] = common.uinAutoCheck(target); const builder = new Builder(this, target, type); await builder.exec(message, escape); - const _sendMsg = async(rich, frag = false)=>{ + const _sendMsg = async (rich, frag = false) => { if (builder.anon) { if (!rich[2]) rich[2] = []; @@ -50,39 +50,39 @@ async function sendMsg(target, message, escape, type) { 37: PB_RESERVER }); } - return await (type?sendGroupMsg:sendPrivateMsg).call(this, target, rich, type); + return await (type ? sendGroupMsg : sendPrivateMsg).call(this, target, rich, type); } - } + }; let rsp; for (const buf of builder.b77) { rsp = await sendB77RichMsg.call(this, buf); } for (const elem of builder.ptts) { - rsp = await _sendMsg({4: elem}); + rsp = await _sendMsg({ 4: elem }); } for (const elems of builder.flashs.concat(builder.jsons, builder.xmls)) { - rsp = await _sendMsg({2: elems}); + rsp = await _sendMsg({ 2: elems }); } if (builder.nodes.length > 0) { const elems = await toForwardMsgElems.call(this, target, builder.nodes); - rsp = await _sendMsg({2: elems}); + rsp = await _sendMsg({ 2: elems }); } if (!builder.length) { if (rsp) return rsp; throw new Error("empty message"); } - rsp = await _sendMsg({2: builder.elems}); + rsp = await _sendMsg({ 2: builder.elems }); if (this.config.resend && rsp.data && rsp.data.message_id === "") { if (builder.stat.length <= 80) { const emsg = "群消息可能发送失败,请检查消息内容。"; this.logger.error(`send failed: [Group: ${target}] ` + emsg); - return {result: -1, emsg}; + return { result: -1, emsg }; } - this.logger.warn(`此消息将尝试使用分片发送。`); - return await _sendMsg({2: builder.elems}, true); + this.logger.warn("此消息将尝试使用分片发送。"); + return await _sendMsg({ 2: builder.elems }, true); } return rsp; } @@ -94,8 +94,8 @@ function buildSyncCookie() { 2: time, 3: this.const1, 4: this.const2, - 5: crypto.randomBytes(4).readUInt32BE(), - 9: crypto.randomBytes(4).readUInt32BE(), + 5: crypto.randomBytes(4).readUInt32BE(), + 9: crypto.randomBytes(4).readUInt32BE(), 11: crypto.randomBytes(4).readUInt32BE(), 12: this.const3, 13: time, @@ -108,23 +108,27 @@ function buildSyncCookie() { * @returns {import("../ref").ProtocolResponse} */ async function sendPrivateMsg(user_id, rich) { - let routing = {1: {1: user_id}}; + let routing = { 1: { 1: user_id } }; if (this.sl.has(user_id)) { try { const group_id = this.sl.get(user_id).group_id; if (group_id && (await this.getGroupMemberInfo(group_id, user_id)).data) - routing = {3: { - 1: common.code2uin(group_id), - 2: user_id, - }}; - } catch (e) {} + routing = { + 3: { + 1: common.code2uin(group_id), + 2: user_id, + } + }; + } catch (e) { } } else if (!this.fl.has(user_id)) { for (const [k, v] of this.gml) { if (v instanceof Map && v.has(user_id)) { - routing = {3: { - 1: common.code2uin(k), - 2: user_id, - }} + routing = { + 3: { + 1: common.code2uin(k), + 2: user_id, + } + }; break; } } @@ -134,7 +138,7 @@ async function sendPrivateMsg(user_id, rich) { const body = pb.encode({ 1: routing, 2: PB_CONTENT, - 3: {1: rich}, + 3: { 1: rich }, 4: seq, 5: random, 6: buildSyncCookie.call(this), @@ -145,11 +149,11 @@ async function sendPrivateMsg(user_id, rich) { if (rsp[1] === 0) { const message_id = genC2CMessageId(user_id, seq, random, rsp[3]); this.logger.info(`send to: [Private: ${user_id} / message_id: ${message_id}]`); - return {result: 0, data: {message_id}}; + return { result: 0, data: { message_id } }; } let emsg = rsp[2] ? String(rsp[2].raw) : ""; this.logger.error(`send failed: [Private: ${user_id}] ${emsg}(${rsp[1]})`); - return {result: rsp[1], emsg}; + return { result: rsp[1], emsg }; } /** @@ -157,19 +161,19 @@ async function sendPrivateMsg(user_id, rich) { * @returns {import("../ref").ProtocolResponse} */ async function sendGroupMsg(target, rich, type) { - const routing = type === 1 ? {2: {1: target}} : {4: {1: target}}; + const routing = type === 1 ? { 2: { 1: target } } : { 4: { 1: target } }; const random = crypto.randomBytes(4).readUInt32BE(); const body = pb.encode({ 1: routing, 2: PB_CONTENT, - 3: {1: rich}, + 3: { 1: rich }, 4: this.seq_id + 1, 5: random, 8: 0 }); const event_id = `interval.${target}.${random}`; let message_id = ""; - this.once(event_id, (id)=>message_id=id); + this.once(event_id, (id) => message_id = id); try { var blob = await this.sendUNI("MessageSvc.PbSendMsg", body); } catch (e) { @@ -181,18 +185,18 @@ async function sendGroupMsg(target, rich, type) { if (rsp[1] !== 0) { let emsg = rsp[2] ? String(rsp[2].raw) : ""; this.logger.error(`send failed: [Group: ${target}] ${emsg}(${rsp[1]})`); - return {result: rsp[1], emsg}; + return { result: rsp[1], emsg }; } if (type === 2) { - return {result: rsp[1]}; + return { result: rsp[1] }; } if (!message_id) { - await new Promise((resolve)=>{ - const timeout = setTimeout(()=>{ + await new Promise((resolve) => { + const timeout = setTimeout(() => { this.removeAllListeners(event_id); resolve(); - }, this.config.resend?500:5000); - this.once(event_id, (id)=>{ + }, this.config.resend ? 500 : 5000); + this.once(event_id, (id) => { message_id = id; clearTimeout(timeout); resolve(); @@ -202,7 +206,7 @@ async function sendGroupMsg(target, rich, type) { this.logger.info(`send to: [Group: ${target} / message_id: ${message_id}]`); if (!message_id) this.logger.warn("生成message_id失败,此消息大概率被风控了。"); - return {result: 0, data: {message_id}}; + return { result: 0, data: { message_id } }; } /** @@ -210,7 +214,7 @@ async function sendGroupMsg(target, rich, type) { * @returns {import("../ref").ProtocolResponse} */ async function sendGroupMsgByFrag(group_id, fragments) { - const routing = {2: {1: group_id}}; + const routing = { 2: { 1: group_id } }; let n = 0; const random = crypto.randomBytes(4).readUInt32BE(); const div = crypto.randomBytes(2).readUInt16BE(); @@ -222,7 +226,7 @@ async function sendGroupMsgByFrag(group_id, fragments) { 2: n, 3: div }, - 3: {1: {2: fragment}}, + 3: { 1: { 2: fragment } }, 4: this.seq_id + 1, 5: random, 8: 0, @@ -232,12 +236,12 @@ async function sendGroupMsgByFrag(group_id, fragments) { } const event_id = `interval.${group_id}.${random}`; let message_id = ""; - await new Promise((resolve)=>{ - const timeout = setTimeout(()=>{ + await new Promise((resolve) => { + const timeout = setTimeout(() => { this.removeAllListeners(event_id); resolve(); }, 3000); - this.once(event_id, (id)=>{ + this.once(event_id, (id) => { message_id = id; clearTimeout(timeout); resolve(); @@ -246,10 +250,10 @@ async function sendGroupMsgByFrag(group_id, fragments) { if (!message_id) { const emsg = "群分片消息可能发送失败,请检查消息内容。"; this.logger.error(`send failed: [Group: ${group_id}] ` + emsg); - return {result: -1, emsg}; + return { result: -1, emsg }; } this.logger.info(`send to: [Group: ${group_id} / message_id: ${message_id}]`); - return {result: 0, data: {message_id}}; + return { result: 0, data: { message_id } }; } function toFragments(elems) { @@ -293,7 +297,7 @@ async function toForwardMsgElems(target, nodes) { } catch (e) { throw new Error("failed to upload forward msg"); } - const preview = ` 转发的聊天记录 `; + const preview = " 转发的聊天记录 "; const template = ` 转发的聊天记录 ${preview}
查看转发消息
`; return [ @@ -351,9 +355,9 @@ async function uploadMultiMsg(target, compressed) { buf: buf, md5: common.md5(buf), key: rsp[10].raw - } - const ip = Array.isArray(rsp[4])?rsp[4][0]:rsp[4], - port = Array.isArray(rsp[5])?rsp[5][0]:rsp[5]; + }; + const ip = Array.isArray(rsp[4]) ? rsp[4][0] : rsp[4], + port = Array.isArray(rsp[5]) ? rsp[5][0] : rsp[5]; await highwayUpload.call(this, ip, port, o, 27); return rsp[2].raw; } @@ -365,8 +369,8 @@ async function sendB77RichMsg(buf) { try { ++this.stat.sent_msg_cnt; await this.sendUNI("OidbSvc.0xb77_9", buf); - } catch {} - return {result: 0, data: {message_id: ""}}; + } catch { } + return { result: 0, data: { message_id: "" } }; } //recall---------------------------------------------------------------------------------------------------- @@ -387,12 +391,12 @@ async function recallMsg(message_id) { await this.sendUNI("PbMessageSvc.PbMsgWithDraw", body); } function buildRecallPrivateMsgBody(message_id) { - const {user_id, seq, random, time} = parseC2CMessageId(message_id); + const { user_id, seq, random, time } = parseC2CMessageId(message_id); let type = 0; try { if (this.sl.get(user_id).group_id) type = 1; - } catch (e) {} + } catch (e) { } return pb.encode({ 1: [{ 1: [{ @@ -404,13 +408,13 @@ function buildRecallPrivateMsgBody(message_id) { 6: random, }], 2: 0, - 3: Buffer.from([0x8,type]), + 3: Buffer.from([0x8, type]), 4: 1, }] }); } function buildRecallGroupMsgBody(message_id) { - var {group_id, seq, random, pktnum} = parseGroupMessageId(message_id); + var { group_id, seq, random, pktnum } = parseGroupMessageId(message_id); if (pktnum > 1) { //分片消息 var msg = [], pb_msg = [], n = pktnum, i = 0; @@ -429,13 +433,13 @@ function buildRecallGroupMsgBody(message_id) { var reserver = { 1: 1, 2: pb_msg, - } + }; } else { var msg = { 1: seq, 2: random, }; - var reserver = {1: 0}; + var reserver = { 1: 0 }; } return pb.encode({ 2: [{ @@ -453,17 +457,17 @@ function buildRecallGroupMsgBody(message_id) { /** * @this {import("../ref").Client} */ -async function getHistoryMsg(message_id) { +async function getHistoryMsg(message_id) { if (message_id.length > 24) { const o = await getGroupMsg.call(this, message_id); try { const msg = await parseGroupMsg.call(this, o[1], o[2], o[3], false); msg.message_type = "group"; msg.real_id = message_id; - return {result: 0, data: msg}; + return { result: 0, data: msg }; } catch (e) { this.logger.debug(e); - return {result: -1, emsg: "failed to get group msg"}; + return { result: -1, emsg: "failed to get group msg" }; } } else { const o = await getC2CMsg.call(this, message_id); @@ -471,10 +475,10 @@ async function getHistoryMsg(message_id) { const msg = await parsePrivateMsg.call(this, o[1][3], o[1], o[2], o[3]); msg.message_type = "private"; msg.real_id = message_id; - return {result: 0, data: msg}; + return { result: 0, data: msg }; } catch (e) { this.logger.debug(e); - return {result: -1, emsg: "failed to get c2c msg"}; + return { result: -1, emsg: "failed to get c2c msg" }; } } } diff --git a/lib/message/face.js b/lib/message/face.js index 197bb6b8..2de4798f 100644 --- a/lib/message/face.js +++ b/lib/message/face.js @@ -50,7 +50,7 @@ const pokemap = { 2007: "玫瑰花", 2009: "让你皮", 2011: "宝贝球", -} +}; module.exports = { map, pokemap diff --git a/lib/message/file.js b/lib/message/file.js index b672ab76..707267df 100644 --- a/lib/message/file.js +++ b/lib/message/file.js @@ -48,4 +48,4 @@ async function getC2CFileUrl(fileid) { module.exports = { getGroupFileUrl, getC2CFileUrl, -} +}; diff --git a/lib/message/history.js b/lib/message/history.js index f65f701e..a39ca45e 100644 --- a/lib/message/history.js +++ b/lib/message/history.js @@ -1,4 +1,4 @@ -"use strict" +"use strict"; const pb = require("../pb"); const {parseC2CMessageId, parseGroupMessageId} = require("../common"); diff --git a/lib/message/image.js b/lib/message/image.js index c4290166..9e53bf36 100644 --- a/lib/message/image.js +++ b/lib/message/image.js @@ -2,7 +2,7 @@ const fs = require("fs"); const path = require("path"); const { randomBytes } = require("crypto"); -const imgSizeOf = require('image-size'); +const imgSizeOf = require("image-size"); const pb = require("../pb"); const common = require("../common"); const { downloadWebImage, readFile, highwayUpload } = require("../service"); @@ -195,7 +195,7 @@ class ImageBuilder { async buildNested(obj) { let { file, url, cache, timeout, proxy, headers } = obj; if (!file) - return this.c.logger.warn(`file不是有效的图片`); + return this.c.logger.warn("file不是有效的图片"); // bytes if (file instanceof Buffer || file instanceof Uint8Array) { @@ -204,7 +204,7 @@ class ImageBuilder { // 网络图片 else if (file.startsWith("http")) { - const filename = common.md5(Buffer.from(file, "utf-8")).toString('hex'); + const filename = common.md5(Buffer.from(file, "utf-8")).toString("hex"); this.filepath = path.join(this.c.dir, "..", "image", filename); this.address = file; this.proxy = ["1", "true", "yes"].includes(String(proxy)); @@ -247,7 +247,7 @@ class ImageBuilder { this.calcSizeOf(); } catch { this.buf = null; - return this.c.logger.warn(`file不是有效的图片`); + return this.c.logger.warn("file不是有效的图片"); } if (!this.c2c && url && url.includes("gchatpic_new")) { diff --git a/lib/message/music.js b/lib/message/music.js index 816a8f39..852ce6fc 100644 --- a/lib/message/music.js +++ b/lib/message/music.js @@ -1,5 +1,5 @@ "use strict"; -const {URL} = require("url"); +const { URL } = require("url"); const http = require("http"); const https = require("https"); const pb = require("../pb"); @@ -21,17 +21,17 @@ function parse(o) { } async function qwerty(url) { - return new Promise((resolve, reject)=>{ + return new Promise((resolve, reject) => { const protocol = url.startsWith("https") ? https : http; - protocol.get(url, (res)=>{ + protocol.get(url, (res) => { let data = ""; res.setEncoding("utf8"); - res.on("data", chunk=>data+=chunk); - res.on("end", ()=>{ + res.on("data", chunk => data += chunk); + res.on("end", () => { resolve(data); }); }).on("error", reject); - }) + }); } async function getQQSongInfo(id) { @@ -40,7 +40,7 @@ async function getQQSongInfo(id) { let mid = rsp.mid, title = rsp.name, album = rsp.album.mid, singer = "unknown"; try { singer = rsp.singer[0].name; - } catch {} + } catch { } rsp = await qwerty(`http://u.y.qq.com/cgi-bin/musicu.fcg?g_tk=2034008533&uin=0&format=json&data={"comm":{"ct":23,"cv":0},"url_mid":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"4311206557","songmid":["${mid}"],"songtype":[0],"uin":"0","loginflag":1,"platform":"23"}}}&_=1599039471576`); rsp = JSON.parse(rsp).url_mid.data.midurlinfo[0]; return { @@ -58,8 +58,8 @@ async function get163SongInfo(id) { return { title: rsp.name, singer: rsp.artists[0].name, - jumpUrl: `https://y.music.163.com/m/song/` + id, - musicUrl: `http://music.163.com/song/media/outer/url?id=` + id, + jumpUrl: "https://y.music.163.com/m/song/" + id, + musicUrl: "http://music.163.com/song/media/outer/url?id=" + id, preview: rsp.album.picUrl, }; } @@ -68,12 +68,12 @@ async function build(target, type, id, bu) { var appid, appname, appsign, style = 4; if (type == "qq") { appid = 100497308, appname = "com.tencent.qqmusic", appsign = "cbd27cd7c861227d013a25b2d10f0799"; - var {singer, title, jumpUrl, musicUrl, preview} = await getQQSongInfo(id); + var { singer, title, jumpUrl, musicUrl, preview } = await getQQSongInfo(id); if (!musicUrl) style = 0; } else if (type == "163") { appid = 100495085, appname = "com.netease.cloudmusic", appsign = "da6b069da1e2982db3e386233f68d76d"; - var {singer, title, jumpUrl, musicUrl, preview} = await get163SongInfo(id); + var { singer, title, jumpUrl, musicUrl, preview } = await get163SongInfo(id); } else { throw new Error("unknown music type"); } diff --git a/lib/message/parser.js b/lib/message/parser.js index 8cfeb1e2..9a2d46c3 100644 --- a/lib/message/parser.js +++ b/lib/message/parser.js @@ -5,12 +5,12 @@ const zlib = require("zlib"); const querystring = require("querystring"); const tea = require("crypto-tea"); const face = require("./face"); -const {getGroupMsgBySeq} = require("./history"); -const {int32ip2str} = require("../service"); -const {buildImageFileParam} = require("./image"); -const {getGroupFileUrl, getC2CFileUrl} = require("./file"); +const { getGroupMsgBySeq } = require("./history"); +const { int32ip2str } = require("../service"); +const { buildImageFileParam } = require("./image"); +const { getGroupFileUrl, getC2CFileUrl } = require("./file"); const pb = require("../pb"); -const {genC2CMessageId, genGroupMessageId, timestamp} = require("../common"); +const { genC2CMessageId, genGroupMessageId, timestamp } = require("../common"); function escapeCQInside(s) { if (s === "&") return "&"; @@ -46,20 +46,20 @@ async function downloadMultiMsg(resid, bu) { }); const blob = await this.sendUNI("MultiMsg.ApplyDown", body); const rsp = pb.decode(blob)[3]; - const ip = int32ip2str(Array.isArray(rsp[4])?rsp[4][0]:rsp[4]), - port = Array.isArray(rsp[5])?rsp[5][0]:rsp[5]; + const ip = int32ip2str(Array.isArray(rsp[4]) ? rsp[4][0] : rsp[4]), + port = Array.isArray(rsp[5]) ? rsp[5][0] : rsp[5]; let url = port == 443 ? "https://ssl.htdata.qq.com" : `http://${ip}:${port}`; url += rsp[2].raw; const headers = { "User-Agent": `QQ/${this.apk.version} CFNetwork/1126`, "Net-Type": "Wifi" }; - return new Promise((resolve, reject)=>{ + return new Promise((resolve, reject) => { const protocol = port == 443 ? https : http; - protocol.get(url, {headers}, (res)=>{ + protocol.get(url, { headers }, (res) => { const data = []; - res.on("data", (chunk)=>data.push(chunk)); - res.on("end", ()=>{ + res.on("data", (chunk) => data.push(chunk)); + res.on("end", () => { try { let buf = Buffer.concat(data); if (res.headers["accept-encoding"] && res.headers["accept-encoding"].includes("gzip")) @@ -74,7 +74,7 @@ async function downloadMultiMsg(resid, bu) { } catch (e) { reject(); } - }) + }); }).on("error", reject); }); } @@ -85,147 +85,147 @@ async function downloadMultiMsg(resid, bu) { async function parseMessage(rich, from = 0, gflag = false) { const elems = Array.isArray(rich[2]) ? rich[2] : [rich[2]]; if (rich[4]) - elems.unshift(Object.setPrototypeOf({}, {9999: rich[4]})); + elems.unshift(Object.setPrototypeOf({}, { 9999: rich[4] })); let extra = {}, anon = {}; const chain = []; let raw_message = ""; let bface_tmp = null, bface_magic = null, ignore_text = false; for (let v of elems) { const type = parseInt(Object.keys(Reflect.getPrototypeOf(v))[0]); - const msg = {type:"",data:{}}; + const msg = { type: "", data: {} }; let o = v[type]; switch (type) { - case 45: //reply - if (Array.isArray(o[1])) - o[1] = o[1][0]; - try { - if (gflag) { - const m = await getGroupMsgBySeq.call(this, from, o[1]); - msg.data.id = genGroupMessageId(from, o[2], o[1], m[3][1][1][3], m[1][6]); - } else { - let random = o[8][3]; - if (typeof random === "bigint") - random = parseInt(random&0xffffffffn); - msg.data.id = genC2CMessageId(from, o[1], random, o[3]); - } - msg.type = "reply"; - } catch {} - break; - case 21: //anonGroupMsg - anon = o; - break; - case 16: //extraInfo - extra = o; - break; - case 37: //generalFlags - if (o[6] === 1 && o[7]) - return await parseMultiMsg.call(this, o[7].raw, from); - break; - case 34: //sface - msg.type = "sface"; - msg.data.id = o[1]; - break; - case 17: - msg.type = "shake"; - ignore_text = true; - break; - case 12: //xml - case 51: //json - msg.type = type === 12 ? "xml" : "json"; - if (o[1].raw[0] > 0) - msg.data.data = String(zlib.unzipSync(o[1].raw.slice(1))); - else - msg.data.data = String(o[1].raw.slice(1)) - if (o[2] > 0) - msg.data.type = o[2]; - ignore_text = true; - break; - case 5: //file - [msg.type, msg.data] = await parseTransElem.call(this, o, from); - ignore_text = true; - break; - case 1: //text - if (ignore_text) break; - if (bface_tmp && o[1]) { - const text = String(o[1].raw).replace("[","").replace("]","").trim(); - if (text.includes("猜拳") && bface_magic) { - msg.type = "rps"; - msg.data.id = bface_magic.raw[16] - 0x30 + 1; - } else if (text.includes("骰子") && bface_magic) { - msg.type = "dice"; - msg.data.id = bface_magic.raw[16] - 0x30 + 1; - } else { - msg.data.file = bface_tmp, msg.type = "bface"; - msg.data.text = text; - } - bface_tmp = null; - bface_magic = null; - break; + case 45: //reply + if (Array.isArray(o[1])) + o[1] = o[1][0]; + try { + if (gflag) { + const m = await getGroupMsgBySeq.call(this, from, o[1]); + msg.data.id = genGroupMessageId(from, o[2], o[1], m[3][1][1][3], m[1][6]); + } else { + let random = o[8][3]; + if (typeof random === "bigint") + random = parseInt(random & 0xffffffffn); + msg.data.id = genC2CMessageId(from, o[1], random, o[3]); } - if (o[3] && o[3].raw[1] === 1) { - msg.type = "at"; - if (o[3].raw[6] === 1) - msg.data.qq = "all" - else - msg.data.qq = o[3].raw.readUInt32BE(7); + msg.type = "reply"; + } catch { } + break; + case 21: //anonGroupMsg + anon = o; + break; + case 16: //extraInfo + extra = o; + break; + case 37: //generalFlags + if (o[6] === 1 && o[7]) + return await parseMultiMsg.call(this, o[7].raw, from); + break; + case 34: //sface + msg.type = "sface"; + msg.data.id = o[1]; + break; + case 17: + msg.type = "shake"; + ignore_text = true; + break; + case 12: //xml + case 51: //json + msg.type = type === 12 ? "xml" : "json"; + if (o[1].raw[0] > 0) + msg.data.data = String(zlib.unzipSync(o[1].raw.slice(1))); + else + msg.data.data = String(o[1].raw.slice(1)); + if (o[2] > 0) + msg.data.type = o[2]; + ignore_text = true; + break; + case 5: //file + [msg.type, msg.data] = await parseTransElem.call(this, o, from); + ignore_text = true; + break; + case 1: //text + if (ignore_text) break; + if (bface_tmp && o[1]) { + const text = String(o[1].raw).replace("[", "").replace("]", "").trim(); + if (text.includes("猜拳") && bface_magic) { + msg.type = "rps"; + msg.data.id = bface_magic.raw[16] - 0x30 + 1; + } else if (text.includes("骰子") && bface_magic) { + msg.type = "dice"; + msg.data.id = bface_magic.raw[16] - 0x30 + 1; } else { - msg.type = "text"; + msg.data.file = bface_tmp, msg.type = "bface"; + msg.data.text = text; } - msg.data.text = String(o[1].raw); - break; - case 2: //face - msg.type = "face", msg.data.id = o[1]; - break; - case 6: //bface - bface_tmp = o[4].raw.toString("hex") + o[7].raw.toString("hex") + o[5]; - bface_magic = o[12]; + bface_tmp = null; + bface_magic = null; break; - case 4: //notOnlineImage - msg.type = "image"; - msg.data = parseImageElem(o, from, 1); - break; - case 8: //customFace - msg.type = "image"; - msg.data = parseImageElem(o, from, 0); - break; - case 53: //commonElem - if (o[1] === 3) { - msg.type = "flash"; - if (o[2][1]) { //customFace - msg.data = parseImageElem(o[2][1], from, 0); - } - else if (o[2][2]) { //notOnlineImage - msg.data = parseImageElem(o[2][2], from, 1); - } - ignore_text = true; - } else if (o[1] === 33) { - msg.type = "face"; - msg.data.id = o[2][1]; - if (face.map[msg.data.id]) - msg.data.text = face.map[msg.data.id]; - else if (o[2][2]) - msg.data.text = String(o[2][2].raw); - } else if (o[1] === 2) { - msg.type = "poke"; - msg.data.type = o[3]; - if (o[3] === 126) { - msg.data.id = o[2][4]; - msg.data.name = face.pokemap[o[2][4]]; - } else { - msg.data.id = -1; - msg.data.name = face.pokemap[o[3]]; - } - ignore_text = true; + } + if (o[3] && o[3].raw[1] === 1) { + msg.type = "at"; + if (o[3].raw[6] === 1) + msg.data.qq = "all"; + else + msg.data.qq = o[3].raw.readUInt32BE(7); + } else { + msg.type = "text"; + } + msg.data.text = String(o[1].raw); + break; + case 2: //face + msg.type = "face", msg.data.id = o[1]; + break; + case 6: //bface + bface_tmp = o[4].raw.toString("hex") + o[7].raw.toString("hex") + o[5]; + bface_magic = o[12]; + break; + case 4: //notOnlineImage + msg.type = "image"; + msg.data = parseImageElem(o, from, 1); + break; + case 8: //customFace + msg.type = "image"; + msg.data = parseImageElem(o, from, 0); + break; + case 53: //commonElem + if (o[1] === 3) { + msg.type = "flash"; + if (o[2][1]) { //customFace + msg.data = parseImageElem(o[2][1], from, 0); + } + else if (o[2][2]) { //notOnlineImage + msg.data = parseImageElem(o[2][2], from, 1); } - break; - case 9999: //ptt - [msg.type, msg.data] = await parsePttElem.call(this, o, from); ignore_text = true; - break; + } else if (o[1] === 33) { + msg.type = "face"; + msg.data.id = o[2][1]; + if (face.map[msg.data.id]) + msg.data.text = face.map[msg.data.id]; + else if (o[2][2]) + msg.data.text = String(o[2][2].raw); + } else if (o[1] === 2) { + msg.type = "poke"; + msg.data.type = o[3]; + if (o[3] === 126) { + msg.data.id = o[2][4]; + msg.data.name = face.pokemap[o[2][4]]; + } else { + msg.data.id = -1; + msg.data.name = face.pokemap[o[3]]; + } + ignore_text = true; + } + break; + case 9999: //ptt + [msg.type, msg.data] = await parsePttElem.call(this, o, from); + ignore_text = true; + break; } if (msg.type) { - if (msg.type === "text" && chain[chain.length-1] && chain[chain.length-1].type === "text") - chain[chain.length-1].data.text += msg.data.text; + if (msg.type === "text" && chain[chain.length - 1] && chain[chain.length - 1].type === "text") + chain[chain.length - 1].data.text += msg.data.text; else chain.push(msg); if (msg.type === "text") @@ -234,12 +234,12 @@ async function parseMessage(rich, from = 0, gflag = false) { raw_message += genCQMsg(msg); } } - return {chain, raw_message, extra, anon}; + return { chain, raw_message, extra, anon }; } function genCQMsg(msg) { - const data = querystring.stringify(msg.data, ",", "=", {encodeURIComponent: (s)=>s.replace(/&|,|\[|\]/g, escapeCQInside)}); - return `[CQ:` + msg.type + (data ? "," : "") + data + `]`; + const data = querystring.stringify(msg.data, ",", "=", { encodeURIComponent: (s) => s.replace(/&|,|\[|\]/g, escapeCQInside) }); + return "[CQ:" + msg.type + (data ? "," : "") + data + "]"; } function parseImageElem(o, from, c2c = false) { @@ -268,9 +268,9 @@ async function parseMultiMsg(resid, from) { } async function parsePttElem(o) { - const data = {md5: o[4].raw.toString("hex")}; + const data = { md5: o[4].raw.toString("hex") }; if (o[20]) { - const url = String(o[20].raw); + const url = String(o[20].raw); data.file = url.startsWith("http") ? url : "https://grouptalk.c2c.qq.com" + url; } else if (o[3]) { data.file = o[3].raw.toString("hex"); @@ -283,13 +283,13 @@ async function parseTransElem(o, from) { v = v[2]; let rsp = await getGroupFileUrl.call(this, from, v[1], v[2].raw); const data = { - name: String(v[4].raw), - url: `http://${rsp[4].raw}/ftn_handler/${rsp[6].raw.toString("hex")}/?fname=${v[4].raw}`, - size: v[3], - md5: rsp[9].raw.toString("hex"), + name: String(v[4].raw), + url: `http://${rsp[4].raw}/ftn_handler/${rsp[6].raw.toString("hex")}/?fname=${v[4].raw}`, + size: v[3], + md5: rsp[9].raw.toString("hex"), duration: v[5], - busid: from.toString(36) + "-" + v[1], - fileid: String(v[2].raw) + busid: from.toString(36) + "-" + v[1], + fileid: String(v[2].raw) }; return ["file", data]; } diff --git a/lib/message/recv.js b/lib/message/recv.js index a970bfb0..990eecd4 100644 --- a/lib/message/recv.js +++ b/lib/message/recv.js @@ -1,6 +1,6 @@ "use strict"; -const {parseMessage, parseC2CFileElem} = require("./parser"); -const {genC2CMessageId, genGroupMessageId, timestamp, parseFunString} = require("../common"); +const { parseMessage, parseC2CFileElem } = require("./parser"); +const { genC2CMessageId, genGroupMessageId, timestamp, parseFunString } = require("../common"); /** * @param {141|166|167|208|529} type @@ -13,7 +13,7 @@ async function parsePrivateMsg(type, head, content, body) { seq = head[5]; let sub_type, message_id = "", font = "unknown"; - const sender = Object.assign({user_id}, this.fl.get(user_id)); + const sender = Object.assign({ user_id }, this.fl.get(user_id)); if (type === 141) { sub_type = "other"; if (head[8] && head[8][4]) { @@ -26,7 +26,7 @@ async function parsePrivateMsg(type, head, content, body) { sub_type = this.fl.has(user_id) ? "friend" : "single"; } if (sender.nickname === undefined) { - const stranger = (await this.getStrangerInfo(user_id, seq%5==0)).data; + const stranger = (await this.getStrangerInfo(user_id, seq % 5 == 0)).data; if (stranger) { stranger.group_id = sender.group_id; Object.assign(sender, stranger); @@ -37,19 +37,19 @@ async function parsePrivateMsg(type, head, content, body) { try { message_id = genC2CMessageId(user_id, seq, body[1][1][3], time); font = String(body[1][1][9].raw); - } catch {} + } catch { } if (type === 529) { if (head[4] !== 4) return; - var {chain, raw_message} = await parseC2CFileElem.call(this, body[2][1]); + var { chain, raw_message } = await parseC2CFileElem.call(this, body[2][1]); } else if (body[1] && body[1][2]) { - var {chain, raw_message} = await parseMessage.call(this, body[1], user_id); + var { chain, raw_message } = await parseMessage.call(this, body[1], user_id); } return { sub_type, message_id, user_id, message: chain, raw_message, font, sender, time, - auto_reply: !!(content&&content[4]) + auto_reply: !!(content && content[4]) }; } @@ -67,7 +67,7 @@ async function parseGroupMsg(head, content, body, ignore_self = true) { if (!group_name) { try { group_name = this.gl.get(group_id).group_name; - } catch {} + } catch { } } this.msgExists(group_id, 0, seq, time); @@ -82,7 +82,7 @@ async function parseGroupMsg(head, content, body, ignore_self = true) { this.getGroupInfo(group_id); - var {chain, raw_message, extra, anon} = await parseMessage.call(this, body[1], group_id, 1); + var { chain, raw_message, extra, anon } = await parseMessage.call(this, body[1], group_id, 1); let font = String(body[1][1][9].raw), card = parseFunString(group[4].raw); @@ -116,14 +116,14 @@ async function parseGroupMsg(head, content, body, ignore_self = true) { user.last_sent_time = time; this.gl.get(group_id).last_sent_time = time; } - } catch (e) {} + } catch (e) { } } if (user_id === this.uin && this.config.ignore_self && ignore_self) return; if (user) { - var {nickname, sex, age, area, level, role, title} = user; + var { nickname, sex, age, area, level, role, title } = user; } else { var nickname = card, sex = "unknown", age = 0, area = "", level = 0, role = "member", title = ""; } @@ -162,7 +162,7 @@ async function parseDiscussMsg(head, body) { user_id, nickname, card }; - const {chain, raw_message} = await parseMessage.call(this, body[1], discuss_id); + const { chain, raw_message } = await parseMessage.call(this, body[1], discuss_id); return { discuss_id, discuss_name, user_id, diff --git a/lib/online-push.js b/lib/online-push.js index 82d27293..fce9ac5e 100644 --- a/lib/online-push.js +++ b/lib/online-push.js @@ -1,8 +1,8 @@ "use strict"; const pb = require("./pb"); const jce = require("./jce"); -const {parseGroupMsg, parseDiscussMsg} = require("./message/recv"); -const {genC2CMessageId, genGroupMessageId} = require("./common"); +const { parseGroupMsg, parseDiscussMsg } = require("./message/recv"); +const { genC2CMessageId, genGroupMessageId } = require("./common"); /** * OnlinePush回执 @@ -13,19 +13,19 @@ const {genC2CMessageId, genGroupMessageId} = require("./common"); */ function handleOnlinePush(svrip, seq, rubbish = []) { const resp = jce.encodeStruct([ - this.uin, rubbish, svrip&0xffffffff, null, 0 + this.uin, rubbish, svrip & 0xffffffff, null, 0 ]); const extra = { - req_id: seq, + req_id: seq, service: "OnlinePush", - method: "SvcRespPushMsg", + method: "SvcRespPushMsg", }; - const body = jce.encodeWrapper({resp}, extra); + const body = jce.encodeWrapper({ resp }, extra); this.writeUNI("OnlinePush.RespPush", body); } const sub0x27 = { - 80: function(data, time) { + 80: function (data, time) { const o = data[12]; const group_id = o[3]; if (!o[4]) @@ -33,26 +33,26 @@ const sub0x27 = { const group_name = String(o[2][2].raw); try { this.gl.get(group_id).group_name = group_name; - } catch (e) {} + } catch (e) { } this.em("notice.group.setting", { group_id, time, user_id: o[4], group_name, }); }, - 5: function(data, time) { + 5: function (data, time) { const user_id = data[14][1]; let nickname; try { nickname = this.fl.get(user_id).nickname; this.fl.delete(user_id); - } catch (e) {} + } catch (e) { } this.logger.info(`更新了好友列表,删除了好友 ${user_id}(${nickname})`); this.em("notice.friend.decrease", { user_id, nickname, time }); }, - 20: function(data, time) { + 20: function (data, time) { // 20002昵称 20009性别 20031生日 23109农历生日 20019说明 20032地区 24002故乡 const user_id = data[8][1]; const o = data[8][2]; @@ -62,7 +62,7 @@ const sub0x27 = { value = String(o[2].raw); } else if (o[1] === 20009) { key = "sex"; - value = ["unknown","male","female"][o[2].raw[0]]; + value = ["unknown", "male", "female"][o[2].raw[0]]; } else if (o[1] === 20031) { key = "age"; value = new Date().getFullYear() - o[2].raw.readUInt16BE(); @@ -74,21 +74,21 @@ const sub0x27 = { } try { this.fl.get(user_id)[key] = value; - } catch (e) {} + } catch (e) { } if (user_id === this.uin) this[key] = value; else { - const e = {user_id,time}; + const e = { user_id, time }; e[key] = value; this.em("notice.friend.profile", e); } }, - 60: function(data, time) { + 60: function (data, time) { const user_id = data[10][1]; const sign = String(data[10][2].raw); try { this.fl.get(user_id).signature = sign; - } catch (e) {} + } catch (e) { } if (user_id === this.uin) this.signature = sign; else @@ -96,20 +96,20 @@ const sub0x27 = { user_id, signature: sign, time }); }, - 40: function(data, time) { + 40: function (data, time) { try { const o = data[9][1], uin = o[2]; if (o[1] > 0) return; //0好友备注 1群备注 this.fl.get(uin).remark = String(o[3].raw); - } catch (e) {} + } catch (e) { } }, - 21: function(data, time) { + 21: function (data, time) { // 群头像增加 } -} +}; const push528 = { - 0x8A: function(buf, time) { + 0x8A: function (buf, time) { let data = pb.decode(buf)[1]; if (Array.isArray(data)) data = data[0]; @@ -120,10 +120,10 @@ const push528 = { user_id, message_id: genC2CMessageId(user_id, data[3], data[6], data[5]), time }); }, - 0x8B: function(buf, time) { + 0x8B: function (buf, time) { return push528[0x8A].call(this, buf, time); }, - 0xB3: function(buf, time) { + 0xB3: function (buf, time) { const data = pb.decode(buf)[2]; const user_id = data[1], nickname = String(data[5].raw); this.fl.set(user_id, { @@ -134,18 +134,18 @@ const push528 = { remark: nickname, }); this.sl.delete(user_id); - this.getStrangerInfo(user_id).then(()=>{ + this.getStrangerInfo(user_id).then(() => { this.logger.info(`更新了好友列表,新增了好友 ${user_id}(${nickname})`); this.em("notice.friend.increase", { user_id, nickname, time }); }); }, - 0xD4: function(buf, time) { + 0xD4: function (buf, time) { const group_id = pb.decode(buf)[1]; this.getGroupInfo(group_id, true); }, - 0x3B: function(buf, time) { + 0x3B: function (buf, time) { const data = pb.decode(buf); const group_id = data[2]; this.em("notice.group.setting", { @@ -153,23 +153,23 @@ const push528 = { enable_show_title: data[3] > 0, }); }, - 0x27: function(buf, time) { + 0x27: function (buf, time) { let data = pb.decode(buf)[1]; if (Array.isArray(data)) data = data[0]; if (typeof sub0x27[data[2]] === "function") sub0x27[data[2]].call(this, data, time); }, - 0x122: function(buf, time) { + 0x122: function (buf, time) { const data = pb.decode(buf); - const eve = {time}; + const eve = { time }; Object.assign(eve, parsePoke.call(this, data)); this.em("notice.friend.poke", eve); }, - 0x115: function(buf, time) { + 0x115: function (buf, time) { // 正在输入 }, -} +}; function parsePoke(data) { let user_id, operator_id, action, suffix; @@ -188,7 +188,7 @@ function parsePoke(data) { operator_id = this.uin; if (!user_id) user_id = this.uin; - return {user_id, operator_id, action, suffix}; + return { user_id, operator_id, action, suffix }; } @@ -208,7 +208,7 @@ function onGroupSetting(group_id, field, enable, time) { } const push732 = { - 0x0C: function(group_id, buf, time) { + 0x0C: function (group_id, buf, time) { const operator_id = buf.readUInt32BE(6); const user_id = buf.readUInt32BE(16); let duration = buf.readUInt32BE(20); @@ -220,12 +220,12 @@ const push732 = { else if (user_id === this.uin) this.gl.get(group_id).shutup_time_me = duration ? (time + duration) : 0; this.gml.get(group_id).get(user_id).shutup_time = duration ? (time + duration) : 0; - } catch (e) {} + } catch (e) { } this.em("notice.group.ban", { group_id, operator_id, user_id, duration, time }); }, - 0x11: function(group_id, buf, time) { + 0x11: function (group_id, buf, time) { const data = pb.decode(buf.slice(7))[11]; const operator_id = data[1]; const msg = Array.isArray(data[3]) ? data[3][0] : data[3]; @@ -235,20 +235,20 @@ const push732 = { group_id, user_id, operator_id, message_id, time }); }, - 0x14: function(group_id, buf, time) { + 0x14: function (group_id, buf, time) { const data = pb.decode(buf.slice(7))[26]; if (data) { - const eve = {group_id, time}; + const eve = { group_id, time }; Object.assign(eve, parsePoke.call(this, data)); if (eve.action) this.em("notice.group.poke", eve); } }, - 0x06: function(group_id, buf, time) { + 0x06: function (group_id, buf, time) { if (buf[5] !== 1) return; onGroupSetting.call(this, group_id, "enable_guest", buf[10] > 0, time); }, - 0x0E: function(group_id, buf, time) { + 0x0E: function (group_id, buf, time) { if (buf[5] !== 1) return; const duration = buf.readInt32BE(10); if (buf[14] === 0) @@ -263,7 +263,7 @@ const push732 = { }); } }, - 0x0F: function(group_id, buf, time) { + 0x0F: function (group_id, buf, time) { if (buf[12] === 1) var field = "enable_upload_album"; else if (buf[12] === 2) @@ -271,7 +271,7 @@ const push732 = { var enable = buf[8] === 0x0 || buf[8] === 0x20; onGroupSetting.call(this, group_id, field, enable, time); }, - 0x10: function(group_id, buf, time) { + 0x10: function (group_id, buf, time) { if (buf[6] === 0x22) { let field; if (buf[buf.length - 2] === 0x08) @@ -296,7 +296,7 @@ const push732 = { try { this.gml.get(group_id).get(user_id).title = title; this.gml.get(group_id).get(user_id).title_expire_time = -1; - } catch(e) {} + } catch (e) { } return this.em("notice.group.title", { group_id, user_id, nickname, title @@ -332,14 +332,13 @@ function onOnlinePush(blob, seq) { for (let v of list) { v = jce.decode(v); rubbish.push(jce.encodeNested([ - this.uin, v[1], v[3], v[8], 0,0,0,0,0,0,0 - ])) + this.uin, v[1], v[3], v[8], 0, 0, 0, 0, 0, 0, 0 + ])); if (!this.sync_finished) continue; const time = v[5]; if (v[2] === 528) { const decoded = jce.decode(v[6]); const type = decoded[0], buf = decoded[10]; - // console.log(type, buf.toString("hex").replace(/(.)(.)/g, '$1$2 ')) if (typeof push528[type] === "function") push528[type].call(this, buf, time); } @@ -367,10 +366,10 @@ function onOnlinePushTrans(blob, seq) { if (buf[5] === 0 || buf[5] === 1) { const user_id = buf.readUInt32BE(6); const set = buf[10] > 0; - (async()=>{ + (async () => { try { (await this.getGroupMemberInfo(group_id, user_id)).data.role = (set ? "admin" : "member"); - } catch (e) {} + } catch (e) { } this.em("notice.group.admin", { group_id, user_id, set, time }); @@ -378,12 +377,12 @@ function onOnlinePushTrans(blob, seq) { } else if (buf[5] === 0xFF) { const operator_id = buf.readUInt32BE(6); const user_id = buf.readUInt32BE(10); - (async()=>{ + (async () => { try { this.gl.get(group_id).owner_id = user_id; (await this.getGroupMemberInfo(group_id, operator_id)).data.role = "member"; (await this.getGroupMemberInfo(group_id, user_id)).data.role = "owner"; - } catch (e) {} + } catch (e) { } this.em("notice.group.transfer", { group_id, operator_id, user_id, time }); @@ -396,12 +395,12 @@ function onOnlinePushTrans(blob, seq) { let operator_id, dismiss = false, member; try { member = this.gml.get(group_id).get(user_id); - } catch {} + } catch { } if (buf[9] === 0x82 || buf[9] === 0x2) { operator_id = user_id; try { this.gml.get(group_id).delete(user_id); - } catch {} + } catch { } } else { operator_id = buf.readUInt32BE(10); if (buf[9] === 0x01 || buf[9] === 0x81) @@ -413,12 +412,12 @@ function onOnlinePushTrans(blob, seq) { } else { try { this.gml.get(group_id).delete(user_id); - } catch {} + } catch { } } } try { this.gl.get(group_id).member_count--; - } catch {} + } catch { } this.em("notice.group.decrease", { group_id, user_id, operator_id, dismiss, member, time }); @@ -438,7 +437,7 @@ async function onGroupMsg(blob, seq) { const msg = await parseGroupMsg.call(this, o[1][1], o[1][2], o[1][3]); if (msg && msg.raw_message) { const sender = msg.sender; - this.logger.info(`recv from: [Group: ${msg.group_name}(${msg.group_id}), Member: ${sender.card?sender.card:sender.nickname}(${msg.user_id})] ` + msg.raw_message); + this.logger.info(`recv from: [Group: ${msg.group_name}(${msg.group_id}), Member: ${sender.card ? sender.card : sender.nickname}(${msg.user_id})] ` + msg.raw_message); this.em("message.group." + msg.sub_type, msg); } } catch (e) { diff --git a/lib/pb.js b/lib/pb.js index fa3645e0..72b7df0e 100644 --- a/lib/pb.js +++ b/lib/pb.js @@ -32,23 +32,23 @@ function _encode(writer, tag, value) { value = tmp; type = 0; } - if (typeof value === "number") + if (typeof value === "number") type = Number.isInteger(value) ? 0 : 1; const head = parseInt(tag) << 3 | type; writer.uint32(head); switch (type) { - case 0: - if (value < 0) - writer.sint64(value); - else - writer.int64(value); - break; - case 1: - writer.double(value); - break; - case 2: - writer.bytes(isBuffer(value) ? value : Buffer.from(value)); - break; + case 0: + if (value < 0) + writer.sint64(value); + else + writer.int64(value); + break; + case 1: + writer.double(value); + break; + case 2: + writer.bytes(isBuffer(value) ? value : Buffer.from(value)); + break; } } @@ -67,7 +67,7 @@ function encode(o) { } function long2int(long) { - const bigint = (BigInt(long.high)<<32n)|(BigInt(long.low)&0xffffffffn); + const bigint = (BigInt(long.high) << 32n) | (BigInt(long.low) & 0xffffffffn); const int = parseInt(long); return Number.isSafeInteger(int) ? int : bigint; } @@ -80,23 +80,23 @@ function decode(buf) { const tag = k >> 3, type = k & 0b111; let value; switch (type) { - case 0: - value = long2int(reader.int64()); - break; - case 1: - value = long2int(reader.fixed64()); - break; - case 2: - value = reader.bytes(); - let decoded; - try { - decoded = decode(value); - } catch {} - value = new Nested(value, decoded); - break; - case 5: - value = reader.fixed32(); - break; + case 0: + value = long2int(reader.int64()); + break; + case 1: + value = long2int(reader.fixed64()); + break; + case 2: + value = reader.bytes(); + let decoded; + try { + decoded = decode(value); + } catch { } + value = new Nested(value, decoded); + break; + case 5: + value = reader.fixed32(); + break; } if (Array.isArray(data[tag])) { data[tag].push(value); diff --git a/lib/service.js b/lib/service.js index ce0bb086..af9bc631 100644 --- a/lib/service.js +++ b/lib/service.js @@ -2,9 +2,9 @@ const net = require("net"); const http = require("http"); const https = require("https"); -const HttpsProxyAgent = require('https-proxy-agent'); +const HttpsProxyAgent = require("https-proxy-agent"); const tea = require("crypto-tea"); -const {randomBytes} = require("crypto"); +const { randomBytes } = require("crypto"); const fs = require("fs"); const pb = require("./pb"); const jce = require("./jce"); @@ -16,9 +16,9 @@ function int32ip2str(ip) { ip = ip & 0xffffffff; return [ ip & 0xff, - (ip & 0xff00 ) >> 8, - (ip & 0xff0000 ) >> 16, - (ip & 0xff000000 ) >> 24 & 0xff, + (ip & 0xff00) >> 8, + (ip & 0xff0000) >> 16, + (ip & 0xff000000) >> 24 & 0xff, ].join("."); } @@ -38,7 +38,7 @@ function buildHighwayUploadRequestPacket(o, cmd) { 6: this.apk.subid, 7: 4096, 8: cmd, - 10:2052, + 10: 2052, }, 2: { 2: o.buf.length, @@ -68,15 +68,15 @@ function buildHighwayUploadRequestPacket(o, cmd) { async function highwayUpload(ip, port, o, cmd) { ip = int32ip2str(ip); this.logger.trace(`highway ip:${ip} port:${port}`); - return new Promise((resolve)=>{ - const client = net.connect(port, ip, ()=>{ + return new Promise((resolve) => { + const client = net.connect(port, ip, () => { client.write(packet, client.end.bind(client)); }); client.on("end", resolve); client.on("close", resolve); client.on("error", resolve); var packet = buildHighwayUploadRequestPacket.call(this, o, cmd); - }) + }); } /** @@ -99,7 +99,7 @@ async function downloadFromWeb(url, headers, timeout, proxy, mime_type, maxsize headers = null; } } - const options = {timeout, headers}; + const options = { timeout, headers }; if (proxy && process.env.http_proxy) { try { const agent = new HttpsProxyAgent(process.env.http_proxy); @@ -108,9 +108,9 @@ async function downloadFromWeb(url, headers, timeout, proxy, mime_type, maxsize console.log(e); } } - return new Promise((resolve, reject)=>{ + return new Promise((resolve, reject) => { try { - const req = protocol.get(url, options, async(res)=>{ + const req = protocol.get(url, options, async (res) => { // 重定向一次(没有好的库暂时手动实现) if (String(res.statusCode).startsWith("3") && !redirect && res.headers["location"]) { try { @@ -125,7 +125,7 @@ async function downloadFromWeb(url, headers, timeout, proxy, mime_type, maxsize return; } if (mime_type && (!res.headers["content-type"] || !res.headers["content-type"].includes(mime_type))) { - reject("不是合法的"+mime_type+"文件。"); + reject("不是合法的" + mime_type + "文件。"); return; } if (res.headers["content-length"] && res.headers["content-length"] > maxsize) { @@ -133,20 +133,20 @@ async function downloadFromWeb(url, headers, timeout, proxy, mime_type, maxsize return; } let data = Buffer.alloc(0); - res.on("data", (chunk)=>{ + res.on("data", (chunk) => { data = Buffer.concat([data, chunk]); if (data.length >= maxsize) { res.destroy(); reject(`文件体积太大(maxsize=${maxsize})。`); } }); - res.on("end", ()=>{ + res.on("end", () => { resolve(data); }); }); - req.on("error", (e)=>{ + req.on("error", (e) => { reject(e.message); - }).on("timeout", ()=>{ + }).on("timeout", () => { req.destroy(); reject("connect ETIMEDOUT"); }); @@ -169,20 +169,20 @@ async function downloadWebRecord(url, proxy, timeout, headers = null) { } async function readFile(path, maxsize = MAX_UPLOAD_SIZE) { - const stream = fs.createReadStream(path, {highWaterMark: 1024 * 5120}); - return new Promise((resolve, reject)=>{ + const stream = fs.createReadStream(path, { highWaterMark: 1024 * 5120 }); + return new Promise((resolve, reject) => { let data = Buffer.alloc(0); - stream.on("data", (chunk)=>{ + stream.on("data", (chunk) => { data = Buffer.concat([data, chunk]); if (data.length >= maxsize) { stream.destroy(); reject(`文件体积太大(maxsize=${maxsize})。`); } }); - stream.on("end", ()=>{ + stream.on("end", () => { resolve(data); }); - stream.on("error", (e)=>{ + stream.on("error", (e) => { reject(e.message); }); }); @@ -191,7 +191,7 @@ async function readFile(path, maxsize = MAX_UPLOAD_SIZE) { /** * @this {import("./ref").Client} */ -async function getTcpServer() { +async function getServerList() { const key = Buffer.from("F0441F5FF42DA58FDCF7949ABA62D411", "hex"); const HttpServerListReq = jce.encodeStruct([ null, @@ -200,30 +200,34 @@ async function getTcpServer() { ]); const extra = { service: "ConfigHttp", - method: "HttpServerListReq", + method: "HttpServerListReq", }; - let body = jce.encodeWrapper({HttpServerListReq}, extra); + let body = jce.encodeWrapper({ HttpServerListReq }, extra); const len = Buffer.alloc(4); len.writeUInt32BE(body.length + 4); body = Buffer.concat([len, body]); body = tea.encrypt(body, key); - return await new Promise((resolve, reject)=>{ + return await new Promise((resolve, reject) => { const id = setTimeout(reject, 3000); - https.request("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp", {method: "POST"}, (res)=>{ + https.request("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp", { method: "POST" }, (res) => { let data = []; res.on("error", reject); - res.on("data", (chunk)=>data.push(chunk)); - res.on("end", ()=>{ + res.on("data", (chunk) => data.push(chunk)); + res.on("end", () => { try { clearTimeout(id); data = Buffer.concat(data); data = tea.decrypt(data, key).slice(4); const nested = jce.decodeWrapper(data); const parent = jce.decode(nested); - data = jce.decode(parent[2][0]); - resolve({ - ip: data[1], port: data[2] - }); + const list = []; + for (let v of parent[2]) { + v = jce.decode(v); + list.push({ + ip: v[1], port: v[2] + }); + } + resolve(list); } catch { reject(); } @@ -233,5 +237,5 @@ async function getTcpServer() { } module.exports = { - downloadWebImage, downloadWebRecord, highwayUpload, int32ip2str, readFile + downloadWebImage, downloadWebRecord, highwayUpload, int32ip2str, readFile, getServerList }; diff --git a/lib/sysmsg.js b/lib/sysmsg.js index c924c133..de0dda36 100644 --- a/lib/sysmsg.js +++ b/lib/sysmsg.js @@ -15,7 +15,7 @@ function genFriendRequestFlag(user_id, seq) { function parseFriendRequestFlag(flag) { const user_id = parseInt(flag.slice(0, 8), 16); const seq = BigInt("0x" + flag.slice(8)); - return {user_id, seq}; + return { user_id, seq }; } /** @@ -38,7 +38,7 @@ function parseGroupRequestFlag(flag) { const group_id = parseInt(flag.slice(8, 16), 16); const invite = parseInt(flag.slice(16, 17)); const seq = BigInt("0x" + flag.slice(17)); - return {user_id, group_id, seq, invite}; + return { user_id, group_id, seq, invite }; } const frd_buf = pb.encode({ @@ -80,7 +80,7 @@ async function getNewFriend() { user_id, nickname, source: String(v[50][5].raw), comment: String(v[50][4].raw), - sex: v[50][67]===0?"male":(v[50][67]===1?"famale":"unknown"), + sex: v[50][67] === 0 ? "male" : (v[50][67] === 1 ? "famale" : "unknown"), age: v[50][68], flag, time }); @@ -90,7 +90,7 @@ async function getNewFriend() { } } -const notify_types = {84:1,87:2,525:22}; +const notify_types = { 84: 1, 87: 2, 525: 22 }; const grp_buf = pb.encode({ 1: 10, 4: 1000, @@ -182,7 +182,7 @@ async function getNewGroup(type) { * @returns {import("./ref").ProtocolResponse} */ async function friendAction(flag, approve = true, remark = "", block = false) { - const {user_id, seq} = parseFriendRequestFlag(flag); + const { user_id, seq } = parseFriendRequestFlag(flag); const body = pb.encode({ 1: 1, 2: seq, @@ -191,14 +191,14 @@ async function friendAction(flag, approve = true, remark = "", block = false) { 5: 6, 6: 7, 8: { - 1: approve?2:3, + 1: approve ? 2 : 3, 52: String(remark), - 53: block?1:0 + 53: block ? 1 : 0 }, }); const blob = await this.sendUNI("ProfileService.Pb.ReqSystemMsgAction.Friend", body); const rsp = pb.decode(blob)[1]; - return {result: rsp[1], emsg: rsp[2]?String(rsp[2].raw):undefined}; + return { result: rsp[1], emsg: rsp[2] ? String(rsp[2].raw) : undefined }; } /** @@ -207,25 +207,25 @@ async function friendAction(flag, approve = true, remark = "", block = false) { * @returns {import("./ref").ProtocolResponse} */ async function groupAction(flag, approve = true, reason = "", block = false) { - const {user_id, group_id, seq, invite} = parseGroupRequestFlag(flag); + const { user_id, group_id, seq, invite } = parseGroupRequestFlag(flag); const body = pb.encode({ 1: 1, 2: seq, 3: user_id, 4: 1, 5: 3, - 6: invite?10016:31, - 7: invite?2:1, + 6: invite ? 10016 : 31, + 7: invite ? 2 : 1, 8: { - 1: approve?11:12, + 1: approve ? 11 : 12, 2: group_id, 50: String(reason), - 53: block?1:0, + 53: block ? 1 : 0, }, }); const blob = await this.sendUNI("ProfileService.Pb.ReqSystemMsgAction.Group", body); const rsp = pb.decode(blob)[1]; - return {result: rsp[1], emsg: rsp[2]?String(rsp[2].raw):undefined}; + return { result: rsp[1], emsg: rsp[2] ? String(rsp[2].raw) : undefined }; } module.exports = { diff --git a/lib/troop.js b/lib/troop.js index f5bc192a..bf3813fb 100644 --- a/lib/troop.js +++ b/lib/troop.js @@ -1,7 +1,7 @@ "use strict"; const querystring = require("querystring"); const https = require("https"); -const {uinAutoCheck} = require("./common"); +const { uinAutoCheck } = require("./common"); const pb = require("./pb"); const jce = require("./jce"); @@ -13,9 +13,9 @@ const jce = require("./jce"); * @returns {import("./ref").ProtocolResponse} */ async function setAdmin(group_id, user_id, enable = true) { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [group_id, user_id] = uinAutoCheck(group_id, user_id); const buf = Buffer.allocUnsafe(9); - buf.writeUInt32BE(group_id), buf.writeUInt32BE(user_id, 4), buf.writeUInt8(enable?1:0, 8); + buf.writeUInt32BE(group_id), buf.writeUInt32BE(user_id, 4), buf.writeUInt8(enable ? 1 : 0, 8); const blob = await this.sendUNI("OidbSvc.0x55c_1", buf); const result = pb.decode(blob)[3]; if (result === 0) { @@ -24,15 +24,15 @@ async function setAdmin(group_id, user_id, enable = true) { const new_role = enable ? "admin" : "member"; if (old_role !== new_role && old_role !== "owner") { this.gml.get(group_id).get(user_id).role = new_role; - setImmediate(()=>{ + setImmediate(() => { this.em("notice.group.admin", { group_id, user_id, set: !!enable }); }); } - } catch (e) {} + } catch (e) { } } - return {result}; + return { result }; } /** @@ -45,20 +45,20 @@ async function setAdmin(group_id, user_id, enable = true) { * @returns {import("./ref").ProtocolResponse} */ async function setTitle(group_id, user_id, title = "", duration = -1) { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [group_id, user_id] = uinAutoCheck(group_id, user_id); title = String(title); - duration = parseInt(duration)&0xffffffff; + duration = parseInt(duration) & 0xffffffff; const body = pb.encode({ 1: group_id, 3: [{ 1: user_id, 7: title, 5: title, - 6: duration?duration:-1 + 6: duration ? duration : -1 }] }); const blob = await this.sendUNI("OidbSvc.0x8fc_2", body); - return {result: pb.decode(blob)[3]}; + return { result: pb.decode(blob)[3] }; } /** @@ -70,12 +70,12 @@ async function setTitle(group_id, user_id, title = "", duration = -1) { * @returns {import("./ref").ProtocolResponse} */ async function doSetting(group_id, k, v) { - var [group_id] = uinAutoCheck(group_id); + [group_id] = uinAutoCheck(group_id); const settings = { shutupTime: 17, ingGroupName: 3, ingGroupMemo: 4, - } + }; const tag = settings[k]; if (!tag) throw new Error("unknown setting key"); @@ -95,7 +95,7 @@ async function doSetting(group_id, k, v) { * @returns {import("./ref").ProtocolResponse} */ async function setCard(group_id, user_id, card = "") { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [group_id, user_id] = uinAutoCheck(group_id, user_id); const MGCREQ = jce.encodeStruct([ 0, group_id, 0, [ jce.encodeNested([ @@ -104,16 +104,16 @@ async function setCard(group_id, user_id, card = "") { ] ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "mqq.IMService.FriendListServiceServantObj", - method: "ModifyGroupCardReq", + method: "ModifyGroupCardReq", }; - const body = jce.encodeWrapper({MGCREQ}, extra); + const body = jce.encodeWrapper({ MGCREQ }, extra); const blob = await this.sendUNI("friendlist.ModifyGroupCardReq", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); const result = parent[3].length > 0 ? 0 : 1; - return {result}; + return { result }; } /** @@ -124,13 +124,13 @@ async function setCard(group_id, user_id, card = "") { * @returns {import("./ref").ProtocolResponse} */ async function kickMember(group_id, user_id, block = false) { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [group_id, user_id] = uinAutoCheck(group_id, user_id); const body = pb.encode({ 1: group_id, 2: [{ 1: 5, 2: user_id, - 3: block?1:0, + 3: block ? 1 : 0, }], }); const blob = await this.sendUNI("OidbSvc.0x8a0_0", body); @@ -138,9 +138,9 @@ async function kickMember(group_id, user_id, block = false) { const result = o[2][1]; try { var member = this.gml.get(group_id).get(user_id); - } catch {} + } catch { } if (result === 0 && this.gml.has(group_id) && this.gml.get(group_id).delete(user_id)) { - setImmediate(()=>{ + setImmediate(() => { this.em("notice.group.decrease", { group_id, user_id, operator_id: this.uin, @@ -148,7 +148,7 @@ async function kickMember(group_id, user_id, block = false) { }); }); } - return {result}; + return { result }; } /** @@ -159,13 +159,13 @@ async function kickMember(group_id, user_id, block = false) { * @returns {import("./ref").ProtocolResponse} */ async function muteMember(group_id, user_id, duration = 1800) { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [group_id, user_id] = uinAutoCheck(group_id, user_id); duration = parseInt(duration); if (duration > 2592000 || duration < 0) duration = 2592000; const buf = Buffer.allocUnsafe(15); buf.writeUInt32BE(group_id), buf.writeUInt8(32, 4), buf.writeUInt16BE(1, 5); - buf.writeUInt32BE(user_id, 7), buf.writeUInt32BE(duration?duration:0, 11); + buf.writeUInt32BE(user_id, 7), buf.writeUInt32BE(duration ? duration : 0, 11); await this.sendUNI("OidbSvc.0x570_8", buf); } @@ -176,7 +176,7 @@ async function muteMember(group_id, user_id, duration = 1800) { * @returns {import("./ref").ProtocolResponse} */ async function quitGroup(group_id, dismiss = false) { - var [group_id] = uinAutoCheck(group_id); + [group_id] = uinAutoCheck(group_id); let command, buf = Buffer.allocUnsafe(8); if (dismiss) { command = 9; @@ -189,15 +189,15 @@ async function quitGroup(group_id, dismiss = false) { command, this.uin, buf ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "KQQ.ProfileService.ProfileServantObj", - method: "GroupMngReq", + method: "GroupMngReq", }; - const body = jce.encodeWrapper({GroupMngReq}, extra); + const body = jce.encodeWrapper({ GroupMngReq }, extra); const blob = await this.sendUNI("ProfileService.GroupMngReq", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); - return {result: parent[1]}; + return { result: parent[1] }; } /** @@ -207,8 +207,8 @@ async function quitGroup(group_id, dismiss = false) { * @returns {import("./ref").ProtocolResponse} */ async function pokeMember(group_id, user_id) { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); - const o = {1: user_id}; + [group_id, user_id] = uinAutoCheck(group_id, user_id); + const o = { 1: user_id }; if (this.gl.has(group_id) || !this.fl.has(group_id)) o[2] = group_id; else @@ -224,7 +224,7 @@ async function pokeMember(group_id, user_id) { * @returns {import("./ref").ProtocolResponse} */ async function addGroup(group_id, comment = "") { - var [group_id] = uinAutoCheck(group_id); + [group_id] = uinAutoCheck(group_id); comment = Buffer.from(String(comment)).slice(0, 255); const buf = Buffer.allocUnsafe(9 + comment.length); buf.writeUInt32BE(group_id), buf.writeUInt32BE(this.uin, 4), buf.writeUInt8(comment.length, 8); @@ -235,15 +235,15 @@ async function addGroup(group_id, comment = "") { null, "", null, "", "", 0 ]); const extra = { - req_id: this.seq_id + 1, + req_id: this.seq_id + 1, service: "KQQ.ProfileService.ProfileServantObj", - method: "GroupMngReq", + method: "GroupMngReq", }; - const body = jce.encodeWrapper({GroupMngReq}, extra); + const body = jce.encodeWrapper({ GroupMngReq }, extra); const blob = await this.sendUNI("ProfileService.GroupMngReq", body); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); - return {result: parent[1]}; + return { result: parent[1] }; } /** @@ -253,14 +253,14 @@ async function addGroup(group_id, comment = "") { * @returns {import("./ref").ProtocolResponse} */ async function inviteFriend(group_id, user_id) { - var [group_id, user_id] = uinAutoCheck(group_id, user_id); + [group_id, user_id] = uinAutoCheck(group_id, user_id); const body = pb.encode({ 1: group_id, - 2: {1: user_id} + 2: { 1: user_id } }); const blob = await this.sendUNI("OidbSvc.oidb_0x758", body); const result = pb.decode(blob)[4].raw.length > 6 ? 0 : 1; - return {result}; + return { result }; } /** @@ -271,9 +271,9 @@ async function inviteFriend(group_id, user_id) { * @returns {import("./ref").ProtocolResponse} */ async function setAnonymous(group_id, enable = true) { - var [group_id] = uinAutoCheck(group_id); + [group_id] = uinAutoCheck(group_id); const buf = Buffer.allocUnsafe(5); - buf.writeUInt32BE(group_id), buf.writeUInt8(enable?1:0, 4); + buf.writeUInt32BE(group_id), buf.writeUInt8(enable ? 1 : 0, 4); await this.sendUNI("OidbSvc.0x568_22", buf); } @@ -296,11 +296,11 @@ function parseAnonFlag(flag) { * @returns {import("./ref").ProtocolResponse} */ async function muteAnonymous(group_id, flag, duration = 1800) { - var [group_id] = uinAutoCheck(group_id); + [group_id] = uinAutoCheck(group_id); duration = parseInt(duration); if (duration > 2592000 || duration < 0) duration = 2592000; - const {id, nick} = parseAnonFlag(flag); + const { id, nick } = parseAnonFlag(flag); const body = querystring.stringify({ anony_id: id, group_code: group_id, @@ -310,14 +310,14 @@ async function muteAnonymous(group_id, flag, duration = 1800) { }); const cookie = (await this.getCookies("qqweb.qq.com")).data.cookies; try { - const rsp = await new Promise((resolve, reject)=>{ + const rsp = await new Promise((resolve, reject) => { https.request("https://qqweb.qq.com/c/anonymoustalk/blacklist", { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded", cookie } - }, (res)=>{ - res.on("data", (chunk)=>{ + }, (res) => { + res.on("data", (chunk) => { try { const data = JSON.parse(chunk); resolve({ @@ -327,16 +327,16 @@ async function muteAnonymous(group_id, flag, duration = 1800) { } catch (e) { reject(e); } - }) + }); }).on("error", reject).end(body); }); return rsp; } catch (e) { - return {result: -1, emsg: e.message}; + return { result: -1, emsg: e.message }; } } module.exports = { setAdmin, setTitle, setCard, doSetting, setAnonymous, muteAnonymous, - kickMember, muteMember, pokeMember, quitGroup, addGroup, inviteFriend, + kickMember, muteMember, pokeMember, quitGroup, addGroup, inviteFriend, }; diff --git a/lib/wtlogin/ecdh.js b/lib/wtlogin/ecdh.js index 6031f32c..33eaf1c4 100644 --- a/lib/wtlogin/ecdh.js +++ b/lib/wtlogin/ecdh.js @@ -1,13 +1,13 @@ "use strict"; const crypto = require("crypto"); -const {md5} = require("../common"); +const { md5 } = require("../common"); const OICQ_PUBLIC_KEY = Buffer.from("04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E", "hex"); /** * @link https://www.bookstack.cn/read/nodejs-api-doc-cn/crypto-class_ECDH.md */ -const self = crypto.createECDH('prime256v1'); +const self = crypto.createECDH("prime256v1"); const public_key = self.generateKeys(); // const private_key = self.getPrivateKey(); const share_key = md5(self.computeSecret(OICQ_PUBLIC_KEY).slice(0, 16)); diff --git a/lib/wtlogin/tlv.js b/lib/wtlogin/tlv.js index 6ed04966..d778d9c3 100644 --- a/lib/wtlogin/tlv.js +++ b/lib/wtlogin/tlv.js @@ -1,8 +1,8 @@ "use strict"; const crypto = require("crypto"); -const tea = require('crypto-tea'); +const tea = require("crypto-tea"); const Writer = require("./writer"); -const {md5} = require("../common"); +const { md5 } = require("../common"); const pb = require("../pb"); /** @@ -21,28 +21,28 @@ function packTlv(tag, ...args) { } const tlv_map = { - 0x01: function() { + 0x01: function () { return new Writer() .writeU16(1) // ip ver .writeBytes(crypto.randomBytes(4)) .writeU32(this.uin) - .write32(Date.now()&0xffffffff) + .write32(Date.now() & 0xffffffff) .writeBytes(Buffer.alloc(4)) //ip .writeU16(0); }, - 0x02: function(captcha) { + 0x02: function (captcha) { return new Writer() .writeU16(0) // sign ver .writeTlv(captcha) .writeTlv(this.captcha_sign); }, - 0x08: function() { + 0x08: function () { return new Writer() .writeU16(0) .writeU32(2052) .writeU16(0); }, - 0x18: function() { + 0x18: function () { return new Writer() .writeU16(1) // ping ver .writeU32(1536) @@ -52,19 +52,19 @@ const tlv_map = { .writeU16(0) .writeU16(0); }, - 0x100: function(emp = 0) { + 0x100: function (emp = 0) { return new Writer() .writeU16(1) // db buf ver .writeU32(7) // sso ver, dont over 7 .writeU32(this.apk.appid) - .writeU32(emp?2:this.apk.subid) + .writeU32(emp ? 2 : this.apk.subid) .writeU32(0) // app client ver .writeU32(this.apk.sigmap); }, - 0x104: function() { + 0x104: function () { return new Writer().writeBytes(this.t104); }, - 0x106: function(emp = 0) { + 0x106: function (emp = 0) { const body = new Writer() .writeU16(4) // tgtgt ver .writeBytes(crypto.randomBytes(4)) @@ -72,12 +72,12 @@ const tlv_map = { .writeU32(this.apk.appid) .writeU32(0) // app client ver .writeU64(this.uin) - .write32(Date.now()&0xffffffff) + .write32(Date.now() & 0xffffffff) .writeBytes(Buffer.alloc(4)) // dummy ip .writeU8(1) // save password .writeBytes(this.password_md5) .writeBytes(this.device.tgtgt) - .writeU32(emp?1:0) + .writeU32(emp ? 1 : 0) .writeU8(1) // guid available .writeBytes(this.device.guid) .writeU32(this.apk.subid) @@ -92,31 +92,31 @@ const tlv_map = { ])); return new Writer().writeBytes(tea.encrypt(body, key)); }, - 0x107: function() { + 0x107: function () { return new Writer() .writeU16(0) // pic type .writeU8(0) // captcha type .writeU16(0) // pic size .writeU8(1); // ret type }, - 0x108: function() { + 0x108: function () { return new Writer().writeBytes(this.ksid); }, - 0x109: function() { + 0x109: function () { return new Writer().writeBytes(md5(this.device.imei)); }, - 0x10a: function() { + 0x10a: function () { return new Writer().writeBytes(this.sig.tgt); }, - 0x116: function() { + 0x116: function () { return new Writer() .writeU8(0) .writeU32(this.apk.bitmap) .writeU32(0x10400) // sub sigmap .writeU8(1) // size of app id list - .writeU32(1600000226) // app id list[0] + .writeU32(1600000226); // app id list[0] }, - 0x124: function() { + 0x124: function () { return new Writer() .writeTlv(this.device.os_type.slice(0, 16)) .writeTlv(this.device.version.release.slice(0, 16)) @@ -125,7 +125,7 @@ const tlv_map = { .writeU16(0) .writeTlv(this.device.apn.slice(0, 16)); }, - 0x128: function() { + 0x128: function () { return new Writer() .writeU16(0) .writeU8(0) // guid new @@ -136,22 +136,22 @@ const tlv_map = { .writeTlv(this.device.guid.slice(0, 16)) .writeTlv(this.device.brand.slice(0, 16)); }, - 0x141: function() { + 0x141: function () { return new Writer() .writeU16(1) // ver .writeTlv(this.device.sim) .writeU16(2) // network type .writeTlv(this.device.apn); }, - 0x142: function() { + 0x142: function () { return new Writer() .writeU16(0) .writeTlv(this.apk.id.slice(0, 32)); }, - 0x143: function(d2) { + 0x143: function (d2) { return new Writer().writeBytes(d2); }, - 0x144: function() { + 0x144: function () { const body = new Writer() .writeU16(5) // tlv cnt .writeBytes(packTlv.call(this, 0x109)) @@ -161,54 +161,54 @@ const tlv_map = { .writeBytes(packTlv.call(this, 0x16e)); return new Writer().writeBytes(tea.encrypt(body.read(), this.device.tgtgt)); }, - 0x145: function() { + 0x145: function () { return new Writer().writeBytes(this.device.guid); }, - 0x147: function() { + 0x147: function () { return new Writer() .writeU32(this.apk.appid) .writeTlv(this.apk.ver.slice(0, 5)) .writeTlv(this.apk.sign); }, - 0x154: function() { + 0x154: function () { return new Writer().writeU32(this.seq_id); }, - 0x16a: function() { + 0x16a: function () { return new Writer().writeBytes(this.sig.srm_token); }, - 0x16e: function() { + 0x16e: function () { return new Writer().writeBytes(this.device.model); }, - 0x177: function() { + 0x177: function () { return new Writer() .writeU8(0x01) .writeU32(this.apk.buildtime) .writeTlv(this.apk.sdkver); }, - 0x187: function() { + 0x187: function () { return new Writer().writeBytes(md5(this.device.mac_address)); }, - 0x188: function() { + 0x188: function () { return new Writer().writeBytes(md5(this.device.android_id)); }, - 0x191: function() { + 0x191: function () { return new Writer().writeU8(0x82); }, - 0x193: function(ticket) { + 0x193: function (ticket) { return new Writer().writeBytes(ticket); }, - 0x194: function() { + 0x194: function () { return new Writer().writeBytes(this.device.imsi); }, - 0x202: function() { + 0x202: function () { return new Writer() .writeTlv(this.device.wifi_bssid.slice(0, 16)) .writeTlv(this.device.wifi_ssid.slice(0, 32)); }, - 0x401: function() { + 0x401: function () { return new Writer().writeBytes(crypto.randomBytes(16)); }, - 0x511: function() { + 0x511: function () { const domains = [ "tenpay.com", "openmobile.qq.com", "docs.qq.com", "connect.qq.com", "qzone.qq.com", "vip.qq.com", "qun.qq.com", "game.qq.com", "qqweb.qq.com", @@ -219,21 +219,21 @@ const tlv_map = { stream.writeU8(0x01).writeTlv(v); return stream; }, - 0x516: function() { + 0x516: function () { return new Writer().writeU32(0); }, - 0x521: function() { + 0x521: function () { return new Writer() .writeU32(0) // product type .writeU16(0); // const }, - 0x525: function() { + 0x525: function () { return new Writer() .writeU16(1) // tlv cnt .writeU16(0x536) // tag .writeTlv(Buffer.from([0x1, 0x0])); // zero }, - 0x52d: function() { + 0x52d: function () { const d = this.device; const buf = pb.encode({ 1: d.bootloader, @@ -254,6 +254,6 @@ const tlv_map = { * @param {import("../ref").Client} client * @returns {Function} */ -module.exports.getPacker = function(client) { +module.exports.getPacker = function (client) { return packTlv.bind(client); }; diff --git a/lib/wtlogin/wt.js b/lib/wtlogin/wt.js index d215416c..b9faf03e 100644 --- a/lib/wtlogin/wt.js +++ b/lib/wtlogin/wt.js @@ -6,7 +6,7 @@ const Readable = require("stream").Readable; const ecdh = require("./ecdh"); const Writer = require("./writer"); const tlv = require("./tlv"); -const {timestamp, md5} = require("../common"); +const { timestamp, md5 } = require("../common"); const jce = require("../jce"); const pb = require("../pb"); @@ -36,7 +36,7 @@ function encryptEMPBody(body) { * @returns {Buffer} */ function buildOICQPacket(body, emp = false) { - body = (emp?encryptEMPBody:encryptOICQBody).call(this, body); + body = (emp ? encryptEMPBody : encryptOICQBody).call(this, body); return new Writer() .writeU8(0x02) .writeU16(29 + body.length) // 1 + 27 + body.length + 1 @@ -45,7 +45,7 @@ function buildOICQPacket(body, emp = false) { .writeU16(1) // const .writeU32(this.uin) .writeU8(3) // const - .writeU8(emp?69:0x87) // encrypt type 7:0 69:emp 0x87:4 + .writeU8(emp ? 69 : 0x87) // encrypt type 7:0 69:emp 0x87:4 .writeU8(0) // const .writeU32(2) // const .writeU32(0) // app client ver @@ -104,7 +104,7 @@ function build0x0BPacket(cmd, body, seq = 0) { seq = seq ? seq : this.nextSeq(); this.logger.trace(`send:${cmd} seq:${seq}`); this.send_timestamp = Date.now(); - const type = cmd==="wtlogin.exchange_emp"?2:1; + const type = cmd === "wtlogin.exchange_emp" ? 2 : 1; let sso = new Writer() .writeWithLength(cmd) .writeWithLength(this.session_id) @@ -119,7 +119,7 @@ function build0x0BPacket(cmd, body, seq = 0) { .write32(seq) .writeU8(0) .writeWithLength(this.uin.toString()) - .writeBytes(tea.encrypt(sso, type===1?this.sig.d2key:Buffer.alloc(16))) + .writeBytes(tea.encrypt(sso, type === 1 ? this.sig.d2key : Buffer.alloc(16))) .read(); return new Writer().writeWithLength(body).read(); } @@ -147,13 +147,13 @@ async function passwordLogin(slider = true) { this.device.tgtgt = md5(d2key); return tokenLogin.call(this, d2); } - } catch {} + } catch { } this.logining = true; this.nextSeq(); const t = tlv.getPacker(this); let body = new Writer() .writeU16(9) - .writeU16(slider?24:23) + .writeU16(slider ? 24 : 23) .writeBytes(t(0x18)) .writeBytes(t(0x1)) .writeBytes(t(0x106)) @@ -315,15 +315,15 @@ async function exchangeEMP() { const pkt = build0x0BPacket.call(this, "wtlogin.exchange_emp", buildOICQPacket.call(this, body, true)); try { let blob = await this.send(pkt); - blob = tea.decrypt(blob.slice(16, blob.length-1), this.sig.ticket_key); - const stream = Readable.from(blob, {objectMode: false}); + blob = tea.decrypt(blob.slice(16, blob.length - 1), this.sig.ticket_key); + const stream = Readable.from(blob, { objectMode: false }); stream.read(5); const t = readTlv(stream, 2); if (t[0x119]) decodeT119.call(this, t[0x119]); else this.logger.debug("emp失败"); - } catch {} + } catch { } } /** @@ -369,25 +369,25 @@ async function tokenLogin(d2) { async function register(logout = false) { this.nextSeq(); const pb_buf = pb.encode({ - 1: [{1:46, 2:timestamp()}, {1:283, 2:0}] + 1: [{ 1: 46, 2: timestamp() }, { 1: 283, 2: 0 }] }); const SvcReqRegister = jce.encodeStruct([ this.uin, - logout?0:7, 0, "", logout?21:11, 0, 0, 0, 0, 0, logout?44:0, + logout ? 0 : 7, 0, "", logout ? 21 : 11, 0, 0, 0, 0, 0, logout ? 44 : 0, this.device.version.sdk, 1, "", 0, null, this.device.guid, 2052, 0, this.device.model, this.device.model, this.device.version.release, 1, 0, 0, null, 0, 0, "", 0, this.device.brand, this.device.brand, "", pb_buf, 0, null, 0, null, 1000, 98 ]); const extra = { service: "PushService", - method: "SvcReqRegister", + method: "SvcReqRegister", }; - const body = jce.encodeWrapper({SvcReqRegister}, extra); + const body = jce.encodeWrapper({ SvcReqRegister }, extra); const pkt = build0x0APacket.call(this, "StatSvc.register", body, 1); const blob = await this.send(pkt); const nested = jce.decodeWrapper(blob); const parent = jce.decode(nested); - return parent[9]?true:false; + return parent[9] ? true : false; } //decode tlv---------------------------------------------------------------------------------------------- @@ -400,7 +400,7 @@ async function register(logout = false) { function readTlv(stream, size) { const t = {}; var k; - while(true) { + while (true) { if (stream.readableLength < size) break; if (size === 1) @@ -411,30 +411,30 @@ function readTlv(stream, size) { k = stream.read(4).readInt32BE(); if (k === 255) break; - t[k] = stream.read(stream.read(2).readUInt16BE()) + t[k] = stream.read(stream.read(2).readUInt16BE()); } return t; } function decodeT119(data, token = false) { - const reader = Readable.from(tea.decrypt(data, this.device.tgtgt), {objectMode:false}); + const reader = Readable.from(tea.decrypt(data, this.device.tgtgt), { objectMode: false }); reader.read(2); const t = readTlv(reader, 2); readT11A.call(this, t[0x11a]); readT512.call(this, t[0x512]); this.sig = { - srm_token: t[0x16a]?t[0x16a]:this.sig.srm_token, - tgt: t[0x10a]?t[0x10a]:this.sig.tgt, - tgt_key: t[0x10d]?t[0x10d]:this.sig.tgt_key, - st_key: t[0x10e]?t[0x10e]:this.sig.st_key, - st_web_sig: t[0x103]?t[0x103]:this.sig.st_web_sig, - skey: t[0x120]?t[0x120]:this.sig.skey, - d2: t[0x143]?t[0x143]:this.sig.d2, - d2key: t[0x305]?t[0x305]:this.sig.d2key, - sig_key: t[0x133]?t[0x133]:this.sig.sig_key, - ticket_key: t[0x134]?t[0x134]:this.sig.ticket_key, - device_token: t[0x322]?t[0x322]:this.sig.device_token, - emp_time: token ? 0 : timestamp(), + srm_token: t[0x16a] ? t[0x16a] : this.sig.srm_token, + tgt: t[0x10a] ? t[0x10a] : this.sig.tgt, + tgt_key: t[0x10d] ? t[0x10d] : this.sig.tgt_key, + st_key: t[0x10e] ? t[0x10e] : this.sig.st_key, + st_web_sig: t[0x103] ? t[0x103] : this.sig.st_web_sig, + skey: t[0x120] ? t[0x120] : this.sig.skey, + d2: t[0x143] ? t[0x143] : this.sig.d2, + d2key: t[0x305] ? t[0x305] : this.sig.d2key, + sig_key: t[0x133] ? t[0x133] : this.sig.sig_key, + ticket_key: t[0x134] ? t[0x134] : this.sig.ticket_key, + device_token: t[0x322] ? t[0x322] : this.sig.device_token, + emp_time: token ? 0 : timestamp(), }; fs.writeFile( path.join(this.dir, "token"), @@ -447,22 +447,22 @@ function decodeT119(data, token = false) { this.sig.tgt, this.sig.device_token, ]), - ()=>{} + () => { } ); } function readT11A(data) { if (!data) return; - const stream = Readable.from(data, {objectMode:false}); + const stream = Readable.from(data, { objectMode: false }); stream.read(2); this.age = stream.read(1).readUInt8(); - this.sex = ["unknown","male","female"][stream.read(1).readUInt8()]; + this.sex = ["unknown", "male", "female"][stream.read(1).readUInt8()]; this.nickname = stream.read(stream.read(1).readUInt8() & 0xff); this.nickname = this.nickname ? String(this.nickname) : ""; } function readT512(data) { if (!data) return; - const stream = Readable.from(data, {objectMode:false}); + const stream = Readable.from(data, { objectMode: false }); let len = stream.read(2).readUInt16BE(); while (len-- > 0) { const domain = String(stream.read(stream.read(2).readUInt16BE())); @@ -496,8 +496,8 @@ function readT512(data) { * @this {import("../ref").Client} */ function decodeLoginResponse(blob, token = false) { - blob = tea.decrypt(blob.slice(16, blob.length-1), ecdh.share_key); - const stream = Readable.from(blob, {objectMode:false}); + blob = tea.decrypt(blob.slice(16, blob.length - 1), ecdh.share_key); + const stream = Readable.from(blob, { objectMode: false }); stream.read(2); const type = stream.read(1).readUInt8(); stream.read(2); @@ -531,21 +531,21 @@ function decodeLoginResponse(blob, token = false) { const url = String(t[0x192]); this.logger.info(`收到滑动验证码,请访问以下地址完成滑动:${url} !!!注意:请提前打开浏览器F12->Network(网络),从滑动的返回结果中取出ticket并输入 (成功率非100%,若提示环境异常请再试一次)`); - return this.em("system.login.slider", {url}); + return this.em("system.login.slider", { url }); } else { return passwordLogin.call(this, false); } } if (t[0x165]) { - const stream = Readable.from(t[0x105], {objectMode:false}); + const stream = Readable.from(t[0x105], { objectMode: false }); const signLen = stream.read(2).readUInt16BE(); stream.read(2); this.captcha_sign = stream.read(signLen); const image = stream.read(); - const filepath = path.join(this.dir, `captcha.jpg`); + const filepath = path.join(this.dir, "captcha.jpg"); fs.writeFileSync(filepath, image); this.logger.info(`收到图片验证码,已保存到文件(${filepath}),请查看并输入: `); - return this.em("system.login.captcha", {image}); + return this.em("system.login.captcha", { image }); } const message = "[登陆失败]未知格式的验证码。"; this.logger.error(message); @@ -558,33 +558,33 @@ function decodeLoginResponse(blob, token = false) { const url = String(t[0x204]); this.logger.info("需要扫码验证设备信息,验证地址:" + url); this.logger.debug("验证完毕后重新调用login()即可成功登陆。"); - return this.em("system.login.device", {url}); + return this.em("system.login.device", { url }); } if (t[0x149]) { - const stream = Readable.from(t[0x149], {objectMode:false}); + const stream = Readable.from(t[0x149], { objectMode: false }); stream.read(2); const title = stream.read(stream.read(2).readUInt16BE()).toString(); const content = stream.read(stream.read(2).readUInt16BE()).toString(); const message = `[${title}]${content}`; this.logger.error(message); - return this.em("system.login.error", {code: type, message}); + return this.em("system.login.error", { code: type, message }); } if (t[0x146]) { - const stream = Readable.from(t[0x146], {objectMode:false}); - const version = stream.read(4); //? + const stream = Readable.from(t[0x146], { objectMode: false }); + const version = stream.read(4); const title = stream.read(stream.read(2).readUInt16BE()).toString(); const content = stream.read(stream.read(2).readUInt16BE()).toString(); const message = `[${title}]${content}`; this.logger.error(message); - return this.em("system.login.error", {code: type, message}); + return this.em("system.login.error", { code: type, message }); } this.logger.error("[登陆失败]未知错误。"); this.em("system.login.error", { code: type, - message: `[登陆失败]未知错误。` + message: "[登陆失败]未知错误。" }); } diff --git a/package-lock.json b/package-lock.json index dc659c5f..17f8227d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,156 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/generator": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", + "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.11", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", + "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/types": "^7.12.11" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", + "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "dev": true, + "requires": { + "@babel/types": "^7.12.10" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", + "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", + "dev": true, + "requires": { + "@babel/types": "^7.12.11" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@babel/parser": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", + "dev": true + }, + "@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "@babel/traverse": { + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", + "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.11", + "@babel/generator": "^7.12.11", + "@babel/helper-function-name": "^7.12.11", + "@babel/helper-split-export-declaration": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/types": "^7.12.12", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", + "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -68,6 +218,18 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz", "integrity": "sha512-kwbcs0jySLxzLsa2nWUAGOd/s21WU1jebrEdtzhsj1D4Yps1EOuyI1Qcu+FD56dL7NRNIJtDDjcqIG22NwkgLw==" }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -76,6 +238,181 @@ "debug": "4" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "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" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "crypto-tea": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/crypto-tea/-/crypto-tea-0.2.0.tgz", @@ -94,6 +431,236 @@ "ms": "^2.1.1" } }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", + "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "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.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.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 + } + } + }, + "esrecurse": { + "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": "^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": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "flatted": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "dev": true + } + } + }, "flatted": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", @@ -109,11 +676,76 @@ "universalify": "^0.1.0" } }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -123,6 +755,12 @@ "debug": "4" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "image-size": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.9.3.tgz", @@ -131,16 +769,112 @@ "queue": "6.0.1" } }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "jce": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/jce/-/jce-0.1.7.tgz", "integrity": "sha512-94lI/5YP9U8pr4AW7fMoicUGNE+aFh5Av0z1chmqicuTJ8WkeWPePrOzMjgb92MVX6gg71t0ixvxaoTO0Tow5g==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -149,6 +883,22 @@ "graceful-fs": "^4.1.6" } }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, "log4js": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", @@ -166,11 +916,97 @@ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "protobufjs": { "version": "6.10.1", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", @@ -191,6 +1027,12 @@ "long": "^4.0.0" } }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "queue": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.1.tgz", @@ -199,11 +1041,121 @@ "inherits": "~2.0.3" } }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "rfdc": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==" }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "streamroller": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz", @@ -221,10 +1173,146 @@ } } }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "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": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "dev": true, + "requires": { + "ajv": "^7.0.2", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ajv": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz", + "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/package.json b/package.json index db5b898f..7341d760 100644 --- a/package.json +++ b/package.json @@ -35,5 +35,9 @@ "jce": "^0.1.7", "log4js": "^6.3.0", "protobufjs": "^6.10.1" + }, + "devDependencies": { + "babel-eslint": "^10.1.0", + "eslint": "^7.17.0" } } diff --git a/test.js b/test.js index f22579aa..b4028b3b 100644 --- a/test.js +++ b/test.js @@ -1,6 +1,4 @@ "use strict"; -const fs = require("fs"); -const path = require("path"); const crypto = require("crypto"); const oicq = require("./client"); @@ -58,7 +56,7 @@ function account() { bot.on("internal.timeout", (data)=>{ console.log(data); - }) + }); bot.on("request", (data)=>{ console.log("收到request事件", data); @@ -74,7 +72,7 @@ function account() { return account(); } password(); - }) + }); } function password() { console.log("请输入密码:"); @@ -82,7 +80,7 @@ function password() { input = input.toString().trim(); const password_md5 = crypto.createHash("md5").update(input).digest(); bot.login(password_md5); - }) + }); } function loop() { const help = `※友情提示:将log_level设为trace可获得详细的收发包信息。 @@ -95,36 +93,36 @@ function loop() { const cmd = input.split(" ")[0]; const param = input.replace(cmd, "").trim(); switch (cmd) { - case "bye": - bot.logout(); - process.stdin.destroy(); - break; - case "send": - const abc = param.split(" "); - const target = parseInt(abc[0]); - let res; - if (bot.gl.has(target)) - res = await bot.sendGroupMsg(target, abc[1]); - else - res = await bot.sendPrivateMsg(target, abc[1]); - console.log("发送消息结果", res); - break; - case "eval": - try { - let res = eval(param); - if (res instanceof Promise) - res = await res; - console.log("执行结果", res); - } catch (e) { - console.log(e.stack); - } - break; - default: - console.log("指令错误。"); - console.log(help); - break; + case "bye": + bot.logout(); + process.stdin.destroy(); + break; + case "send": + const abc = param.split(" "); + const target = parseInt(abc[0]); + let res; + if (bot.gl.has(target)) + res = await bot.sendGroupMsg(target, abc[1]); + else + res = await bot.sendPrivateMsg(target, abc[1]); + console.log("发送消息结果", res); + break; + case "eval": + try { + let res = eval(param); + if (res instanceof Promise) + res = await res; + console.log("执行结果", res); + } catch (e) { + console.log(e.stack); + } + break; + default: + console.log("指令错误。"); + console.log(help); + break; } - } + }; process.stdin.on("data", listener); }