From ace7c07d49b9c74792a85b2b966f927cc0e44130 Mon Sep 17 00:00:00 2001 From: takayama Date: Tue, 10 Nov 2020 20:29:27 +0900 Subject: [PATCH 01/11] fix anon --- lib/message/chat.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/message/chat.js b/lib/message/chat.js index 3294d01f..e47453f9 100644 --- a/lib/message/chat.js +++ b/lib/message/chat.js @@ -46,7 +46,7 @@ async function sendMsg(target, message, escape, type) { throw new Error("empty message"); } rsp = await _sendMsg({2: builder.elems}, builder.isLong()); - if (!builder.isLong() && rsp.result === 0 && rsp.data && rsp.data.message_id === "" && !anon) { + if (!builder.isLong() && rsp.result === 0 && rsp.data && rsp.data.message_id === "" && !builder.anon) { this.logger.warn(`此消息将尝试作为长消息再发送一次。`); return await _sendMsg({2: builder.elems}, true); } diff --git a/package-lock.json b/package-lock.json index 059c48d4..fe9b0d73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.10.4", + "version": "1.10.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 00fdc1e2..46ad3ecb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.10.4", + "version": "1.10.5", "description": "QQ protocol!", "main": "client.js", "scripts": { From 0f5a6da11ff3cf74c7c55a8e369e056c926da039 Mon Sep 17 00:00:00 2001 From: takayama Date: Tue, 10 Nov 2020 23:27:14 +0900 Subject: [PATCH 02/11] img len --- lib/message/builder.js | 2 +- lib/message/chat.js | 2 +- lib/message/storage.js | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/message/builder.js b/lib/message/builder.js index cb876575..2758fce4 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -538,7 +538,7 @@ class Builder { this.stat.face_cnt * 23 + this.stat.sface_cnt * 42 + this.stat.bface_cnt * 135 + - this.stat.img_cnt * (this.type?90:304); + this.stat.img_cnt * (this.type?90:295); this.length *= 1.05; } diff --git a/lib/message/chat.js b/lib/message/chat.js index e47453f9..6e4109c8 100644 --- a/lib/message/chat.js +++ b/lib/message/chat.js @@ -197,7 +197,7 @@ async function toLongMessageElems(uin, rich, is_group) { }, })); try { - var resid = await uploadMultiMsg.call(this, uin, compressed, is_group); + var resid = await uploadMultiMsg.call(this, uin, compressed); } catch (e) { throw new Error("fail to upload multi msg"); } diff --git a/lib/message/storage.js b/lib/message/storage.js index 5f9efc94..b8b354ce 100644 --- a/lib/message/storage.js +++ b/lib/message/storage.js @@ -203,10 +203,9 @@ async function uploadPtt(target, buf, md5, codec) { * @this {import("../ref").Client} * @param {Number} target * @param {Buffer} compressed - * @param {Number} is_group * @returns {Promise} resid */ -async function uploadMultiMsg(target, compressed, is_group) { +async function uploadMultiMsg(target, compressed) { const body = pb.encode({ 1: 1, 2: 5, @@ -217,10 +216,10 @@ async function uploadMultiMsg(target, compressed, is_group) { 1: target, 2: compressed.length, 3: common.md5(compressed), - 4: is_group?3:1, + 4: 3, 5: 0, }], - 8: is_group?1:2, + 8: 1, }); const blob = await this.sendUNI("MultiMsg.ApplyUp", body); const rsp = pb.decode(blob)[2]; From 7b2a0fed19de3946736dddd33bb3386bf091dde5 Mon Sep 17 00:00:00 2001 From: takayama Date: Wed, 11 Nov 2020 01:58:11 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client.js | 61 +++++++++--------------------------------- device.js | 43 ++++++++++++++++++++++++++++- lib/individual.js | 2 +- lib/message/storage.js | 14 +++++----- lib/pb.js | 2 +- lib/ref.d.ts | 25 ++++++++++------- lib/resource.js | 2 +- lib/service.js | 2 +- lib/wtlogin/tlv.js | 26 +++++++++--------- lib/wtlogin/wt.js | 6 ++--- 10 files changed, 96 insertions(+), 87 deletions(-) diff --git a/client.js b/client.js index 827f564b..6b77a1c1 100644 --- a/client.js +++ b/client.js @@ -20,7 +20,7 @@ const {getErrorMessage} = require("./exception"); const BUF0 = Buffer.alloc(0); const server_list = [ - {ip:"msfwifi.3g.qq.com",port:8080,ping:null}, + {ip:"msfwifi.3g.qq.com", port:8080}, ]; function buildApiRet(retcode, data = null, error = null) { @@ -41,28 +41,8 @@ class Client extends net.Socket { } class AndroidClient extends Client { reconn_flag = true; - logger; - config; status = Client.OFFLINE; - kickoff_reconn = false; - ignore_self = true; - - // default phone - apkid = "com.tencent.mobileqq"; - apkver = "8.4.1.2703"; - apkname = "A8.4.1.2703aac4"; - apksign = Buffer.from([166, 183, 69, 191, 36, 162, 194, 119, 82, 119, 22, 246, 243, 110, 182, 141]); - buildtime = 1591690260; - appid = 16; - sub_appid = 537064989; - bitmap = 184024956; - sigmap = 34869472; - sdkver = "6.0.0.2433"; - ksid; - device; - - uin = 0; - password_md5; + nickname = ""; age = 0; sex = "unknown"; @@ -81,8 +61,6 @@ class AndroidClient extends Client { session_id = crypto.randomBytes(4); random_key = crypto.randomBytes(16); - captcha_sign; - t104; sig = { srm_token: BUF0, @@ -105,9 +83,7 @@ class AndroidClient extends Client { const2 = crypto.randomBytes(4).readUInt32BE(); const3 = crypto.randomBytes(1)[0]; - dir; - - constructor(uin, config = {}) { + constructor(uin, config) { super(); this.uin = uin; @@ -120,32 +96,20 @@ class AndroidClient extends Client { ...config }; this.config = config; - this.dir = createCacheDir(config.data_dir, uin); - this.logger = log4js.getLogger(`[BOT:${uin}]`); this.logger.level = config.log_level; - this.ignore_self = config.ignore_self; - this.kickoff_reconn = config.kickoff; - - if (config.platform == 3) - this.sub_appid = 537061176; - else if (config.platform == 2) { - this.sub_appid = 537065549; - this.apkid = "com.tencent.minihd.qq"; - this.apkver = "5.8.9.3460"; - this.apkname = "A5.8.9.3460"; - this.apksign = Buffer.from([170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199]); - this.buildtime = 1595836208; - this.bitmap = 150470524; - this.sigmap = 1970400; - } + this.ignore_self = !!config.ignore_self; + this.kickoff_reconn = !!config.kickoff; const filepath = path.join(this.dir, `device-${uin}.json`); if (!fs.existsSync(filepath)) this.logger.info("创建了新的设备文件:" + filepath); - this.device = device(filepath); - this.ksid = Buffer.from(`|${this.device.imei}|` + this.apkname); + this.device = device.getDeviceInfo(filepath); + this.apk = device.getApkInfo(config.platform); + if (config.platform == 3) + this.apk.subid = 537061176; + this.ksid = Buffer.from(`|${this.device.imei}|` + this.apk.name); this.on("error", (err)=>{ this.logger.error(err.message); @@ -301,7 +265,6 @@ class AndroidClient extends Client { sub_type = "kickoff"; if (this.kickoff_reconn) { this.logger.info("3秒后重新连接.."); - this.ksid = Buffer.from(`|${this.device.imei}|` + this.apkname); setTimeout(this.login.bind(this), 3000); } else { this.terminate(); @@ -674,8 +637,6 @@ class AndroidClient extends Client { } } -//---------------------------------------------------------------------------------------------------- - /** * @deprecated */ @@ -707,6 +668,8 @@ function createCacheDir(dir, uin) { */ function setGlobalConfig() {} +//---------------------------------------------------------------------------------------------------- + /** * @param {Number} uin * @param {JSON} config diff --git a/device.js b/device.js index 338dfc46..018df8f6 100644 --- a/device.js +++ b/device.js @@ -70,7 +70,7 @@ function genDevice(filepath) { * @param {String} filepath * @returns {import("./lib/ref").Device} */ -module.exports = function(filepath) { +function getDeviceInfo(filepath) { var d; if (fs.existsSync(filepath)) { d = JSON.parse(fs.readFileSync(filepath)); @@ -110,3 +110,44 @@ module.exports = function(filepath) { device.guid = md5(Buffer.concat([Buffer.from(device.imei), Buffer.from(device.mac_address)])); return device; }; + +const apk = { + 1: { + id: "com.tencent.mobileqq", + name: "A8.4.1.2703aac4", + version: "8.4.1.2703", + ver: "8.4.1", + sign: Buffer.from([166, 183, 69, 191, 36, 162, 194, 119, 82, 119, 22, 246, 243, 110, 182, 141]), + buildtime: 1591690260, + appid: 16, + subid: 537064989, + bitmap: 184024956, + sigmap: 34869472, + sdkver: "6.0.0.2428", + }, + 2: { + id: "com.tencent.minihd.qq", + name: "A5.8.9.3460", + version: "5.8.9.3460", + ver: "5.8.9", + sign: Buffer.from([170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199]), + buildtime: 1595836208, + appid: 16, + subid: 537065549, + bitmap: 150470524, + sigmap: 1970400, + sdkver: "6.0.0.2433", + } +} + +/** + * @param {Number} platform + * @returns {import("./lib/ref").ApkInfo} + */ +function getApkInfo(platform) { + return apk[platform] ? apk[platform] : apk[2]; +} + +module.exports = { + getDeviceInfo, getApkInfo +} diff --git a/lib/individual.js b/lib/individual.js index 940b04bd..72311ba3 100644 --- a/lib/individual.js +++ b/lib/individual.js @@ -193,7 +193,7 @@ async function setSign(sign = "") { 3: { 1: 109, 2: {6: 825110830}, - 3: this.apkver.substr(0, 5) + 3: this.apk.ver }, 5: { 1: this.uin, diff --git a/lib/message/storage.js b/lib/message/storage.js index b8b354ce..fc43d741 100644 --- a/lib/message/storage.js +++ b/lib/message/storage.js @@ -63,7 +63,7 @@ async function imageStore(group_id, imgs) { 8: 9, 9: 1, 12: 1000, - 13: this.apkver, + 13: this.apk.version, 15: 1006, }); } @@ -104,7 +104,7 @@ async function offPicUp(user_id, imgs) { 12: 1, 13: 1, 16: 1000, - 17: this.apkver, + 17: this.apk.version, 22: 1, }); } @@ -164,7 +164,7 @@ async function uploadPtt(target, buf, md5, codec) { 8: 9, 9: 4, 11: 0, - 10: this.apkver, + 10: this.apk.version, 12: 1, 13: 1, 14: codec, @@ -187,7 +187,7 @@ async function uploadPtt(target, buf, md5, codec) { } const url = `http://${int32ip2str(ip)}:${port}/?` + querystring.stringify(params); const headers = { - "User-Agent": `QQ/${this.apkver} CFNetwork/1126`, + "User-Agent": `QQ/${this.apk.version} CFNetwork/1126`, "Net-Type": "Wifi" }; await new Promise((resolve)=>{ @@ -211,7 +211,7 @@ async function uploadMultiMsg(target, compressed) { 2: 5, 3: 9, 4: 3, - 5: this.apkver, + 5: this.apk.version, 6: [{ 1: target, 2: compressed.length, @@ -260,7 +260,7 @@ async function downloadMultiMsg(resid, bu) { 2: 5, 3: 9, 4: 3, - 5: this.apkver, + 5: this.apk.version, 7: [{ 1: resid, 2: 3, @@ -275,7 +275,7 @@ async function downloadMultiMsg(resid, bu) { let url = port == 443 ? "https://ssl.htdata.qq.com" : `http://${ip}:${port}`; url += rsp[2].raw; const headers = { - "User-Agent": `QQ/${this.apkver} CFNetwork/1126`, + "User-Agent": `QQ/${this.apk.version} CFNetwork/1126`, "Net-Type": "Wifi" }; return new Promise((resolve, reject)=>{ diff --git a/lib/pb.js b/lib/pb.js index 9836deb9..ee6168b2 100644 --- a/lib/pb.js +++ b/lib/pb.js @@ -122,7 +122,7 @@ function encodeOIDB(cmd, body) { 2: isNaN(type) ? 1 : type, 3: 0, 4: body, - 6: "android " + this.apkver.substr(0, 5), + 6: "android " + this.apk.ver, }); } diff --git a/lib/ref.d.ts b/lib/ref.d.ts index 35919496..ba53b3a4 100644 --- a/lib/ref.d.ts +++ b/lib/ref.d.ts @@ -54,6 +54,20 @@ export interface Sig { device_token?: Buffer, } +export interface ApkInfo { + id: string, + name: string, + version: string, + ver: string, + sign: Buffer, + buildtime: number, + appid: number, + subid: number, + bitmap: number, + sigmap: number, + sdkver: string, +} + export interface ProtocolResponse { result: number, emsg?: string, @@ -76,16 +90,7 @@ export class Client extends oicq.Client { status: Symbol; kickoff_reconn: boolean; - apkid: string; - apkver: string; - apkname: string; - apksign: Buffer; - buildtime: number; - appid: number; - sub_appid: number; - bitmap: number; - sigmap: number; - sdkver: string; + apk: ApkInfo; ksid: string | Buffer; device: Device; diff --git a/lib/resource.js b/lib/resource.js index d9816e7d..0290281e 100644 --- a/lib/resource.js +++ b/lib/resource.js @@ -196,7 +196,7 @@ async function getGI(group_id, no_cache = false) { return {result: 0, data: ginfo}; const body = pb.encode({ - 1: this.sub_appid, + 1: this.apk.subid, 2: [{ 1: group_id, 2: { diff --git a/lib/service.js b/lib/service.js index ba32ceaa..27cf6327 100644 --- a/lib/service.js +++ b/lib/service.js @@ -38,7 +38,7 @@ function buildHighwayUploadRequestPackets(o, cmd, seq = crypto.randomBytes(2).re 2: String(this.uin), 3: "PicUp.DataUp", 4: seq++, - 6: this.sub_appid, + 6: this.apk.subid, 7: 4096, 8: cmd, 10:2052, diff --git a/lib/wtlogin/tlv.js b/lib/wtlogin/tlv.js index 57f8cf20..2700a2d4 100644 --- a/lib/wtlogin/tlv.js +++ b/lib/wtlogin/tlv.js @@ -46,7 +46,7 @@ const tlv_map = { return new Writer() .writeU16(1) // ping ver .writeU32(1536) - .writeU32(this.appid) + .writeU32(this.apk.appid) .writeU32(0) // app client ver .writeU32(this.uin) .writeU16(0) @@ -56,10 +56,10 @@ const tlv_map = { return new Writer() .writeU16(1) // db buf ver .writeU32(7) // sso ver, dont over 7 - .writeU32(this.appid) - .writeU32(emp?2:this.sub_appid) + .writeU32(this.apk.appid) + .writeU32(emp?2:this.apk.subid) .writeU32(0) // app client ver - .writeU32(this.sigmap);// sigmap + .writeU32(this.apk.sigmap); }, 0x104: function() { return new Writer().writeBytes(this.t104); @@ -69,7 +69,7 @@ const tlv_map = { .writeU16(4) // tgtgt ver .writeBytes(crypto.randomBytes(4)) .writeU32(7) // sso ver - .writeU32(this.appid) + .writeU32(this.apk.appid) .writeU32(0) // app client ver .writeU64(this.uin) .write32(Date.now()&0xffffffff) @@ -80,7 +80,7 @@ const tlv_map = { .writeU32(emp?1:0) .writeU8(1) // guid available .writeBytes(this.device.guid) - .writeU32(this.sub_appid) + .writeU32(this.apk.subid) .writeU32(1) // login type password .writeTlv(String(this.uin)) .writeU16(0) @@ -108,7 +108,7 @@ const tlv_map = { 0x116: function() { return new Writer() .writeU8(0) - .writeU32(this.bitmap) + .writeU32(this.apk.bitmap) .writeU32(0x10400) // sub sigmap .writeU8(1) // size of app id list .writeU32(1600000226) // app id list[0] @@ -143,7 +143,7 @@ const tlv_map = { 0x142: function() { return new Writer() .writeU16(0) - .writeTlv(this.apkid.slice(0, 32)); + .writeTlv(this.apk.id.slice(0, 32)); }, 0x144: function() { const body = new Writer() @@ -160,9 +160,9 @@ const tlv_map = { }, 0x147: function() { return new Writer() - .writeU32(this.appid) - .writeTlv(this.apkver.slice(0, 5)) - .writeTlv(this.apksign); + .writeU32(this.apk.appid) + .writeTlv(this.apk.ver.slice(0, 5)) + .writeTlv(this.apk.sign); }, 0x154: function() { return new Writer().writeU32(this.seq_id); @@ -176,8 +176,8 @@ const tlv_map = { 0x177: function() { return new Writer() .writeU8(0x01) - .writeU32(this.buildtime) - .writeTlv(this.sdkver); + .writeU32(this.apk.buildtime) + .writeTlv(this.apk.sdkver); }, 0x187: function() { return new Writer().writeBytes(md5(this.device.mac_address)); diff --git a/lib/wtlogin/wt.js b/lib/wtlogin/wt.js index 7c6f9974..9f65bc25 100644 --- a/lib/wtlogin/wt.js +++ b/lib/wtlogin/wt.js @@ -64,8 +64,8 @@ function buildOICQPacket(body, emp = false) { function build0x0APacket(cmd, body, type) { this.logger.trace(`send:${cmd} seq:${this.seq_id}`); let sso = new Writer().writeU32(this.seq_id) - .writeU32(this.sub_appid) - .writeU32(this.sub_appid) + .writeU32(this.apk.subid) + .writeU32(this.apk.subid) .writeBytes(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00])) // unknown .writeWithLength(this.sig.tgt) .writeWithLength(cmd) @@ -350,7 +350,7 @@ function decodeT119(data) { // decodeT130.call(this, t[0x130]); // this.t528 = t[0x528]; // this.t530 = t[0x530]; - this.ksid = t[0x108]; + // this.ksid = t[0x108]; // if (t[0x186]) // decodeT186.call(this, t[0x186]); readT11A.call(this, t[0x11a]); From e2ad8e9058160ca699cd35ea2b58f5720f88c0e6 Mon Sep 17 00:00:00 2001 From: takayama Date: Wed, 11 Nov 2020 02:40:43 +0900 Subject: [PATCH 04/11] add CQ:music --- client.js | 2 +- docs/project.md | 2 +- lib/message/builder.js | 18 ++++++- lib/message/chat.js | 13 +++++ lib/message/music.js | 111 +++++++++++++++++++++++++++++++++++++++++ lib/message/parser.js | 5 ++ 6 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 lib/message/music.js diff --git a/client.js b/client.js index 6b77a1c1..bc4be833 100644 --- a/client.js +++ b/client.js @@ -129,7 +129,7 @@ class AndroidClient extends Client { this.reconn_flag = false; setTimeout(()=>{ this._connect(this.register.bind(this)); - }, 1000); + }, 500); } }); diff --git a/docs/project.md b/docs/project.md index fcd35602..908e5f32 100644 --- a/docs/project.md +++ b/docs/project.md @@ -87,7 +87,7 @@ CQ码是指字符串格式下用于表示多媒体内容的方式,形如: |anonymous||◯|发匿名,[CQ:anonymous,ignore=1]
ignore可省略,为0时匿名失败不发送| |notice|◯||群公告| |file|◯||群文件| -|music|✕|✕| +|music|◯|◯|[CQ:music,type=qq,id=xxxxxx]
[CQ:music,type=163,id=xxxxxx]| |video|✕|✕| |location|◯|◯|[CQ:location,address=江西省九江市修水县,lat=29.063940,lng=114.339610]| |contact|◯|✕|联系人或群推荐 diff --git a/lib/message/builder.js b/lib/message/builder.js index 2758fce4..3f78aba7 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -4,6 +4,7 @@ const fs = require("fs"); const path = require("path"); const crypto = require("crypto"); const spawn = require("child_process"); +const music = require("./music"); const {downloadWebImage, downloadWebRecord} = require("../service"); const {uploadPtt, uploadImages, setPrivateImageNested, setGroupImageNested, getAnonInfo} = require("./storage"); const common = require("../common"); @@ -30,7 +31,8 @@ class Builder { ptts = []; flashs = []; jsons = []; - xmls = []; + xmls = []; + b77 = []; anon; stat = { length: 0, @@ -357,6 +359,17 @@ class Builder { this.buildJsonElem(obj, "收到[[应用]地图]消息,请升级QQ版本查看"); } + async buildMusicElem(cq) { + const {type, id} = cq; + try { + const buf = await music.build.call(this.c, this.target, type, id, this.type); + this.b77.push(buf); + } catch (e) { + // console.log(e) + this.c.logger.warn(`音乐获取失败:type=${type},id=${id}`); + } + } + buildShareElem(cq) { let {url, title, content, image} = cq; if (!url || !title) @@ -479,6 +492,9 @@ class Builder { case "location": this.buildLocationElem(data); break; + case "music": + await this.buildMusicElem(data); + break; case "share": this.buildShareElem(data); break; diff --git a/lib/message/chat.js b/lib/message/chat.js index 6e4109c8..a4dedf0a 100644 --- a/lib/message/chat.js +++ b/lib/message/chat.js @@ -34,6 +34,9 @@ async function sendMsg(target, message, escape, 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}); } @@ -241,6 +244,16 @@ async function toLongMessageElems(uin, rich, is_group) { ]; } +/** + * @this {import("../ref").Client} + */ +async function sendB77RichMsg(buf) { + try { + await this.sendUNI("OidbSvc.0xb77_9", buf); + } catch {} + return {result: 0, data: {message_id: "该消息暂不支持"}}; +} + function genSelfMessageId(user_id, seq, random, timestamp) { const buf = Buffer.allocUnsafe(12); buf.writeUInt32BE(user_id), buf.writeUInt16BE(seq, 4), buf.writeUInt16BE(random, 6), buf.writeUInt32BE(timestamp, 8); diff --git a/lib/message/music.js b/lib/message/music.js new file mode 100644 index 00000000..132e5f2c --- /dev/null +++ b/lib/message/music.js @@ -0,0 +1,111 @@ +"use strict"; +const {URL} = require("url"); +const http = require("http"); +const https = require("https"); +const pb = require("../pb"); + +function parse(o) { + const tag = o.meta.music.tag, data = {}; + if (tag === "QQ音乐") { + data.type = "qq"; + const url = new URL(o.meta.music.jumpUrl); + data.id = url.searchParams.get("songid"); + } else if (tag === "网易云音乐") { + data.type = "163"; + const url = new URL(o.meta.music.musicUrl); + data.id = url.searchParams.get("id"); + } else { + throw new Error("unknown music type"); + } + return data; +} + +async function qwerty(url) { + return new Promise((resolve, reject)=>{ + const protocol = url.startsWith("https") ? https : http; + protocol.get(url, (res)=>{ + let data = ""; + res.setEncoding("utf8"); + res.on("data", chunk=>data+=chunk); + res.on("end", ()=>{ + resolve(data); + }); + }).on("error", reject); + }) +} + +async function getQQSongInfo(id) { + let rsp = await qwerty(`https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"songinfo":{"method":"get_song_detail_yqq","param":{"song_type":0,"song_mid":"","song_id":${id}},"module":"music.pf_song_detail_svr"}}`); + rsp = JSON.parse(rsp).songinfo.data.track_info; + let mid = rsp.mid, title = rsp.name, album = rsp.album.mid, singer = "unknown"; + try { + singer = rsp.singer[0].name; + } 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 { + title: title, + singer: singer, + jumpUrl: `https://i.y.qq.com/v8/playsong.html?platform=11&appshare=android_qq&appversion=10030010&hosteuin=oKnlNenz7i-s7c**&songmid=${mid}&type=0&appsongtype=1&_wv=1&source=qq&ADTAG=qfshare`, + musicUrl: rsp.purl, + preview: `http://y.gtimg.cn/music/photo_new/T002R180x180M000${album}.jpg`, + }; +} + +async function get163SongInfo(id) { + let rsp = await qwerty(`http://music.163.com/api/song/detail/?id=${id}&ids=[${id}]`); + rsp = JSON.parse(rsp).songs[0]; + 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, + preview: rsp.artists[0].picUrl, + }; +} + +/** + * @this {import("../ref").Client} + * @returns {Buffer} + */ +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); + 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); + } else { + throw new Error("unknown music type"); + } + + return pb.encode({ + 1: appid, + 2: 1, + 3: style, + 4: this.uin, + 5: { + 1: 1, + 2: "0.0.0", + 3: appname, + 4: appsign + }, + 10: bu, + 11: target, + 12: { + 10: title, + 11: singer, + 12: title, + 13: jumpUrl, + 14: preview, + 16: musicUrl, + } + }); +} + +module.exports = { + parse, build +}; diff --git a/lib/message/parser.js b/lib/message/parser.js index 55514973..95d3cc45 100644 --- a/lib/message/parser.js +++ b/lib/message/parser.js @@ -2,6 +2,7 @@ const zlib = require("zlib"); const cheerio = require("cheerio"); const querystring = require("querystring"); +const music = require("./music"); const {downloadMultiMsg, getGroupFileUrl} = require("./storage"); const pb = require("../pb"); @@ -195,6 +196,7 @@ async function parseXmlElem(o) { async function parseJsonElem(o) { o = JSON.parse(zlib.unzipSync(o[1].raw.slice(1))); + // console.log(o) let type, data = {}; if (o.app === "com.tencent.map") { type = "location"; @@ -206,6 +208,9 @@ async function parseJsonElem(o) { type = "notice"; data.title = Buffer.from(o.meta.mannounce.title, "base64").toString(); data.content = Buffer.from(o.meta.mannounce.text, "base64").toString(); + } else if (o.app === "com.tencent.structmsg" && o.view === "music") { + type = "music"; + data = music.parse(o); } else { throw new Error("unknown json msg"); } From c05dba6865ae3d3da244d6d5040bbed7a7f82db5 Mon Sep 17 00:00:00 2001 From: takayama Date: Thu, 12 Nov 2020 02:59:53 +0900 Subject: [PATCH 05/11] music --- lib/message/builder.js | 5 ++--- lib/message/music.js | 5 ----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/message/builder.js b/lib/message/builder.js index 3f78aba7..bde70afd 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -362,7 +362,7 @@ class Builder { async buildMusicElem(cq) { const {type, id} = cq; try { - const buf = await music.build.call(this.c, this.target, type, id, this.type); + const buf = await music.build(this.target, type, id, this.type); this.b77.push(buf); } catch (e) { // console.log(e) @@ -543,8 +543,7 @@ class Builder { await this.buildElem(v.type, v.data); } } else if (message) { - message = String(message); - await this.buildFromString(message, escape); + await this.buildFromString(String(message), escape); } await Promise.all(this.tasks); await uploadImages.call(this.c, this.target, this.imgs, this.type); diff --git a/lib/message/music.js b/lib/message/music.js index 132e5f2c..d035cda0 100644 --- a/lib/message/music.js +++ b/lib/message/music.js @@ -64,10 +64,6 @@ async function get163SongInfo(id) { }; } -/** - * @this {import("../ref").Client} - * @returns {Buffer} - */ async function build(target, type, id, bu) { var appid, appname, appsign, style = 4; if (type == "qq") { @@ -86,7 +82,6 @@ async function build(target, type, id, bu) { 1: appid, 2: 1, 3: style, - 4: this.uin, 5: { 1: 1, 2: "0.0.0", From 7f0919333bbd5f33d94190ceba31401645434896 Mon Sep 17 00:00:00 2001 From: takayama Date: Thu, 12 Nov 2020 16:23:43 +0900 Subject: [PATCH 06/11] readFile (/dev/random bug) --- lib/individual.js | 15 +++++++------- lib/message/builder.js | 38 ++++++++++++++++++------------------ lib/service.js | 44 ++++++++++++++++++++++++++++-------------- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/lib/individual.js b/lib/individual.js index 72311ba3..b5cdfa95 100644 --- a/lib/individual.js +++ b/lib/individual.js @@ -1,7 +1,6 @@ "use strict"; -const fs = require("fs"); const {uinAutoCheck, md5} = require("./common"); -const {downloadWebImage, highwayUpload} = require("./service"); +const {downloadWebImage, highwayUpload, readFile} = require("./service"); const pb = require("./pb"); const jce = require("./jce"); @@ -19,17 +18,19 @@ async function setPortrait(file) { if (file.startsWith("base64://")) { buf = Buffer.from(file.replace("base64://", ""), "base64"); } else if (file.startsWith("http")) { - buf = await downloadWebImage(file); + try { + buf = await downloadWebImage(file); + } catch (e) { + throw new Error(e); + } } else { file = file.replace(/^file:\/{2,3}/, ""); try { - buf = await fs.promises.readFile(file) + buf = await readFile(file); } catch (e) { - throw new Error("Local file not exists: " + file); + throw new Error(e); } } - if (!buf || !buf.length) - throw new Error("Fail to get file: " + file); } const body = pb.encode({ 1281: { diff --git a/lib/message/builder.js b/lib/message/builder.js index bde70afd..4693af53 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -5,7 +5,7 @@ const path = require("path"); const crypto = require("crypto"); const spawn = require("child_process"); const music = require("./music"); -const {downloadWebImage, downloadWebRecord} = require("../service"); +const {downloadWebImage, downloadWebRecord, readFile} = require("../service"); const {uploadPtt, uploadImages, setPrivateImageNested, setGroupImageNested, getAnonInfo} = require("./storage"); const common = require("../common"); @@ -207,15 +207,18 @@ class Builder { fs.unlink(filepath, ()=>{}); throw new Error("bad file"); } - } catch (e) { + } catch { const task = (async()=>{ - const buf = await downloadWebImage.call(this.c, file, proxy=="1", timeout); - if (buf) { - img.buf = buf; - img.size = buf.length; - img.md5 = common.md5(buf); - fs.writeFile(filepath, img.md5.toString("hex") + img.size, ()=>{}); + try { + var buf = await downloadWebImage(file, proxy=="1", timeout); + } catch (e) { + this.c.logger.warn(`下载网络图片失败 ${file} 失败。`); + return this.c.logger.warn(e); } + img.buf = buf; + img.size = buf.length; + img.md5 = common.md5(buf); + fs.writeFile(filepath, img.md5.toString("hex") + img.size, ()=>{}); })(); this.tasks.push(task); } @@ -234,13 +237,11 @@ class Builder { if (md5.length !== 16) { try { file = file.replace(/^file:\/{2,3}/, ""); - buf = await fs.promises.readFile(file); - if (buf.length > 31457280) - return; + buf = await readFile(file); md5 = common.md5(buf), size = buf.length; } catch (e) { this.c.logger.warn(`获取本地图片 ${file} 失败。`); - return; + return this.c.logger.warn(e); } } //只有md5和size @@ -302,7 +303,7 @@ class Builder { } if (!buf) { if (file.startsWith("http://") || file.startsWith("https://")) - file = await downloadWebRecord.call(this.c, file, proxy=="1", timeout); + file = await downloadWebRecord(file, proxy=="1", timeout); else if (file.startsWith("base64://")) file = Buffer.from(file.replace("base64://", ""), "base64"); buf = await audioTrans.call(this.c, cache_filepath, file); @@ -310,9 +311,8 @@ class Builder { const head = buf.slice(0, 7).toString(); codec = head.includes("SILK") ? 1 : 0; } catch (e) { - this.c.logger.debug(e); this.c.logger.warn(`音频文件 ${url} 处理失败。`); - return; + return this.c.logger.debug(e); } md5 = common.md5(buf), size = buf.length; try { @@ -583,7 +583,7 @@ async function audioTrans(cache_filepath, file) { let filepath, tmp; if (typeof file === "string") { filepath = file; - file = await fs.promises.readFile(filepath); + file = await readFile(filepath, 0xfffffff); } else { tmp = Math.random() + "" + Date.now(); filepath = path.join(path.dirname(cache_filepath), tmp); @@ -602,9 +602,9 @@ async function audioTrans(cache_filepath, file) { if (tmp) fs.unlink(filepath, ()=>{}); try { - const target = await fs.promises.readFile(cache_filepath); - this.logger.debug(`成功转换了一个音频。`); - resolve(target); + const amr = await fs.promises.readFile(cache_filepath); + this.logger.info(`ffmpeg成功转换了一个音频。`); + resolve(amr); } catch (e) { this.logger.warn(`音频转码到amr失败,请确认你的ffmpeg可以处理此转换。`); reject(); diff --git a/lib/service.js b/lib/service.js index 27cf6327..91b456dd 100644 --- a/lib/service.js +++ b/lib/service.js @@ -4,6 +4,7 @@ const http = require("http"); const https = require("https"); const HttpsProxyAgent = require('https-proxy-agent'); const crypto = require("crypto"); +const fs = require("fs"); const pb = require("./pb"); const common = require("./common"); const MAX_UPLOAD_SIZE = 31457280; @@ -93,7 +94,6 @@ async function highwayUpload(ip, port, o, cmd) { } /** - * @this {import("./ref").Client} * @param {String} url * @param {Number} timeout * @param {Boolean} proxy @@ -111,7 +111,7 @@ async function downloadFromWeb(url, timeout, proxy, mime_type, maxsize = MAX_UPL const agent = new HttpsProxyAgent(process.env.http_proxy); options.agent = agent; } catch (e) { - this.logger.warn(e); + console.log(e); } } return new Promise((resolve, reject)=>{ @@ -131,15 +131,15 @@ async function downloadFromWeb(url, timeout, proxy, mime_type, maxsize = MAX_UPL return; } if (res.headers["content-length"] && res.headers["content-length"] > maxsize) { - reject(url + " 文件体积太大。"); + reject(url + ` 文件体积太大(maxsize=${maxsize})。`); return; } let data = Buffer.alloc(0); res.on("data", (chunk)=>{ data = Buffer.concat([data, chunk]); - if (data.length > maxsize) { + if (data.length >= maxsize) { res.destroy(); - reject(url + " 文件体积太大。"); + reject(url + ` 文件体积太大(maxsize=${maxsize})。`); } }); res.on("end", ()=>{ @@ -155,23 +155,37 @@ async function downloadFromWeb(url, timeout, proxy, mime_type, maxsize = MAX_UPL } /** - * @this {import("./ref").Client} * @param {String} url * @param {Boolean} proxy * @param {Number} timeout */ async function downloadWebImage(url, proxy, timeout) { - try { - return await downloadFromWeb.call(this, url, timeout, proxy, "image"); - } catch (e) { - this.logger.warn(e); - return; - } + return await downloadFromWeb(url, timeout, proxy, "image"); } async function downloadWebRecord(url, proxy, timeout) { - return await downloadFromWeb.call(this, url, timeout, proxy, "", 0xfffffff); + return await downloadFromWeb(url, timeout, proxy, "", 0xfffffff); } -module.exports = { - downloadWebImage, downloadWebRecord, highwayUpload, int32ip2str +async function readFile(path, maxsize = MAX_UPLOAD_SIZE) { + const stream = fs.createReadStream(path, {highWaterMark: 1024 * 5120}); + return new Promise((resolve, reject)=>{ + let data = Buffer.alloc(0); + stream.on("data", (chunk)=>{ + data = Buffer.concat([data, chunk]); + if (data.length >= maxsize) { + stream.destroy(); + reject(path + ` 文件体积太大(maxsize=${maxsize})。`); + } + }); + stream.on("end", ()=>{ + resolve(data); + }); + stream.on("error", (e)=>{ + reject(e.message); + }); + }); } + +module.exports = { + downloadWebImage, downloadWebRecord, highwayUpload, int32ip2str, readFile +}; From 7b04380399a1d579a7ff0432697a45ad40e8802f Mon Sep 17 00:00:00 2001 From: takayama Date: Thu, 12 Nov 2020 17:01:10 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=E5=90=88=E5=B9=B6face&sface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/project.md | 3 +-- lib/message/builder.js | 58 ++++++++++++++++++++---------------------- lib/message/parser.js | 2 +- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/docs/project.md b/docs/project.md index 908e5f32..88ad96cb 100644 --- a/docs/project.md +++ b/docs/project.md @@ -77,8 +77,7 @@ CQ码是指字符串格式下用于表示多媒体内容的方式,形如: |[CQ码]|收|发|说明| |-|-|-|-| |at|◯|◯|[CQ:at,qq=123456,text=@ABC,dummy=0]
text用来定义@不到时的输出
dummy设为1可以假@| -|face|◯|◯|[CQ:face,id=104] -|sface|◯|◯|此表情HD协议不支持,[CQ:sface,id=271,text=/吃瓜]| +|face|◯|◯|[CQ:face,id=104]| |bface|◯|◯|原创表情,[CQ:bface,file=xxxxxxxx,text=摸头]| |dice&rps|◯|◯|骰子和猜拳:
[CQ:dice,id=1]
[CQ:rps,id=1]| |image|◯|◯|参考 [图片](https://github.com/howmanybots/onebot/blob/master/v11/specs/message/segment.md#%E5%9B%BE%E7%89%87)| diff --git a/lib/message/builder.js b/lib/message/builder.js index 4693af53..31016d05 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -95,39 +95,37 @@ class Builder { ++this.stat.at_cnt; } buildFaceElem(cq) { - let {id} = cq; - id = parseInt(id); - if (id < 0 || id > 0xff || isNaN(id)) - return this.c.logger.warn("不正确的表情ID:" + id); - const old = Buffer.allocUnsafe(2); - old.writeUInt16BE(0x1441 + id); - this.elems.push({ - 2: { - 1: id, - 2: old, - 11: FACE_OLD_BUF - } - }); - ++this.stat.face_cnt; - } - buildSFaceElem(cq) { let {id, text} = cq; id = parseInt(id); - if (id <= 0xff || isNaN(id)) + if (id < 0 || id > 0xffff || isNaN(id)) return this.c.logger.warn("不正确的表情ID:" + id); - if (!text) text = "/" + id; - this.elems.push({ - 53: { - 1: 33, + if (id <= 0xff) { + const old = Buffer.allocUnsafe(2); + old.writeUInt16BE(0x1441 + id); + this.elems.push({ 2: { 1: id, - 2: text, - 3: text - }, - 3: 1 - } - }); - ++this.stat.sface_cnt; + 2: old, + 11: FACE_OLD_BUF + } + }); + ++this.stat.face_cnt; + } else { + if (!text) + text = "/" + id; + this.elems.push({ + 53: { + 1: 33, + 2: { + 1: id, + 2: text, + 3: text + }, + 3: 1 + } + }); + ++this.stat.sface_cnt; + } } buildBFaceElem(cq) { try { @@ -467,10 +465,8 @@ class Builder { this.buildAtElem(data); break; case "face": - this.buildFaceElem(data); - break; case "sface": - this.buildSFaceElem(data); + this.buildFaceElem(data); break; case "bface": this.buildBFaceElem(data); diff --git a/lib/message/parser.js b/lib/message/parser.js index 95d3cc45..29c57955 100644 --- a/lib/message/parser.js +++ b/lib/message/parser.js @@ -103,7 +103,7 @@ async function parseMessage(rich, from = 0) { msg.data.file = o[2][1][7].raw.toString("hex") + (o[2][1][2]?o[2][1][2]:""); ignore_text = true; } else if (o[1] === 33) { - msg.type = "sface"; + msg.type = "face"; msg.data.id = o[2][1]; msg.data.text = String(o[2][2].raw); } From 509385dd27efe8d09c88bab62683e8193c13ed45 Mon Sep 17 00:00:00 2001 From: takayama Date: Thu, 12 Nov 2020 21:18:33 +0900 Subject: [PATCH 08/11] add face map --- lib/message/builder.js | 5 ++++- lib/message/face.js | 28 ++++++++++++++++++++++++++++ lib/message/parser.js | 6 +++++- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 lib/message/face.js diff --git a/lib/message/builder.js b/lib/message/builder.js index 31016d05..14227548 100644 --- a/lib/message/builder.js +++ b/lib/message/builder.js @@ -5,6 +5,7 @@ const path = require("path"); const crypto = require("crypto"); const spawn = require("child_process"); const music = require("./music"); +const face = require("./face"); const {downloadWebImage, downloadWebRecord, readFile} = require("../service"); const {uploadPtt, uploadImages, setPrivateImageNested, setGroupImageNested, getAnonInfo} = require("./storage"); const common = require("../common"); @@ -111,7 +112,9 @@ class Builder { }); ++this.stat.face_cnt; } else { - if (!text) + if (face.map[id]) + text = face.map[id]; + else if (!text) text = "/" + id; this.elems.push({ 53: { diff --git a/lib/message/face.js b/lib/message/face.js new file mode 100644 index 00000000..d42a3e90 --- /dev/null +++ b/lib/message/face.js @@ -0,0 +1,28 @@ +"use strict"; + +const map = { + 260: "/搬砖中", + 261: "/忙到飞起", + 262: "/脑阔疼", + 263: "/沧桑", + 264: "/捂脸", + 265: "/辣眼睛", + 266: "/哦哟", + 267: "/头秃", + 268: "/问号脸", + 269: "/暗中观察", + 270: "/emm", + 271: "/吃瓜", + 272: "/呵呵哒", + 273: "/我酸了", + 274: "/太南了", + 276: "/辣椒酱", + 277: "/汪汪", + 278: "/汗", + 279: "/打脸", + 280: "/击掌", +}; + +module.exports = { + map, +}; diff --git a/lib/message/parser.js b/lib/message/parser.js index 29c57955..ae964ff4 100644 --- a/lib/message/parser.js +++ b/lib/message/parser.js @@ -3,6 +3,7 @@ const zlib = require("zlib"); const cheerio = require("cheerio"); const querystring = require("querystring"); const music = require("./music"); +const face = require("./face"); const {downloadMultiMsg, getGroupFileUrl} = require("./storage"); const pb = require("../pb"); @@ -105,7 +106,10 @@ async function parseMessage(rich, from = 0) { } else if (o[1] === 33) { msg.type = "face"; msg.data.id = o[2][1]; - msg.data.text = String(o[2][2].raw); + 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); } break; case 9999: From d23899926ed5a6173e278ba0dd1cc9c307c35ae4 Mon Sep 17 00:00:00 2001 From: takayama Date: Thu, 12 Nov 2020 21:19:04 +0900 Subject: [PATCH 09/11] fix highway upload overseas --- lib/message/storage.js | 4 ++-- lib/service.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/message/storage.js b/lib/message/storage.js index fc43d741..6eefedad 100644 --- a/lib/message/storage.js +++ b/lib/message/storage.js @@ -84,7 +84,7 @@ async function imageStore(group_id, imgs) { v[6] = [v[6]]; v[7] = [v[7]]; } - const index = i % v[6].length; + const index = i % v[6].slice(0, 2).length; imgs[i].key = v[8].raw; tasks.push(highwayUpload.call(this, v[6][index], v[7][index], imgs[i], 2)); } @@ -124,7 +124,7 @@ async function offPicUp(user_id, imgs) { v[7] = [v[7]]; v[8] = [v[8]]; } - const index = i % v[7].length; + const index = i % v[7].slice(0, 2).length; imgs[i].key = v[9].raw; tasks.push(highwayUpload.call(this, v[7][index], v[8][index], imgs[i], 1)); } diff --git a/lib/service.js b/lib/service.js index 91b456dd..f5276ca3 100644 --- a/lib/service.js +++ b/lib/service.js @@ -74,6 +74,7 @@ function buildHighwayUploadRequestPackets(o, cmd, seq = crypto.randomBytes(2).re */ 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, ()=>{ let n = 0; From e3459613295102beefcbb0f3b6a32c4572175c8f Mon Sep 17 00:00:00 2001 From: takayama Date: Fri, 13 Nov 2020 01:41:27 +0900 Subject: [PATCH 10/11] finish emp --- client.js | 22 ++++++++++++++-------- docs/project.md | 26 +++++++++++++------------- lib/ref.d.ts | 1 + lib/wtlogin/wt.js | 33 +++++++++++++++++---------------- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/client.js b/client.js index bc4be833..6d435646 100644 --- a/client.js +++ b/client.js @@ -74,6 +74,7 @@ class AndroidClient extends Client { sig_key: BUF0, ticket_key: BUF0, device_token: BUF0, + emp_time: timestamp(), }; cookies = {}; @@ -223,14 +224,16 @@ class AndroidClient extends Client { return; this.heartbeat = setInterval(async()=>{ this.doCircle(); - if (Date.now() - this.send_timestamp > 240000) - core.getMsg.call(this); try { await wt.heartbeat.call(this); - } catch (e) { - this.logger.warn("Heartbeat timeout!"); - if (Date.now() - this.recv_timestamp > 10000) - this.destroy(); + } catch { + try { + await wt.heartbeat.call(this); + } catch { + this.logger.warn("Heartbeat timeout!"); + if (Date.now() - this.recv_timestamp > 15000) + this.destroy(); + } } }, 60000); } @@ -350,6 +353,9 @@ class AndroidClient extends Client { } } doCircle() { + wt.exchangeEMP.call(this); + if (Date.now() - this.send_timestamp > 120000) + core.getMsg.call(this); for (let time of this.seq_cache.keys()) { if (timestamp() - time >= 60) this.seq_cache.delete(time); @@ -567,7 +573,7 @@ class AndroidClient extends Client { /////////////////////////////////////////////////// async getCookies(domain) { - // await wt.exchangeEMP(); + await wt.exchangeEMP.call(this); if (domain && !this.cookies[domain]) return buildApiRet(100, null, {code: -1, message: "unknown domain"}); let cookies = `uin=o${this.uin}; skey=${this.sig.skey};`; @@ -577,7 +583,7 @@ class AndroidClient extends Client { } async getCsrfToken() { - // await wt.exchangeEMP(); + await wt.exchangeEMP.call(this); let token = 5381; for (let v of this.sig.skey) token = token + (token << 5) + v; diff --git a/docs/project.md b/docs/project.md index 88ad96cb..fe051996 100644 --- a/docs/project.md +++ b/docs/project.md @@ -5,18 +5,18 @@ ---- -|[消息]|文字和表情|长消息|图片|语音|合并转发|xml/json|匿名| +|[消息]|文字和表情|长消息|图片|语音|合并转发|分享|匿名| |-|-|-|-|-|-|-|-| -|好友|◯|◯|◯|◯||✕|| -|群聊|◯|◯|◯|◯||✕|◯| -|讨论组|◯|◯|◯|◯||✕|✕| -|临时会话|◯|◯|◯|✕|✕|✕|| +|好友|◯|◯|◯|◯||◯|| +|群聊|◯|◯|◯|◯||◯|◯| +|讨论组|◯|◯|◯|◯|||| +|临时会话|◯|◯|◯||||| ---- |[好友功能]|API|事件| |-|-|-| -|好友列表|◯|◯(好友增加)| +|好友列表|◯|◯(好友增减)| |陌生人列表|◯|| |处理申请|◯|◯| |撤回消息|◯|◯| @@ -29,12 +29,12 @@ |[群功能]|API|事件| |-|-|-| -|群列表|◯|◯(群增加)| -|成员列表|◯|◯(成员增加)| +|群列表|◯|◯(群增减)| +|成员列表|◯|◯(成员增减)| |踢人|◯|◯| |禁言|◯|◯| |撤回|◯|◯| -|修改名片|◯|✕| +|修改名片|◯|| |修改群名|◯|◯| |群公告|◯|◯| |其他设置|✕|◯| @@ -45,9 +45,9 @@ |转让|✕|◯| |解散|◯|◯| |退群|◯|◯| -|同意邀请|◯|◯| -|处理申请|◯|◯| -|邀请好友入群|◯|| +|群邀请|◯|◯| +|群申请|◯|◯| +|邀请好友|◯|| |添加群|◯|| ---- @@ -61,7 +61,7 @@ |修改个人说明|◯| |修改签名|◯| |修改头像|◯| -|获取cookies|△| +|获取cookies|◯| ---- diff --git a/lib/ref.d.ts b/lib/ref.d.ts index ba53b3a4..fd8fec0c 100644 --- a/lib/ref.d.ts +++ b/lib/ref.d.ts @@ -52,6 +52,7 @@ export interface Sig { sig_key: Buffer, ticket_key: Buffer, device_token?: Buffer, + emp_time: number, } export interface ApkInfo { diff --git a/lib/wtlogin/wt.js b/lib/wtlogin/wt.js index 9f65bc25..75f78fdf 100644 --- a/lib/wtlogin/wt.js +++ b/lib/wtlogin/wt.js @@ -238,6 +238,8 @@ async function heartbeat() { * @this {import("../ref").Client} */ async function exchangeEMP() { + if (timestamp() - this.sig.emp_time < 14400) + return; this.nextSeq(); const t = tlv.getPacker(this); const body = new Writer() @@ -272,13 +274,11 @@ async function exchangeEMP() { const stream = Readable.from(blob, {objectMode: false}); stream.read(5); const t = readTlv(stream, 2); - console.log(t) if (t[0x119]) decodeT119.call(this, t[0x119]); - } catch (e) { - this.logger.debug(e); - this.logger.debug("emp失败"); - } + else + this.logger.debug("emp失败"); + } catch {} } //---------------------------------------------------------------------------------------------- @@ -356,17 +356,18 @@ function decodeT119(data) { readT11A.call(this, t[0x11a]); readT512.call(this, t[0x512]); this.sig = { - srm_token: t[0x16a], - tgt: t[0x10a], - tgt_key: t[0x10d], - st_key: t[0x10e], - st_web_sig: t[0x103], - skey: t[0x120], - d2: t[0x143], - d2key: t[0x305], - sig_key: t[0x133], - ticket_key: t[0x134], - device_token: t[0x322], + 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: timestamp(), }; } // function decodeT130(data) { From d3fdfcdbf96d5bbc05b32ddbdcda604c72e1cf85 Mon Sep 17 00:00:00 2001 From: takayama Date: Fri, 13 Nov 2020 01:58:03 +0900 Subject: [PATCH 11/11] update ver to 1.10.6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fe9b0d73..e0b4a9d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.10.5", + "version": "1.10.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 46ad3ecb..63acda9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.10.5", + "version": "1.10.6", "description": "QQ protocol!", "main": "client.js", "scripts": {