oicq-icalingua-plus-plus 1.24.39 → 1.24.41
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/lib/message/builder.js +19 -3
- package/lib/oicq.js +20 -4
- package/lib/onlinepush.js +128 -2
- package/lib/qimei.js +21 -6
- package/lib/service.js +40 -3
- package/package.json +3 -3
package/lib/message/builder.js
CHANGED
|
@@ -172,8 +172,9 @@ class Builder {
|
|
|
172
172
|
* @private
|
|
173
173
|
* @param {string} text
|
|
174
174
|
* @param {Buffer} attr6
|
|
175
|
+
* @param {Buffer} extra12
|
|
175
176
|
*/
|
|
176
|
-
buildTextElem(text, attr6 = null) {
|
|
177
|
+
buildTextElem(text, attr6 = null, extra12 = null) {
|
|
177
178
|
text = String(text);
|
|
178
179
|
let n = 0;
|
|
179
180
|
while (n < text.length) {
|
|
@@ -198,7 +199,8 @@ class Builder {
|
|
|
198
199
|
this.elems.push({
|
|
199
200
|
1: {
|
|
200
201
|
1: chunk,
|
|
201
|
-
3: attr6
|
|
202
|
+
3: attr6,
|
|
203
|
+
12: extra12,
|
|
202
204
|
}
|
|
203
205
|
});
|
|
204
206
|
}
|
|
@@ -231,7 +233,21 @@ class Builder {
|
|
|
231
233
|
const buf = Buffer.allocUnsafe(6);
|
|
232
234
|
buf.writeUInt8(display.length), buf.writeUInt8(flag, 1), buf.writeUInt32BE(q, 2);
|
|
233
235
|
const attr6 = Buffer.concat([AT_BUF, buf, BUF2]);
|
|
234
|
-
|
|
236
|
+
let uid = String(q);
|
|
237
|
+
try {
|
|
238
|
+
if (qq !== "all") {
|
|
239
|
+
const member = this.c.gml.get(this.target).get(q);
|
|
240
|
+
uid = member.uid || uid;
|
|
241
|
+
}
|
|
242
|
+
} catch (e) { }
|
|
243
|
+
const extra12 = {
|
|
244
|
+
3: flag === 1 ? 1 : 2,
|
|
245
|
+
4: q,
|
|
246
|
+
5: 0,
|
|
247
|
+
9: uid,
|
|
248
|
+
11: 0,
|
|
249
|
+
};
|
|
250
|
+
this.buildTextElem(display, attr6, extra12);
|
|
235
251
|
}
|
|
236
252
|
|
|
237
253
|
/**
|
package/lib/oicq.js
CHANGED
|
@@ -14,7 +14,7 @@ const { timestamp, BUF0, BUF16, unzip, log } = require("./common");
|
|
|
14
14
|
const push = require("./onlinepush");
|
|
15
15
|
const sysmsg = require("./core/sysmsg");
|
|
16
16
|
const { initFL, initGL } = require("./core/friendlist");
|
|
17
|
-
const { int32ip2str, getUploadChannel } = require("./service");
|
|
17
|
+
const { int32ip2str, getUploadChannel, checkIPConnectivity } = require("./service");
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* @this {Client}
|
|
@@ -102,6 +102,11 @@ function pushReqListener(blob, seq) {
|
|
|
102
102
|
if (v[1] === 10) {
|
|
103
103
|
this.storage.port = v[2][0][3];
|
|
104
104
|
this.storage.ip = int32ip2str(v[2][0][2]);
|
|
105
|
+
checkIPConnectivity(this.storage.ip, this.storage.port).then((res) => {
|
|
106
|
+
if (res) return;
|
|
107
|
+
this.logger.warn("上传通道IP不可用,将使用通用域名");
|
|
108
|
+
this.storage.ip = "v6.htdata.qq.com";
|
|
109
|
+
});
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
this.saveStorageConfig();
|
|
@@ -170,7 +175,6 @@ function msfOfflineListener(blob) {
|
|
|
170
175
|
* @this {Client}
|
|
171
176
|
*/
|
|
172
177
|
function kickoffListener(data) {
|
|
173
|
-
this._wt.deleteToken();
|
|
174
178
|
this.status = STATUS_PENDING;
|
|
175
179
|
this._stopHeartbeat();
|
|
176
180
|
this.logger.warn(data.info);
|
|
@@ -191,6 +195,7 @@ function kickoffListener(data) {
|
|
|
191
195
|
this.logger.mark("3秒后重新连接..");
|
|
192
196
|
setTimeout(this.login.bind(this), 3000);
|
|
193
197
|
}
|
|
198
|
+
if (sub_type !== "kickoff") this._wt.deleteToken();
|
|
194
199
|
this.em("system.offline." + sub_type, { message: data.info });
|
|
195
200
|
}
|
|
196
201
|
|
|
@@ -209,6 +214,7 @@ Client.prototype._register = async function () {
|
|
|
209
214
|
};
|
|
210
215
|
|
|
211
216
|
Client.prototype._var4 = 0;
|
|
217
|
+
Client.prototype._nt_hb_var = 0;
|
|
212
218
|
Client.prototype._runCircleTask = async function () {
|
|
213
219
|
if (this._var4++ > 10) {
|
|
214
220
|
await this._wt.refreshD2();
|
|
@@ -235,13 +241,22 @@ Client.prototype._startHeartbeat = function () {
|
|
|
235
241
|
}
|
|
236
242
|
this._wt.syncTimeDiff();
|
|
237
243
|
this._wt.heartbeat();
|
|
238
|
-
if (this.config.useNT)
|
|
244
|
+
if (this.config.useNT) {
|
|
245
|
+
if (this._nt_hb_var++ >= 5) {
|
|
246
|
+
this._nt_hb_var = 0;
|
|
247
|
+
this._wt.ssoHeartbeat();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
239
250
|
if (timestamp() - this.sig.qsign_token_time >= (60 * 60)) {
|
|
240
251
|
this.sig.qsign_token_time = timestamp();
|
|
241
252
|
this.refreshQSignToken();
|
|
242
253
|
}
|
|
243
254
|
if (!this.storage.port) {
|
|
244
|
-
|
|
255
|
+
try {
|
|
256
|
+
await getUploadChannel.call(this);
|
|
257
|
+
} catch {
|
|
258
|
+
this.logger.warn("getUploadChannel failed");
|
|
259
|
+
}
|
|
245
260
|
}
|
|
246
261
|
}, 30000);
|
|
247
262
|
};
|
|
@@ -397,6 +412,7 @@ const listeners = {
|
|
|
397
412
|
"MessageSvc.PushReaded": pushReadedListener,
|
|
398
413
|
//"StatSvc.MsfConnProbe": function(){this._wt.ssoHeartbeat()},
|
|
399
414
|
"trpc.msg.olpush.OlPushService.MsgPush": push.NTMsgListener,
|
|
415
|
+
//"trpc.msg.register_proxy.RegisterProxy.InfoSyncPush": push.infoSyncPushListener,
|
|
400
416
|
};
|
|
401
417
|
|
|
402
418
|
// MessageSvc.RequestPushStatus 其他PC端login
|
package/lib/onlinepush.js
CHANGED
|
@@ -839,7 +839,6 @@ async function NTMsgListener(blob, seq) {
|
|
|
839
839
|
break;
|
|
840
840
|
// WIP: NT的系统消息
|
|
841
841
|
}
|
|
842
|
-
|
|
843
842
|
}
|
|
844
843
|
|
|
845
844
|
/**
|
|
@@ -882,6 +881,133 @@ function c2cNTMsgConverter(msg) {
|
|
|
882
881
|
3: body,
|
|
883
882
|
};
|
|
884
883
|
}
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* @this {import("./ref").Client}
|
|
887
|
+
*/
|
|
888
|
+
async function infoSyncPushListener(blob, seq) {
|
|
889
|
+
const o = pb.decode(blob);
|
|
890
|
+
const type = o[3];
|
|
891
|
+
switch (type) {
|
|
892
|
+
case 2:
|
|
893
|
+
try {
|
|
894
|
+
const group_message_sync = o[7]; //群消息
|
|
895
|
+
if (group_message_sync && group_message_sync[3]) {
|
|
896
|
+
const groups = Array.isArray(group_message_sync[3]) ? group_message_sync[3] : [group_message_sync[3]];
|
|
897
|
+
for (let group of groups) {
|
|
898
|
+
const group_id = group[3];
|
|
899
|
+
const from_seq = group[4];
|
|
900
|
+
const to_seq = group[5];
|
|
901
|
+
const msgs = Array.isArray(group[6]) ? group[6] : [group[6]];
|
|
902
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
903
|
+
const msg = msgs[i];
|
|
904
|
+
await NTMsgSync.call(this, Buffer.from(pb.encode({ 1: msg })), seq);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
const olpush_sync = o[8]; //push732 push528 私聊消息
|
|
909
|
+
if (olpush_sync && olpush_sync[4]) {
|
|
910
|
+
const olpushs_groups = Array.isArray(olpush_sync[4]) ? olpush_sync[4] : [olpush_sync[4]];
|
|
911
|
+
for (let groups of olpushs_groups) {
|
|
912
|
+
const olpushs = Array.isArray(groups[8]) ? groups[8] : [groups[8]];
|
|
913
|
+
for (let i = olpushs.length - 1; i >= 0; i--) {
|
|
914
|
+
const olpush = olpushs[i];
|
|
915
|
+
await NTMsgSync.call(this, Buffer.from(pb.encode({ 1: olpush })), seq);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
const guild_sync = o[9]; //频道,用不上
|
|
920
|
+
} catch (e) {
|
|
921
|
+
this.logger.warn("NT同步消息失败");
|
|
922
|
+
this.logger.debug(e);
|
|
923
|
+
}
|
|
924
|
+
break;
|
|
925
|
+
case 5:
|
|
926
|
+
//群消息列表同步
|
|
927
|
+
try {
|
|
928
|
+
const list = Array.isArray(o[6]) ? o[6] : [o[6]];
|
|
929
|
+
const chats = [];
|
|
930
|
+
for (let chat of list) {
|
|
931
|
+
chats.push({
|
|
932
|
+
group_id: chat[1],
|
|
933
|
+
group_name: String(chat[9]),
|
|
934
|
+
unread_count: chat[2] - chat[3] - 1,
|
|
935
|
+
last_seq: chat[2],
|
|
936
|
+
last_unread_seq: chat[3],
|
|
937
|
+
})
|
|
938
|
+
}
|
|
939
|
+
this.em("new_tech_sync.group_list", chats);
|
|
940
|
+
} catch (e) {
|
|
941
|
+
this.logger.warn("群消息列表同步失败");
|
|
942
|
+
this.logger.debug(e);
|
|
943
|
+
}
|
|
944
|
+
break;
|
|
945
|
+
default:
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* @this {import("./ref").Client}
|
|
952
|
+
*/
|
|
953
|
+
async function NTMsgSync(blob, seq) {
|
|
954
|
+
const o = pb.decode(blob);
|
|
955
|
+
const type = o[1][2][1];
|
|
956
|
+
this.logger.debug("NT message type", type);
|
|
957
|
+
switch (type) {
|
|
958
|
+
case 82: //群聊消息
|
|
959
|
+
try {
|
|
960
|
+
const msg = groupNTMsgConverter.call(this, o);
|
|
961
|
+
//生成消息id
|
|
962
|
+
const head = msg[1], content = msg[2], body = msg[3];
|
|
963
|
+
if (head[9][2] === 127) return;
|
|
964
|
+
const user_id = head[1], time = head[6], seq = head[5];
|
|
965
|
+
const group_id = head[9][1], random = body[1][1][3];
|
|
966
|
+
const message_id = genGroupMessageId(group_id, user_id, seq, random, time, content[1]);
|
|
967
|
+
//懒得搞分片消息了
|
|
968
|
+
//解析消息
|
|
969
|
+
const data = await parseGroupMsg.call(this, msg, true);
|
|
970
|
+
if (data && data.raw_message) {
|
|
971
|
+
if (data.user_id === this.uin && this.config.ignore_self)
|
|
972
|
+
return;
|
|
973
|
+
data.reply = (message, auto_escape = false) => this.sendGroupMsg(data.group_id, message, auto_escape);
|
|
974
|
+
data.message_id = message_id;
|
|
975
|
+
const sender = data.sender;
|
|
976
|
+
this.logger.info(`nt sync message: [Group: ${data.group_name}(${data.group_id}), Member: ${sender.card ? sender.card : sender.nickname}(${data.user_id})] ` + data.raw_message);
|
|
977
|
+
this.em("new_tech_sync.group." + data.sub_type, data);
|
|
978
|
+
}
|
|
979
|
+
} catch (e) {
|
|
980
|
+
// this.logger.debug(e);
|
|
981
|
+
}
|
|
982
|
+
break;
|
|
983
|
+
case 141: //陌生人
|
|
984
|
+
case 166: //好友
|
|
985
|
+
case 167: //单向好友
|
|
986
|
+
case 208: //好友语音
|
|
987
|
+
case 529: //离线文件
|
|
988
|
+
try {
|
|
989
|
+
const msg = c2cNTMsgConverter.call(this, o);
|
|
990
|
+
const data = await parseC2CMsg.call(this, msg, true);
|
|
991
|
+
if (data.user_id === this.uin) {
|
|
992
|
+
data.user_id = msg[1][2];
|
|
993
|
+
this.em("new_tech_sync.private." + data.sub_type, data);
|
|
994
|
+
} else {
|
|
995
|
+
if (data && data.raw_message) {
|
|
996
|
+
data.reply = (message, auto_escape = false) => this.sendPrivateMsg(data.user_id, message, auto_escape);
|
|
997
|
+
this.logger.info(`nt sync message: [Private: ${data.user_id}(${data.sub_type})] ` + data.raw_message);
|
|
998
|
+
this.em("new_tech_sync.private." + data.sub_type, data);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
} catch (e) {
|
|
1002
|
+
this.logger.debug(e);
|
|
1003
|
+
}
|
|
1004
|
+
break;
|
|
1005
|
+
default:
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
885
1010
|
module.exports = {
|
|
886
|
-
onlinePushListener, onlinePushTransListener, c2cMsgSyncListener, groupMsgListener, discussMsgListener,
|
|
1011
|
+
onlinePushListener, onlinePushTransListener, c2cMsgSyncListener, groupMsgListener, discussMsgListener,
|
|
1012
|
+
NTMsgListener, infoSyncPushListener
|
|
887
1013
|
};
|
package/lib/qimei.js
CHANGED
|
@@ -17,6 +17,22 @@ LQ+FLkpncClKVIrBwv6PHyUvuCb0rIarmgDnzkfQAqVufEtR64iazGDKatvJ9y6B
|
|
|
17
17
|
9NMbHddGSAUmRTCrHQIDAQAB
|
|
18
18
|
-----END PUBLIC KEY-----`;
|
|
19
19
|
|
|
20
|
+
class SeededRandom {
|
|
21
|
+
constructor(seed) {
|
|
22
|
+
this.seed = seed;
|
|
23
|
+
this.state = md5(seed.toString()).toString("hex");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
next() {
|
|
27
|
+
this.state = md5(this.state + secret).toString("hex");
|
|
28
|
+
return parseInt(this.state.substring(0, 8), 16) / 0xffffffff;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
nextInt(min, max) {
|
|
32
|
+
return Math.floor(this.next() * (max - min + 1)) + min;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
20
36
|
function dateFormat(fmt = "YYYY-mm-dd HH:MM:SS", date = new Date()) {
|
|
21
37
|
let ret;
|
|
22
38
|
const opt = {
|
|
@@ -43,10 +59,9 @@ function dateFormat(fmt = "YYYY-mm-dd HH:MM:SS", date = new Date()) {
|
|
|
43
59
|
* @returns
|
|
44
60
|
*/
|
|
45
61
|
function genRandomPayloadByDevice(info, apk, platform) {
|
|
62
|
+
const seededRandom = new SeededRandom(info.android_id);
|
|
46
63
|
const rangeRand = (max = 1, min = 0) => {
|
|
47
|
-
|
|
48
|
-
const diff = max - min
|
|
49
|
-
return Math.floor(Math.random() * diff) + min
|
|
64
|
+
return seededRandom.nextInt(min, max);
|
|
50
65
|
};
|
|
51
66
|
const reserved = {
|
|
52
67
|
"harmony": "0",
|
|
@@ -67,10 +82,10 @@ function genRandomPayloadByDevice(info, apk, platform) {
|
|
|
67
82
|
"kernel": info.proc_version
|
|
68
83
|
};
|
|
69
84
|
let beaconId = "";
|
|
70
|
-
const timestamp =
|
|
71
|
-
const mtime1 = new Date(
|
|
85
|
+
const timestamp = info.mtime || apk.buildtime * 1000 + rangeRand(10 * 24 * 60 * 60 * 1000, 0);
|
|
86
|
+
const mtime1 = new Date(timestamp);
|
|
72
87
|
const mtimeStr1 = dateFormat("YYYY-mm-ddHHMMSS", mtime1) + "." + info.imei.slice(2, 11);
|
|
73
|
-
const mtime2 = new Date(
|
|
88
|
+
const mtime2 = new Date(timestamp - parseInt(info.imei.slice(2, 4)));
|
|
74
89
|
const mtimeStr2 = dateFormat("YYYY-mm-ddHHMMSS", mtime2) + "." + info.imei.slice(5, 14);
|
|
75
90
|
for (let i = 1; i <= 40; i++) {
|
|
76
91
|
if ([1, 13, 14, 17, 18, 21, 33, 34, 37, 38].includes(i)) {
|
package/lib/service.js
CHANGED
|
@@ -354,10 +354,47 @@ async function getUploadChannel() {
|
|
|
354
354
|
const rsp = pb.decode(blob)[1281];
|
|
355
355
|
this.storage.sig_session = rsp[1].toBuffer();
|
|
356
356
|
this.storage.session_key = rsp[2].toBuffer();
|
|
357
|
-
|
|
358
|
-
this.storage.
|
|
357
|
+
const server = Array.isArray(rsp[3][2]) ? rsp[3][2][0] : rsp[3][2];
|
|
358
|
+
this.storage.ip = int32ip2str(server[2]);
|
|
359
|
+
this.storage.port = server[3];
|
|
360
|
+
if (!(await checkIPConnectivity(this.storage.ip, this.storage.port))) {
|
|
361
|
+
this.logger.warn("上传通道IP不可用,将使用通用域名");
|
|
362
|
+
this.storage.ip = "v6.htdata.qq.com";
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 检查IP地址是否连通
|
|
368
|
+
* @param {string} ip - 要检查的IP地址
|
|
369
|
+
* @param {number} port - 要检查的端口号
|
|
370
|
+
* @param {number} timeout - 超时时间,单位毫秒
|
|
371
|
+
* @returns {Promise<boolean>}
|
|
372
|
+
*/
|
|
373
|
+
function checkIPConnectivity(ip, port, timeout = 5000) {
|
|
374
|
+
return new Promise((resolve) => {
|
|
375
|
+
const socket = new net.Socket();
|
|
376
|
+
|
|
377
|
+
socket.setTimeout(timeout);
|
|
378
|
+
|
|
379
|
+
socket.on('connect', () => {
|
|
380
|
+
socket.destroy();
|
|
381
|
+
resolve(true);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
socket.on('timeout', () => {
|
|
385
|
+
socket.destroy();
|
|
386
|
+
resolve(false);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
socket.on('error', () => {
|
|
390
|
+
socket.destroy();
|
|
391
|
+
resolve(false);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
socket.connect(port, ip);
|
|
395
|
+
});
|
|
359
396
|
}
|
|
360
397
|
|
|
361
398
|
module.exports = {
|
|
362
|
-
downloadFromWeb, highwayUploadStream, int32ip2str, highwayHttpUpload, MAX_UPLOAD_SIZE, getUploadChannel,
|
|
399
|
+
downloadFromWeb, highwayUploadStream, int32ip2str, highwayHttpUpload, MAX_UPLOAD_SIZE, getUploadChannel, checkIPConnectivity
|
|
363
400
|
};
|
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.24.
|
|
5
|
-
"app_version": "1.24.
|
|
6
|
-
"upday": "2024/08/
|
|
4
|
+
"version": "1.24.41",
|
|
5
|
+
"app_version": "1.24.41",
|
|
6
|
+
"upday": "2024/08/09",
|
|
7
7
|
"protocol_version": "v11",
|
|
8
8
|
"description": "oicq(https://github.com/takayama-lily/oicq) v1 for Icalingua++",
|
|
9
9
|
"main": "index.js",
|