oicq-icalingua-plus-plus 1.26.7 → 1.26.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +3 -1
- package/lib/algo/jce/jce.js +6 -6
- package/lib/algo/reader.js +81 -0
- package/lib/client-ext.js +3 -3
- package/lib/message/multi.js +8 -1
- package/lib/oicq.js +11 -15
- package/lib/onlinepush.js +54 -12
- package/lib/ref.d.ts +2 -1
- package/lib/wtlogin/login-password.js +14 -14
- package/lib/wtlogin/login-qrcode.js +3 -3
- package/lib/wtlogin/wt.js +24 -20
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -1240,7 +1240,9 @@ export class Client extends EventEmitter {
|
|
|
1240
1240
|
|
|
1241
1241
|
//----------以下为隐藏方法,可用于扩展协议----------\\
|
|
1242
1242
|
/** 发送一个未加密的uni包 */
|
|
1243
|
-
sendUni(cmd: string, body: Uint8Array): Promise<Buffer>;
|
|
1243
|
+
sendUni(cmd: string, body: Uint8Array, timeout?: number, options?: SsoOptions): Promise<Buffer>;
|
|
1244
|
+
/** 写入一个未加密的uni包 */
|
|
1245
|
+
writeUni(cmd: string, body: Buffer, seq?: number, options?: SsoOptions): Promise<void>;
|
|
1244
1246
|
/** 发送一个未加密的oidb包 */
|
|
1245
1247
|
sendOidb(cmd: string, body: Uint8Array): Promise<Buffer>;
|
|
1246
1248
|
/** 发送一个未加密的OidbSvcTrpcTcp包 */
|
package/lib/algo/jce/jce.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const
|
|
2
|
+
const Reader = require("../reader");
|
|
3
3
|
class JceError extends Error { }
|
|
4
4
|
const BUF0 = Buffer.alloc(0);
|
|
5
5
|
|
|
@@ -36,7 +36,7 @@ let _encoding = "utf8";
|
|
|
36
36
|
class Struct extends null { }
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* @param {
|
|
39
|
+
* @param {Reader} stream
|
|
40
40
|
*/
|
|
41
41
|
function readHead(stream) {
|
|
42
42
|
const head = stream.read(1).readUInt8();
|
|
@@ -49,7 +49,7 @@ function readHead(stream) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* @param {
|
|
52
|
+
* @param {Reader} stream
|
|
53
53
|
* @param {number} type UInt8 0~13
|
|
54
54
|
*/
|
|
55
55
|
function readBody(stream, type) {
|
|
@@ -108,7 +108,7 @@ function readBody(stream, type) {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
|
-
* @param {
|
|
111
|
+
* @param {Reader} stream
|
|
112
112
|
*/
|
|
113
113
|
function readStruct(stream) {
|
|
114
114
|
const struct = Object.create(Struct.prototype);
|
|
@@ -123,7 +123,7 @@ function readStruct(stream) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* @param {
|
|
126
|
+
* @param {Reader} stream
|
|
127
127
|
*/
|
|
128
128
|
function readElement(stream) {
|
|
129
129
|
const head = readHead(stream);
|
|
@@ -286,7 +286,7 @@ function setEncoding(encoding = "utf8") {
|
|
|
286
286
|
* @returns {{[k: number]: any}}
|
|
287
287
|
*/
|
|
288
288
|
function decode(blob) {
|
|
289
|
-
const stream =
|
|
289
|
+
const stream = new Reader(blob);
|
|
290
290
|
stream.read(0);
|
|
291
291
|
const result = Object.create(null);
|
|
292
292
|
while(stream.readableLength) {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
class Reader {
|
|
2
|
+
/**
|
|
3
|
+
* @param {Buffer | ArrayBuffer | Uint8Array} data
|
|
4
|
+
*/
|
|
5
|
+
constructor(data) {
|
|
6
|
+
if (data instanceof Buffer) {
|
|
7
|
+
this._buf = data;
|
|
8
|
+
} else {
|
|
9
|
+
this._buf = Buffer.from(data);
|
|
10
|
+
}
|
|
11
|
+
this._offset = 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get readableLength() {
|
|
15
|
+
return Math.max(0, this._buf.length - this._offset);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
read(n) {
|
|
19
|
+
if (arguments.length === 0) {
|
|
20
|
+
n = this.readableLength;
|
|
21
|
+
}
|
|
22
|
+
if (typeof n !== "number") {
|
|
23
|
+
throw new TypeError("n must be a number");
|
|
24
|
+
}
|
|
25
|
+
if (n <= 0 || this.readableLength === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const r = this._buf.subarray(this._offset, this._offset + n);
|
|
30
|
+
this._offset += n;
|
|
31
|
+
return r;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
readU8() {
|
|
35
|
+
const value = this._buf.readUInt8(this._offset);
|
|
36
|
+
this._offset += 1;
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
readU16() {
|
|
41
|
+
const value = this._buf.readUInt16BE(this._offset);
|
|
42
|
+
this._offset += 2;
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
readU32() {
|
|
47
|
+
const value = this._buf.readUInt32BE(this._offset);
|
|
48
|
+
this._offset += 4;
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
read32() {
|
|
53
|
+
const value = this._buf.readInt32BE(this._offset);
|
|
54
|
+
this._offset += 4;
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
readU64() {
|
|
59
|
+
const value = this._buf.readBigUInt64BE(this._offset);
|
|
60
|
+
this._offset += 8;
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
readBytes(length) {
|
|
65
|
+
const value = Buffer.from(this._buf.slice(this._offset, this._offset + length));
|
|
66
|
+
this._offset += length;
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
readWithLength() {
|
|
71
|
+
const length = this.readU32() - 4;
|
|
72
|
+
return this.readBytes(length);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
readTlv() {
|
|
76
|
+
const length = this.readU16();
|
|
77
|
+
return this.readBytes(length);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = Reader;
|
package/lib/client-ext.js
CHANGED
|
@@ -68,9 +68,9 @@ Client.prototype.writeUni = async function (cmd, body, seq = 0, options = {}) {
|
|
|
68
68
|
/**
|
|
69
69
|
* 发送一个uni包并返回响应包
|
|
70
70
|
*/
|
|
71
|
-
Client.prototype.sendUni = async function (cmd, body, timeout = 5) {
|
|
71
|
+
Client.prototype.sendUni = async function (cmd, body, timeout = 5, options = {}) {
|
|
72
72
|
const seq = this.nextSeq();
|
|
73
|
-
const packet = await this._buildUniPacket(cmd, body, seq);
|
|
73
|
+
const packet = await this._buildUniPacket(cmd, body, seq, options);
|
|
74
74
|
return this.send(packet, timeout, seq);
|
|
75
75
|
};
|
|
76
76
|
|
|
@@ -232,7 +232,7 @@ Client.prototype.buildSyncCookie = function () {
|
|
|
232
232
|
* 消息同步
|
|
233
233
|
*/
|
|
234
234
|
Client.prototype.pbGetMsg = async function (force = false, flag = 0, count = 10) {
|
|
235
|
-
if (this.config.useNT
|
|
235
|
+
if (this.config.useNT) return true;
|
|
236
236
|
if (count <= 0) {
|
|
237
237
|
this.sync_cookie = null;
|
|
238
238
|
return true;
|
package/lib/message/multi.js
CHANGED
|
@@ -14,6 +14,7 @@ const deflate = util.promisify(zlib.deflate);
|
|
|
14
14
|
const { getC2CMsgs, getGroupMsgs } = require("./history");
|
|
15
15
|
const http = require("http");
|
|
16
16
|
const https = require("https");
|
|
17
|
+
const { sleep } = require("../qsign-api");
|
|
17
18
|
const BUF1 = Buffer.from([1]);
|
|
18
19
|
|
|
19
20
|
function buildTextElem(str) {
|
|
@@ -193,8 +194,9 @@ async function _downloadMultiMsgNt(resid, bu) {
|
|
|
193
194
|
* @param {boolean} dm
|
|
194
195
|
* @param {number} target
|
|
195
196
|
* @param {boolean} nt
|
|
197
|
+
* @param {number} retry
|
|
196
198
|
*/
|
|
197
|
-
async function makeForwardMsg(iterable, dm = false, target = 0, nt = true) {
|
|
199
|
+
async function makeForwardMsg(iterable, dm = false, target = 0, nt = true, retry = 0) {
|
|
198
200
|
|
|
199
201
|
if (typeof iterable[Symbol.iterator] !== "function")
|
|
200
202
|
iterable = [iterable];
|
|
@@ -520,6 +522,11 @@ async function makeForwardMsg(iterable, dm = false, target = 0, nt = true) {
|
|
|
520
522
|
this.logger.warn("failed to upload forward msg with NT protocol, try old protocol -> " + e.message);
|
|
521
523
|
return makeForwardMsg.call(this, iterable, dm, target, false);
|
|
522
524
|
}
|
|
525
|
+
if (retry < 3) {
|
|
526
|
+
this.logger.warn("failed to upload forward msg, retry -> " + e.message);
|
|
527
|
+
await sleep(1000);
|
|
528
|
+
return makeForwardMsg.call(this, iterable, dm, target, nt, retry + 1);
|
|
529
|
+
}
|
|
523
530
|
throw new Error("failed to upload forward msg -> " + e.message);
|
|
524
531
|
}
|
|
525
532
|
|
package/lib/oicq.js
CHANGED
|
@@ -10,6 +10,7 @@ const { Client, STATUS_ONLINE, STATUS_OFFLINE, STATUS_PENDING } = require("./cli
|
|
|
10
10
|
const tea = require("./algo/tea");
|
|
11
11
|
const pb = require("./algo/pb");
|
|
12
12
|
const jce = require("./algo/jce");
|
|
13
|
+
const Reader = require("./algo/reader");
|
|
13
14
|
const { timestamp, BUF0, BUF16, unzip, log } = require("./common");
|
|
14
15
|
const push = require("./onlinepush");
|
|
15
16
|
const sysmsg = require("./core/sysmsg");
|
|
@@ -388,20 +389,19 @@ function pushDomainListener() {
|
|
|
388
389
|
* @param {Buffer} buf
|
|
389
390
|
*/
|
|
390
391
|
async function parseSSO(buf) {
|
|
392
|
+
const stream = new Reader(buf);
|
|
393
|
+
const header = new Reader(stream.readWithLength());
|
|
391
394
|
const headlen = buf.readInt32BE();
|
|
392
|
-
const seq =
|
|
393
|
-
const retcode =
|
|
395
|
+
const seq = header.read(4).readInt32BE();
|
|
396
|
+
const retcode = header.read(4).readInt32BE();
|
|
397
|
+
const retmsg = String(header.readWithLength());
|
|
394
398
|
if (retcode !== 0) {
|
|
395
|
-
const retmsg_len = buf.readUInt32BE(12);
|
|
396
|
-
const retmsg = String(buf.slice(16, 16 + retmsg_len - 4));
|
|
397
399
|
const error = new Error("unsuccessful retcode: " + retcode + " retmsg: " + retmsg + " seq: " + seq);
|
|
398
400
|
if (this.handlers.has(seq))
|
|
399
401
|
this.handlers.get(seq)(null, error);
|
|
400
402
|
throw error;
|
|
401
403
|
}
|
|
402
|
-
|
|
403
|
-
let len = buf.readUInt32BE(offset); // length of cmd
|
|
404
|
-
const cmd = String(buf.slice(offset + 4, offset + len));
|
|
404
|
+
const cmd = String(header.readWithLength());
|
|
405
405
|
|
|
406
406
|
if (cmd === "Heartbeat.Alive") {
|
|
407
407
|
return {
|
|
@@ -409,13 +409,9 @@ async function parseSSO(buf) {
|
|
|
409
409
|
};
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const flag = buf.readInt32BE(offset);
|
|
416
|
-
offset += 4;
|
|
417
|
-
len = buf.readUInt32BE(offset); // length of reserved
|
|
418
|
-
const reserved = buf.slice(offset + 4, offset + len);
|
|
412
|
+
const session_id = header.readWithLength();
|
|
413
|
+
const flag = header.read(4).readInt32BE();
|
|
414
|
+
const reserved = header.readWithLength();
|
|
419
415
|
let payload;
|
|
420
416
|
if (flag === 0) {
|
|
421
417
|
payload = buf.slice(headlen + 4);
|
|
@@ -502,7 +498,7 @@ async function packetListener(pkt) {
|
|
|
502
498
|
if (this.handlers.has(sso.seq))
|
|
503
499
|
return this.handlers.get(sso.seq)(sso.payload);
|
|
504
500
|
if (Reflect.has(listeners, sso.cmd))
|
|
505
|
-
listeners[sso.cmd].call(this, sso.payload, sso.seq);
|
|
501
|
+
listeners[sso.cmd].call(this, sso.payload, sso.seq, sso);
|
|
506
502
|
this.emit("internal.sso", sso);
|
|
507
503
|
} catch (e) {
|
|
508
504
|
++this.stat.sso_error;
|
package/lib/onlinepush.js
CHANGED
|
@@ -7,7 +7,7 @@ const pb = require("./algo/pb");
|
|
|
7
7
|
const jce = require("./algo/jce");
|
|
8
8
|
const sysmsg = require("./core/sysmsg");
|
|
9
9
|
const { parseC2CMsg ,parseGroupMsg, parseDiscussMsg } = require("./message/parser");
|
|
10
|
-
const { genC2CMessageId, genGroupMessageId, log, uin2code } = require("./common");
|
|
10
|
+
const { genC2CMessageId, genGroupMessageId, log, uin2code, BUF0 } = require("./common");
|
|
11
11
|
const { updateFL, uid2uin } = require("./core/friendlist");
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -766,7 +766,7 @@ function rebuildFragments(msg) {
|
|
|
766
766
|
/**
|
|
767
767
|
* @this {import("./ref").Client}
|
|
768
768
|
*/
|
|
769
|
-
async function NTMsgListener(blob, seq) {
|
|
769
|
+
async function NTMsgListener(blob, seq, sso) {
|
|
770
770
|
const o = pb.decode(blob);
|
|
771
771
|
const type = o[1][2] ? o[1][2][1] : 114514;
|
|
772
772
|
//this.logger.debug("NT message type", type);
|
|
@@ -800,8 +800,46 @@ async function NTMsgListener(blob, seq) {
|
|
|
800
800
|
}
|
|
801
801
|
break;
|
|
802
802
|
case 33: //群员入群
|
|
803
|
+
const group_id = uin2code(o[1][1][1]);
|
|
804
|
+
const msg = o[1][3][2];
|
|
805
|
+
const user_uid = String(msg[3]);
|
|
806
|
+
const user_id = await uid2uin.call(this, user_uid);
|
|
807
|
+
let nickname = "";
|
|
808
|
+
const ginfo = (await this.getGroupInfo(group_id)).data;
|
|
809
|
+
if (!ginfo) return;
|
|
810
|
+
if (user_id === this.uin) {
|
|
811
|
+
nickname = this.nickname;
|
|
812
|
+
this.logger.info(`更新了群列表,新增了群:${group_id}`);
|
|
813
|
+
} else {
|
|
814
|
+
ginfo.member_count++;
|
|
815
|
+
ginfo.last_join_time = timestamp();
|
|
816
|
+
const info = await this.getGroupMemberInfo(group_id, user_id);
|
|
817
|
+
nickname = info.data.nickname || info.data.card || "";
|
|
818
|
+
try {
|
|
819
|
+
if (this.gml.get(group_id).size)
|
|
820
|
+
ginfo.member_count = this.gml.get(group_id).size;
|
|
821
|
+
} catch { }
|
|
822
|
+
this.logger.info(`${user_id}(${nickname}) 加入了群 ${group_id}`);
|
|
823
|
+
}
|
|
824
|
+
this.getGroupMemberList(group_id, true);
|
|
825
|
+
this.em("notice.group.increase", {
|
|
826
|
+
group_id, user_id, nickname
|
|
827
|
+
});
|
|
828
|
+
break;
|
|
803
829
|
case 38: //建群
|
|
804
830
|
case 85: //群申请被同意
|
|
831
|
+
const group_id = uin2code(o[1][1][1]);
|
|
832
|
+
const user_id = this.uin;
|
|
833
|
+
const nickname = this.nickname;
|
|
834
|
+
const ginfo = (await this.getGroupInfo(group_id)).data;
|
|
835
|
+
if (!ginfo) return;
|
|
836
|
+
if (user_id === this.uin) {
|
|
837
|
+
this.logger.info(`更新了群列表,新增了群:${group_id}`);
|
|
838
|
+
this.getGroupMemberList(group_id);
|
|
839
|
+
}
|
|
840
|
+
this.em("notice.group.increase", {
|
|
841
|
+
group_id, user_id, nickname
|
|
842
|
+
});
|
|
805
843
|
break;
|
|
806
844
|
case 141: //陌生人
|
|
807
845
|
case 166: //好友
|
|
@@ -845,11 +883,6 @@ async function NTMsgListener(blob, seq) {
|
|
|
845
883
|
} catch (e) {
|
|
846
884
|
this.logger.debug(e);
|
|
847
885
|
}
|
|
848
|
-
if (o[4]) {
|
|
849
|
-
this.writeUni("trpc.msg.olpush.OlPushService.SsoPushAck", pb.encode({
|
|
850
|
-
1: o[4],
|
|
851
|
-
}));
|
|
852
|
-
}
|
|
853
886
|
break;
|
|
854
887
|
case 732: //push732
|
|
855
888
|
try {
|
|
@@ -864,11 +897,6 @@ async function NTMsgListener(blob, seq) {
|
|
|
864
897
|
} catch (e) {
|
|
865
898
|
this.logger.debug(e);
|
|
866
899
|
}
|
|
867
|
-
if (o[4]) {
|
|
868
|
-
this.writeUni("trpc.msg.olpush.OlPushService.SsoPushAck", pb.encode({
|
|
869
|
-
1: o[4],
|
|
870
|
-
}));
|
|
871
|
-
}
|
|
872
900
|
break;
|
|
873
901
|
case 114514: // 1919810
|
|
874
902
|
// 部分消息没有content
|
|
@@ -877,6 +905,20 @@ async function NTMsgListener(blob, seq) {
|
|
|
877
905
|
this.logger.warn("Unknown NT message type", type);
|
|
878
906
|
break;
|
|
879
907
|
}
|
|
908
|
+
if (o[4]) {
|
|
909
|
+
let trans_info = BUF0;
|
|
910
|
+
try {
|
|
911
|
+
const trans_info = pb.decode(sso.reserved)[23] || BUF0;
|
|
912
|
+
} catch (e) {
|
|
913
|
+
this.logger.debug(e);
|
|
914
|
+
}
|
|
915
|
+
this.writeUni("trpc.msg.olpush.OlPushService.SsoPushAck", pb.encode({
|
|
916
|
+
1: o[4],
|
|
917
|
+
}), undefined, {
|
|
918
|
+
trans_info: trans_info,
|
|
919
|
+
nt_core: true,
|
|
920
|
+
});
|
|
921
|
+
}
|
|
880
922
|
}
|
|
881
923
|
|
|
882
924
|
/**
|
package/lib/ref.d.ts
CHANGED
|
@@ -183,7 +183,8 @@ export class Client extends oicq.Client {
|
|
|
183
183
|
|
|
184
184
|
nextSeq(): number;
|
|
185
185
|
send(): Promise<Buffer>;
|
|
186
|
-
|
|
186
|
+
sendUni(cmd: string, body: Uint8Array, timeout?: number, options?: SsoOptions): Promise<Buffer>;
|
|
187
|
+
writeUni(cmd: string, body: Buffer, seq?: number, options?: SsoOptions): Promise<void>;
|
|
187
188
|
msgExists(from: number, type: number, seq: number, time: number): boolean;
|
|
188
189
|
buildSyncCookie(): Buffer;
|
|
189
190
|
parseEventType(name: string): oicq.CommonEventData;
|
|
@@ -16,7 +16,7 @@ const Writer = require("./writer");
|
|
|
16
16
|
const { md5, NOOP, timestamp, BUF0 } = require("../common");
|
|
17
17
|
const tea = require("../algo/tea");
|
|
18
18
|
const Ecdh = require("./ecdh");
|
|
19
|
-
const
|
|
19
|
+
const Reader = require("../algo/reader");
|
|
20
20
|
const { getQIMEI } = require("../qimei");
|
|
21
21
|
|
|
22
22
|
WtLogin.prototype.passwordLogin = async function () {
|
|
@@ -66,15 +66,15 @@ WtLogin.prototype.passwordLogin = async function () {
|
|
|
66
66
|
this.logger.warn("你的登录缓存有缺失或者是旧版创建的,将使用旧版刷新包。");
|
|
67
67
|
}
|
|
68
68
|
const token = await fs.promises.readFile(path.join(this.dir, "token"));
|
|
69
|
-
const stream =
|
|
70
|
-
const d2key = stream.
|
|
71
|
-
const d2 = stream.
|
|
72
|
-
const ticket = stream.
|
|
73
|
-
const sig = stream.
|
|
74
|
-
const srm = stream.
|
|
75
|
-
const tgt = stream.
|
|
76
|
-
this.sig.device_token = stream.
|
|
77
|
-
this.sig._ksid = stream.
|
|
69
|
+
const stream = new Reader(token);
|
|
70
|
+
const d2key = stream.readTlv();
|
|
71
|
+
const d2 = stream.readTlv();
|
|
72
|
+
const ticket = stream.readTlv();
|
|
73
|
+
const sig = stream.readTlv();
|
|
74
|
+
const srm = stream.readTlv();
|
|
75
|
+
const tgt = stream.readTlv();
|
|
76
|
+
this.sig.device_token = stream.readTlv();
|
|
77
|
+
this.sig._ksid = stream.readTlv() || BUF0;
|
|
78
78
|
if (d2key.length && d2.length && ticket.length && sig.length && srm.length && tgt.length) {
|
|
79
79
|
this.sig.d2 = d2;
|
|
80
80
|
this.sig.d2key = d2key;
|
|
@@ -364,9 +364,9 @@ WtLogin.prototype.refreshD2 = async function (forceEmp11 = false) {
|
|
|
364
364
|
try {
|
|
365
365
|
let payload = await this.c.send(pkt, undefined, seq);
|
|
366
366
|
payload = tea.decrypt(payload.slice(16, payload.length - 1), this.ecdh.share_key);
|
|
367
|
-
const stream =
|
|
367
|
+
const stream = new Reader(payload);
|
|
368
368
|
stream.read(2);
|
|
369
|
-
const type = stream.
|
|
369
|
+
const type = stream.readU8();
|
|
370
370
|
stream.read(2);
|
|
371
371
|
const t = readTlv(stream);
|
|
372
372
|
if (type === 0)
|
|
@@ -495,9 +495,9 @@ WtLogin.prototype.refreshD2WithT10C = async function () {
|
|
|
495
495
|
try {
|
|
496
496
|
let payload = await this.c.send(pkt, undefined, seq);
|
|
497
497
|
payload = tea.decrypt(payload.slice(16, payload.length - 1), this.ecdh.share_key);
|
|
498
|
-
const stream =
|
|
498
|
+
const stream = new Reader(payload);
|
|
499
499
|
stream.read(2);
|
|
500
|
-
const type = stream.
|
|
500
|
+
const type = stream.readU8();
|
|
501
501
|
stream.read(2);
|
|
502
502
|
const t = readTlv(stream);
|
|
503
503
|
if (type === 0)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"use strict";
|
|
10
10
|
const fs = require("fs");
|
|
11
11
|
const path = require("path");
|
|
12
|
-
const
|
|
12
|
+
const Reader = require("../algo/reader");
|
|
13
13
|
const jsqr = require("jsqr");
|
|
14
14
|
const { PNG } = require("pngjs");
|
|
15
15
|
const qrt = require("qrcode-terminal");
|
|
@@ -127,7 +127,7 @@ WtLogin.prototype.fetchQrcode = async function () {
|
|
|
127
127
|
try {
|
|
128
128
|
let payload = await this.c.send(pkt, undefined, seq);
|
|
129
129
|
payload = tea.decrypt(payload.slice(16, -1), this.ecdh.share_key);
|
|
130
|
-
const stream =
|
|
130
|
+
const stream = new Reader(payload);
|
|
131
131
|
stream.read(54);
|
|
132
132
|
const retcode = stream.read(1)[0];
|
|
133
133
|
const sig = stream.read(stream.read(2).readUInt16BE());
|
|
@@ -177,7 +177,7 @@ WtLogin.prototype.qrcodeLogin = async function () {
|
|
|
177
177
|
try {
|
|
178
178
|
let payload = await this.c.send(pkt, undefined, seq);
|
|
179
179
|
payload = tea.decrypt(payload.slice(16, -1), this.ecdh.share_key);
|
|
180
|
-
const stream =
|
|
180
|
+
const stream = new Reader(payload);
|
|
181
181
|
stream.read(48);
|
|
182
182
|
let len = stream.read(2).readUInt16BE();
|
|
183
183
|
if (len > 0) {
|
package/lib/wtlogin/wt.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const fs = require("fs");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const { randomBytes, createHash } = require("crypto");
|
|
5
|
-
const
|
|
5
|
+
const Reader = require("../algo/reader");
|
|
6
6
|
const tea = require("../algo/tea");
|
|
7
7
|
const jce = require("../algo/jce");
|
|
8
8
|
const pb = require("../algo/pb");
|
|
@@ -84,7 +84,7 @@ class WtLogin {
|
|
|
84
84
|
* @param {Buffer} data
|
|
85
85
|
*/
|
|
86
86
|
decodeT119(data, token = false) {
|
|
87
|
-
const reader =
|
|
87
|
+
const reader = new Reader(tea.decrypt(data, this.device.tgtgt), { objectMode: false });
|
|
88
88
|
reader.read(2);
|
|
89
89
|
const t = readTlv(reader);
|
|
90
90
|
this.readT106(t[0x106]);
|
|
@@ -170,7 +170,7 @@ class WtLogin {
|
|
|
170
170
|
}
|
|
171
171
|
readT11A(data) {
|
|
172
172
|
if (!data) return;
|
|
173
|
-
const stream =
|
|
173
|
+
const stream = new Reader(data, { objectMode: false });
|
|
174
174
|
stream.read(2);
|
|
175
175
|
this.age = stream.read(1).readUInt8();
|
|
176
176
|
this.sex = ["unknown", "male", "female"][stream.read(1).readUInt8()];
|
|
@@ -179,7 +179,7 @@ class WtLogin {
|
|
|
179
179
|
}
|
|
180
180
|
readT512(data) {
|
|
181
181
|
if (!data) return;
|
|
182
|
-
const stream =
|
|
182
|
+
const stream = new Reader(data);
|
|
183
183
|
let len = stream.read(2).readUInt16BE();
|
|
184
184
|
while (len-- > 0) {
|
|
185
185
|
const domain = String(stream.read(stream.read(2).readUInt16BE()));
|
|
@@ -191,7 +191,7 @@ class WtLogin {
|
|
|
191
191
|
|
|
192
192
|
calcPoW(data) {
|
|
193
193
|
if (!data || data.length === 0) return Buffer.alloc(0);
|
|
194
|
-
const stream =
|
|
194
|
+
const stream = new Reader(data);
|
|
195
195
|
const version = stream.read(1).readUInt8();
|
|
196
196
|
const typ = stream.read(1).readUInt8();
|
|
197
197
|
const hashType = stream.read(1).readUInt8();
|
|
@@ -262,7 +262,7 @@ class WtLogin {
|
|
|
262
262
|
|
|
263
263
|
_decodeLoginResponse(payload) {
|
|
264
264
|
payload = tea.decrypt(payload.slice(16, payload.length - 1), this.ecdh.share_key);
|
|
265
|
-
const stream =
|
|
265
|
+
const stream = new Reader(payload);
|
|
266
266
|
stream.read(2);
|
|
267
267
|
const type = stream.read(1).readUInt8();
|
|
268
268
|
stream.read(2);
|
|
@@ -287,7 +287,7 @@ class WtLogin {
|
|
|
287
287
|
if (this.token_flag) {
|
|
288
288
|
this.logger.mark("token失效,重新login..");
|
|
289
289
|
if (t[0x146]) {
|
|
290
|
-
const stream =
|
|
290
|
+
const stream = new Reader(t[0x146]);
|
|
291
291
|
const version = stream.read(4);
|
|
292
292
|
const title = stream.read(stream.read(2).readUInt16BE()).toString();
|
|
293
293
|
const content = stream.read(stream.read(2).readUInt16BE()).toString();
|
|
@@ -333,7 +333,7 @@ class WtLogin {
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
if (t[0x149]) {
|
|
336
|
-
const stream =
|
|
336
|
+
const stream = new Reader(t[0x149]);
|
|
337
337
|
stream.read(2);
|
|
338
338
|
const title = stream.read(stream.read(2).readUInt16BE()).toString();
|
|
339
339
|
const content = stream.read(stream.read(2).readUInt16BE()).toString();
|
|
@@ -343,7 +343,7 @@ class WtLogin {
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
if (t[0x146]) {
|
|
346
|
-
const stream =
|
|
346
|
+
const stream = new Reader(t[0x146]);
|
|
347
347
|
const version = stream.read(4);
|
|
348
348
|
const title = stream.read(stream.read(2).readUInt16BE()).toString();
|
|
349
349
|
const content = stream.read(stream.read(2).readUInt16BE()).toString();
|
|
@@ -437,7 +437,7 @@ class WtLogin {
|
|
|
437
437
|
const seq = this.c.nextSeq();
|
|
438
438
|
if (logout) {
|
|
439
439
|
const payload = pb.encode({
|
|
440
|
-
1: 0,
|
|
440
|
+
1: 0, // reg type
|
|
441
441
|
2: {
|
|
442
442
|
1: d.brand + '-' + d.model,
|
|
443
443
|
2: d.device,
|
|
@@ -453,7 +453,8 @@ class WtLogin {
|
|
|
453
453
|
const rsp = pb.decode(blob);
|
|
454
454
|
const result = rsp[7] ? String(rsp[7][2]) === 'unregister success' : false;
|
|
455
455
|
return result;
|
|
456
|
-
} catch {
|
|
456
|
+
} catch (e) {
|
|
457
|
+
this.logger.error(`下线异常:${e.message}`);
|
|
457
458
|
return false;
|
|
458
459
|
}
|
|
459
460
|
}
|
|
@@ -484,9 +485,9 @@ class WtLogin {
|
|
|
484
485
|
},
|
|
485
486
|
9: {
|
|
486
487
|
1: d.guid.toString("hex"),
|
|
487
|
-
2: 0,
|
|
488
|
-
3: String(this.apk.version.split(".")[3]),
|
|
489
|
-
4: 0,
|
|
488
|
+
2: 0, // kickPc
|
|
489
|
+
3: String(this.apk.version.split(".")[3] || "14110"), // buildVer
|
|
490
|
+
4: 0, // first
|
|
490
491
|
5: 2052,
|
|
491
492
|
6: {
|
|
492
493
|
1: d.brand + '-' + d.model,
|
|
@@ -496,8 +497,8 @@ class WtLogin {
|
|
|
496
497
|
5: `${d.product}-user ${d.version.release} ${d.display} ${d.version.incremental} release-keys`
|
|
497
498
|
},
|
|
498
499
|
7: 0,
|
|
499
|
-
8:
|
|
500
|
-
9: 1,
|
|
500
|
+
8: 6, // vendor type
|
|
501
|
+
9: 1, // reg type
|
|
501
502
|
10: {
|
|
502
503
|
1: 1,
|
|
503
504
|
2: 1,
|
|
@@ -519,10 +520,13 @@ class WtLogin {
|
|
|
519
520
|
const blob = await this.c.send(pkt, undefined, seq);
|
|
520
521
|
const rsp = pb.decode(blob);
|
|
521
522
|
const result = rsp[7] ? String(rsp[7][2]) === 'register success' : false;
|
|
522
|
-
if (!result)
|
|
523
|
+
if (!result) {
|
|
524
|
+
this.logger.error(`上线失败:${rsp[7] ? String(rsp[7][2]) : "未知错误"}`);
|
|
523
525
|
await this.deleteToken();
|
|
526
|
+
}
|
|
524
527
|
return result;
|
|
525
|
-
} catch {
|
|
528
|
+
} catch (e) {
|
|
529
|
+
this.logger.error(`上线异常:${e.message}`);
|
|
526
530
|
return false;
|
|
527
531
|
}
|
|
528
532
|
}
|
|
@@ -682,7 +686,7 @@ class WtLogin {
|
|
|
682
686
|
try {
|
|
683
687
|
let payload = await this.c.sendUni("wtlogin.exchange_emp", pkt);
|
|
684
688
|
payload = tea.decrypt(payload.slice(16, payload.length - 1), this.sig.ticket_key);
|
|
685
|
-
const stream =
|
|
689
|
+
const stream = new Reader(payload);
|
|
686
690
|
stream.read(5);
|
|
687
691
|
const t = readTlv(stream);
|
|
688
692
|
if (t[0x119])
|
|
@@ -697,7 +701,7 @@ class WtLogin {
|
|
|
697
701
|
}
|
|
698
702
|
|
|
699
703
|
/**
|
|
700
|
-
* @param {
|
|
704
|
+
* @param {Reader} stream
|
|
701
705
|
* @returns {{[k: number]: Buffer}}
|
|
702
706
|
*/
|
|
703
707
|
function readTlv(stream) {
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oicq-icalingua-plus-plus",
|
|
3
3
|
"app_name": "oicq-icalingua-plus-plus",
|
|
4
|
-
"version": "1.26.
|
|
5
|
-
"app_version": "1.26.
|
|
6
|
-
"upday": "2026/07/
|
|
4
|
+
"version": "1.26.9",
|
|
5
|
+
"app_version": "1.26.9",
|
|
6
|
+
"upday": "2026/07/19",
|
|
7
7
|
"protocol_version": "v11",
|
|
8
8
|
"description": "oicq(https://github.com/takayama-lily/oicq) v1 for Icalingua++",
|
|
9
9
|
"main": "index.js",
|