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 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包 */
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const Readable = require("stream").Readable;
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 {Readable} stream
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 {Readable} stream
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 {Readable} stream
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 {Readable} stream
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 = Readable.from(blob, {objectMode: false});
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 && !force) return true;
235
+ if (this.config.useNT) return true;
236
236
  if (count <= 0) {
237
237
  this.sync_cookie = null;
238
238
  return true;
@@ -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 = buf.readInt32BE(4);
393
- const retcode = buf.readInt32BE(8);
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
- let offset = buf.readUInt32BE(12) + 12;
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
- offset += len;
413
- len = buf.readUInt32BE(offset); // length of session_id
414
- offset += len;
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
- writeUni(cmd: string, body: Buffer, seq?: number): Promise<void>;
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 Readable = require("stream").Readable;
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 = Readable.from(token, { objectMode: false });
70
- const d2key = stream.read(stream.read(2).readUInt16BE());
71
- const d2 = stream.read(stream.read(2).readUInt16BE());
72
- const ticket = stream.read(stream.read(2).readUInt16BE());
73
- const sig = stream.read(stream.read(2).readUInt16BE());
74
- const srm = stream.read(stream.read(2).readUInt16BE());
75
- const tgt = stream.read(stream.read(2).readUInt16BE());
76
- this.sig.device_token = stream.read(stream.read(2).readUInt16BE());
77
- this.sig._ksid = stream.read(stream.read(2).readUInt16BE()) || BUF0;
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 = Readable.from(payload, { objectMode: false });
367
+ const stream = new Reader(payload);
368
368
  stream.read(2);
369
- const type = stream.read(1).readUInt8();
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 = Readable.from(payload, { objectMode: false });
498
+ const stream = new Reader(payload);
499
499
  stream.read(2);
500
- const type = stream.read(1).readUInt8();
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 Readable = require("stream").Readable;
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 = Readable.from(payload, { objectMode: false });
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 = Readable.from(payload, { objectMode: false });
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 Readable = require("stream").Readable;
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 = Readable.from(tea.decrypt(data, this.device.tgtgt), { objectMode: false });
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 = Readable.from(data, { objectMode: false });
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 = Readable.from(data, { objectMode: false });
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 = Readable.from(data, { objectMode: false });
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 = Readable.from(payload, { objectMode: false });
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 = Readable.from(t[0x146], { objectMode: false });
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 = Readable.from(t[0x149], { objectMode: false });
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 = Readable.from(t[0x146], { objectMode: false });
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: 5,
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 = Readable.from(payload, { objectMode: false });
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 {Readable} stream
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.7",
5
- "app_version": "1.26.7",
6
- "upday": "2026/07/18",
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",