@softtynet/zca-js 2.3.3 → 2.3.5
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/README.md +99 -21
- package/dist/apis/auth/exportSession.d.ts +7 -0
- package/dist/apis/auth/exportSession.js +17 -0
- package/dist/apis/call/addUserGroupCall.d.ts +11 -0
- package/dist/apis/call/addUserGroupCall.js +48 -0
- package/dist/apis/call/answerAckVoiceCall.d.ts +5 -0
- package/dist/apis/call/answerAckVoiceCall.js +38 -0
- package/dist/apis/call/answerGroupCall.d.ts +10 -0
- package/dist/apis/call/answerGroupCall.js +45 -0
- package/dist/apis/call/answerVoiceCall.d.ts +11 -0
- package/dist/apis/call/answerVoiceCall.js +50 -0
- package/dist/apis/call/broadcastGroupCallState.d.ts +10 -0
- package/dist/apis/call/broadcastGroupCallState.js +45 -0
- package/dist/apis/call/cancelGroupCall.d.ts +10 -0
- package/dist/apis/call/cancelGroupCall.js +45 -0
- package/dist/apis/call/cancelVoiceCall.d.ts +1 -1
- package/dist/apis/call/cancelVoiceCall.js +5 -1
- package/dist/apis/call/createController.d.ts +7 -0
- package/dist/apis/call/createController.js +9 -0
- package/dist/apis/call/createRtcSession.d.ts +8 -0
- package/dist/apis/call/createRtcSession.js +10 -0
- package/dist/apis/call/endGroupCall.d.ts +10 -0
- package/dist/apis/call/endGroupCall.js +45 -0
- package/dist/apis/call/finishGroupCall.d.ts +12 -0
- package/dist/apis/call/finishGroupCall.js +47 -0
- package/dist/apis/call/getGroupCallState.d.ts +3 -0
- package/dist/apis/call/getGroupCallState.js +38 -0
- package/dist/apis/call/holdVoiceCall.d.ts +5 -0
- package/dist/apis/call/holdVoiceCall.js +34 -0
- package/dist/apis/call/joinGroupCall.d.ts +11 -0
- package/dist/apis/call/joinGroupCall.js +46 -0
- package/dist/apis/call/logEndVoiceCall.d.ts +8 -0
- package/dist/apis/call/logEndVoiceCall.js +46 -0
- package/dist/apis/call/notifyGroupCall.d.ts +9 -0
- package/dist/apis/call/notifyGroupCall.js +44 -0
- package/dist/apis/call/pingGroupCall.d.ts +10 -0
- package/dist/apis/call/pingGroupCall.js +45 -0
- package/dist/apis/call/requestAudioToVideoCall.d.ts +5 -0
- package/dist/apis/call/requestAudioToVideoCall.js +37 -0
- package/dist/apis/call/requestGroupCall.d.ts +9 -0
- package/dist/apis/call/requestGroupCall.js +46 -0
- package/dist/apis/call/requestShareScreenCall.d.ts +5 -0
- package/dist/apis/call/requestShareScreenCall.js +37 -0
- package/dist/apis/call/requestVoiceCall.d.ts +10 -0
- package/dist/apis/call/requestVoiceCall.js +47 -0
- package/dist/apis/call/ringRingGroupCall.d.ts +10 -0
- package/dist/apis/call/ringRingGroupCall.js +45 -0
- package/dist/apis/call/ringRingVoiceCall.d.ts +5 -0
- package/dist/apis/call/ringRingVoiceCall.js +38 -0
- package/dist/apis/call/sendRequestGroupCall.d.ts +11 -0
- package/dist/apis/call/sendRequestGroupCall.js +48 -0
- package/dist/apis/call/sendRequestVoiceCall.d.ts +11 -0
- package/dist/apis/call/sendRequestVoiceCall.js +51 -0
- package/dist/apis/call/sendVoiceCall.d.ts +8 -1
- package/dist/apis/call/sendVoiceCall.js +10 -8
- package/dist/apis/call/shareScreenGroupCall.d.ts +10 -0
- package/dist/apis/call/shareScreenGroupCall.js +45 -0
- package/dist/apis/call/unholdVoiceCall.d.ts +5 -0
- package/dist/apis/call/unholdVoiceCall.js +34 -0
- package/dist/apis/call/updateCallMediaState.d.ts +7 -0
- package/dist/apis/call/updateCallMediaState.js +61 -0
- package/dist/apis/chat/getDirectMessageStatus.d.ts +14 -0
- package/dist/apis/chat/getDirectMessageStatus.js +52 -0
- package/dist/apis/chat/getSuggestedConversations.d.ts +5 -0
- package/dist/apis/chat/getSuggestedConversations.js +24 -0
- package/dist/apis/chat/updatePinConversations.d.ts +24 -0
- package/dist/apis/chat/updatePinConversations.js +40 -0
- package/dist/apis/friend/getFriendProfilesV2.d.ts +26 -0
- package/dist/apis/friend/getFriendProfilesV2.js +38 -0
- package/dist/apis/friend/getFriendsActivePCWeb.d.ts +6 -0
- package/dist/apis/friend/getFriendsActivePCWeb.js +15 -0
- package/dist/apis/friend/verifyFriend.d.ts +11 -0
- package/dist/apis/friend/verifyFriend.js +37 -0
- package/dist/apis/group/analyseGroup.d.ts +4 -0
- package/dist/apis/group/analyseGroup.js +28 -0
- package/dist/apis/group/checkQuotaCommunityMember.d.ts +6 -0
- package/dist/apis/group/checkQuotaCommunityMember.js +34 -0
- package/dist/apis/group/getE2eeGroupList.d.ts +7 -0
- package/dist/apis/group/getE2eeGroupList.js +15 -0
- package/dist/apis/group/getGroupCloudMessagePath.d.ts +19 -0
- package/dist/apis/group/getGroupCloudMessagePath.js +51 -0
- package/dist/apis/group/getMultiGroupCloudMessages.d.ts +5 -0
- package/dist/apis/group/getMultiGroupCloudMessages.js +29 -0
- package/dist/apis/media/getPersonalMedia.d.ts +8 -0
- package/dist/apis/media/getPersonalMedia.js +31 -0
- package/dist/apis/media/getPersonalMediaPreview.d.ts +3 -0
- package/dist/apis/media/getPersonalMediaPreview.js +24 -0
- package/dist/apis/media/removePersonalMedia.d.ts +9 -0
- package/dist/apis/media/removePersonalMedia.js +28 -0
- package/dist/apis.d.ts +126 -0
- package/dist/apis.js +210 -0
- package/dist/call-engine/ZRTPPacketCodec.d.ts +262 -0
- package/dist/call-engine/ZRTPPacketCodec.js +506 -0
- package/dist/call-engine/ZaloCallController.d.ts +134 -0
- package/dist/call-engine/ZaloCallController.js +638 -0
- package/dist/call-engine/ZaloCallTransport.d.ts +83 -0
- package/dist/call-engine/ZaloCallTransport.js +233 -0
- package/dist/call-engine/ZaloRtcSession.d.ts +609 -0
- package/dist/call-engine/ZaloRtcSession.js +2931 -0
- package/dist/call-engine/ZaloSrtpSession.d.ts +80 -0
- package/dist/call-engine/ZaloSrtpSession.js +278 -0
- package/dist/call-engine/index.d.ts +18 -0
- package/dist/call-engine/index.js +24 -0
- package/dist/cjs/apis/auth/exportSession.cjs +22 -0
- package/dist/cjs/apis/call/addUserGroupCall.cjs +53 -0
- package/dist/cjs/apis/call/answerAckVoiceCall.cjs +43 -0
- package/dist/cjs/apis/call/answerGroupCall.cjs +50 -0
- package/dist/cjs/apis/call/answerVoiceCall.cjs +55 -0
- package/dist/cjs/apis/call/broadcastGroupCallState.cjs +50 -0
- package/dist/cjs/apis/call/cancelGroupCall.cjs +50 -0
- package/dist/cjs/apis/call/cancelVoiceCall.cjs +5 -1
- package/dist/cjs/apis/call/createController.cjs +14 -0
- package/dist/cjs/apis/call/createRtcSession.cjs +15 -0
- package/dist/cjs/apis/call/endGroupCall.cjs +50 -0
- package/dist/cjs/apis/call/finishGroupCall.cjs +52 -0
- package/dist/cjs/apis/call/getGroupCallState.cjs +43 -0
- package/dist/cjs/apis/call/holdVoiceCall.cjs +39 -0
- package/dist/cjs/apis/call/joinGroupCall.cjs +51 -0
- package/dist/cjs/apis/call/logEndVoiceCall.cjs +51 -0
- package/dist/cjs/apis/call/notifyGroupCall.cjs +49 -0
- package/dist/cjs/apis/call/pingGroupCall.cjs +50 -0
- package/dist/cjs/apis/call/requestAudioToVideoCall.cjs +42 -0
- package/dist/cjs/apis/call/requestGroupCall.cjs +51 -0
- package/dist/cjs/apis/call/requestShareScreenCall.cjs +42 -0
- package/dist/cjs/apis/call/requestVoiceCall.cjs +52 -0
- package/dist/cjs/apis/call/ringRingGroupCall.cjs +50 -0
- package/dist/cjs/apis/call/ringRingVoiceCall.cjs +43 -0
- package/dist/cjs/apis/call/sendRequestGroupCall.cjs +53 -0
- package/dist/cjs/apis/call/sendRequestVoiceCall.cjs +56 -0
- package/dist/cjs/apis/call/sendVoiceCall.cjs +10 -8
- package/dist/cjs/apis/call/shareScreenGroupCall.cjs +50 -0
- package/dist/cjs/apis/call/unholdVoiceCall.cjs +39 -0
- package/dist/cjs/apis/call/updateCallMediaState.cjs +66 -0
- package/dist/cjs/apis/chat/getDirectMessageStatus.cjs +58 -0
- package/dist/cjs/apis/chat/getSuggestedConversations.cjs +29 -0
- package/dist/cjs/apis/chat/updatePinConversations.cjs +45 -0
- package/dist/cjs/apis/friend/getFriendProfilesV2.cjs +43 -0
- package/dist/cjs/apis/friend/getFriendsActivePCWeb.cjs +20 -0
- package/dist/cjs/apis/friend/verifyFriend.cjs +42 -0
- package/dist/cjs/apis/group/analyseGroup.cjs +33 -0
- package/dist/cjs/apis/group/checkQuotaCommunityMember.cjs +39 -0
- package/dist/cjs/apis/group/getE2eeGroupList.cjs +20 -0
- package/dist/cjs/apis/group/getGroupChatHistory.cjs +8 -7
- package/dist/cjs/apis/group/getGroupCloudMessagePath.cjs +69 -0
- package/dist/cjs/apis/group/getGroupHistoryLegacy.cjs +7 -6
- package/dist/cjs/apis/group/getGroupMessageStatus.cjs +7 -6
- package/dist/cjs/apis/group/getMultiGroupCloudMessages.cjs +34 -0
- package/dist/cjs/apis/media/getPersonalMedia.cjs +36 -0
- package/dist/cjs/apis/media/getPersonalMediaPreview.cjs +29 -0
- package/dist/cjs/apis/media/removePersonalMedia.cjs +33 -0
- package/dist/cjs/apis.cjs +210 -0
- package/dist/cjs/call-engine/ZRTPPacketCodec.cjs +525 -0
- package/dist/cjs/call-engine/ZaloCallController.cjs +643 -0
- package/dist/cjs/call-engine/ZaloCallTransport.cjs +239 -0
- package/dist/cjs/call-engine/ZaloRtcSession.cjs +2937 -0
- package/dist/cjs/call-engine/ZaloSrtpSession.cjs +287 -0
- package/dist/cjs/constants/protocol.cjs +1 -1
- package/dist/cjs/context.cjs +20 -2
- package/dist/cjs/core/zcloud-client.cjs +1 -2
- package/dist/cjs/crypto/ws-cipher.cjs +66 -2
- package/dist/cjs/index.cjs +63 -6
- package/dist/cjs/models/CallEvent.cjs +95 -1
- package/dist/cjs/realtime/handlers/control.handler.cjs +17 -3
- package/dist/cjs/realtime/listener.cjs +37 -6
- package/dist/cjs/update.cjs +10 -1
- package/dist/cjs/utils.cjs +21 -68
- package/dist/constants/protocol.d.ts +1 -1
- package/dist/constants/protocol.js +1 -1
- package/dist/context.d.ts +10 -0
- package/dist/context.js +20 -2
- package/dist/crypto/ws-cipher.d.ts +7 -0
- package/dist/crypto/ws-cipher.js +64 -2
- package/dist/index.d.ts +47 -4
- package/dist/index.js +2 -0
- package/dist/models/CallEvent.d.ts +15 -0
- package/dist/models/CallEvent.js +95 -1
- package/dist/realtime/handlers/control.handler.js +17 -3
- package/dist/realtime/listener.d.ts +6 -0
- package/dist/realtime/listener.js +37 -6
- package/dist/update.js +10 -1
- package/dist/utils.d.ts +0 -7
- package/dist/utils.js +15 -64
- package/index.d.ts +1 -1
- package/package.json +16 -5
|
@@ -4,11 +4,24 @@ exports.CallEventType = void 0;
|
|
|
4
4
|
(function (CallEventType) {
|
|
5
5
|
CallEventType["REQUEST"] = "request";
|
|
6
6
|
CallEventType["ANSWER"] = "answer";
|
|
7
|
+
CallEventType["ANSWER_ACK"] = "answer_ack";
|
|
7
8
|
CallEventType["CANCEL"] = "cancel";
|
|
8
9
|
CallEventType["END"] = "end";
|
|
9
10
|
CallEventType["RINGRING"] = "ringring";
|
|
11
|
+
CallEventType["ONOFF_CAMERA"] = "onoff_camera";
|
|
12
|
+
CallEventType["MUTE_AUDIO"] = "mute_audio";
|
|
13
|
+
CallEventType["AUDIO_TO_VIDEO"] = "audio_to_video";
|
|
14
|
+
CallEventType["SHARE_SCREEN"] = "share_screen";
|
|
10
15
|
CallEventType["GROUP_REQUEST"] = "group_request";
|
|
16
|
+
CallEventType["GROUP_RINGRING"] = "group_ring_ring";
|
|
11
17
|
CallEventType["GROUP_ANSWER"] = "group_answer";
|
|
18
|
+
CallEventType["GROUP_ANSWER_ACK"] = "group_answer_ack";
|
|
19
|
+
CallEventType["GROUP_CANCEL"] = "group_cancel";
|
|
20
|
+
CallEventType["GROUP_END"] = "group_end_call";
|
|
21
|
+
CallEventType["GROUP_ADD_USER"] = "group_add_user";
|
|
22
|
+
CallEventType["GROUP_NOTIFY"] = "group_notify";
|
|
23
|
+
CallEventType["GROUP_BROADCAST"] = "group_broadcast";
|
|
24
|
+
CallEventType["GROUP_BROADCAST_CONFIG"] = "group_broadcast_config";
|
|
12
25
|
CallEventType["UNKNOWN"] = "unknown";
|
|
13
26
|
})(exports.CallEventType || (exports.CallEventType = {}));
|
|
14
27
|
function initializeCallEvent(data, act, act_type) {
|
|
@@ -20,31 +33,112 @@ function initializeCallEvent(data, act, act_type) {
|
|
|
20
33
|
case "answer":
|
|
21
34
|
type = exports.CallEventType.ANSWER;
|
|
22
35
|
break;
|
|
36
|
+
case "answer_ack":
|
|
37
|
+
case "answerack":
|
|
38
|
+
type = exports.CallEventType.ANSWER_ACK;
|
|
39
|
+
break;
|
|
23
40
|
case "cancel":
|
|
24
41
|
type = exports.CallEventType.CANCEL;
|
|
25
42
|
break;
|
|
26
43
|
case "end":
|
|
27
44
|
case "endcall":
|
|
45
|
+
case "end_call":
|
|
28
46
|
type = exports.CallEventType.END;
|
|
29
47
|
break;
|
|
30
48
|
case "ringring":
|
|
49
|
+
case "ring_ring":
|
|
31
50
|
type = exports.CallEventType.RINGRING;
|
|
32
51
|
break;
|
|
52
|
+
case "onoff_camera":
|
|
53
|
+
type = exports.CallEventType.ONOFF_CAMERA;
|
|
54
|
+
break;
|
|
55
|
+
case "mute_audio":
|
|
56
|
+
type = exports.CallEventType.MUTE_AUDIO;
|
|
57
|
+
break;
|
|
58
|
+
case "audio_to_video":
|
|
59
|
+
type = exports.CallEventType.AUDIO_TO_VIDEO;
|
|
60
|
+
break;
|
|
61
|
+
case "share_screen":
|
|
62
|
+
type = exports.CallEventType.SHARE_SCREEN;
|
|
63
|
+
break;
|
|
33
64
|
case "group_request":
|
|
34
65
|
type = exports.CallEventType.GROUP_REQUEST;
|
|
35
66
|
break;
|
|
67
|
+
case "group_ring_ring":
|
|
68
|
+
case "group_ringring":
|
|
69
|
+
type = exports.CallEventType.GROUP_RINGRING;
|
|
70
|
+
break;
|
|
36
71
|
case "group_answer":
|
|
37
72
|
type = exports.CallEventType.GROUP_ANSWER;
|
|
38
73
|
break;
|
|
74
|
+
case "group_answer_ack":
|
|
75
|
+
type = exports.CallEventType.GROUP_ANSWER_ACK;
|
|
76
|
+
break;
|
|
77
|
+
case "group_cancel":
|
|
78
|
+
type = exports.CallEventType.GROUP_CANCEL;
|
|
79
|
+
break;
|
|
80
|
+
case "group_end_call":
|
|
81
|
+
case "group_endcall":
|
|
82
|
+
case "group_end":
|
|
83
|
+
type = exports.CallEventType.GROUP_END;
|
|
84
|
+
break;
|
|
85
|
+
case "group_add_user":
|
|
86
|
+
type = exports.CallEventType.GROUP_ADD_USER;
|
|
87
|
+
break;
|
|
88
|
+
case "group_notify":
|
|
89
|
+
type = exports.CallEventType.GROUP_NOTIFY;
|
|
90
|
+
break;
|
|
91
|
+
case "group_broadcast":
|
|
92
|
+
type = exports.CallEventType.GROUP_BROADCAST;
|
|
93
|
+
break;
|
|
94
|
+
case "group_broadcast_config":
|
|
95
|
+
type = exports.CallEventType.GROUP_BROADCAST_CONFIG;
|
|
96
|
+
break;
|
|
39
97
|
default:
|
|
40
98
|
type = exports.CallEventType.UNKNOWN;
|
|
41
99
|
break;
|
|
42
100
|
}
|
|
101
|
+
const enrichedData = { ...data };
|
|
102
|
+
let parsedParams;
|
|
103
|
+
if (typeof enrichedData.params === "string") {
|
|
104
|
+
try {
|
|
105
|
+
const p = JSON.parse(enrichedData.params);
|
|
106
|
+
if (p && typeof p === "object")
|
|
107
|
+
parsedParams = p;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Ignore invalid JSON
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else if (enrichedData.params && typeof enrichedData.params === "object") {
|
|
114
|
+
parsedParams = enrichedData.params;
|
|
115
|
+
}
|
|
116
|
+
if (enrichedData.callId === undefined) {
|
|
117
|
+
const extractedCallId = Number(enrichedData.call_id ??
|
|
118
|
+
enrichedData.id ??
|
|
119
|
+
parsedParams?.callId ??
|
|
120
|
+
parsedParams?.call_id ??
|
|
121
|
+
parsedParams?.id ??
|
|
122
|
+
0);
|
|
123
|
+
if (extractedCallId > 0) {
|
|
124
|
+
enrichedData.callId = extractedCallId;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (enrichedData.callerId === undefined) {
|
|
128
|
+
const extractedCallerId = enrichedData.uidN ??
|
|
129
|
+
parsedParams?.uidN ??
|
|
130
|
+
enrichedData.uidFrom ??
|
|
131
|
+
enrichedData.fromId ??
|
|
132
|
+
parsedParams?.uidFrom;
|
|
133
|
+
if (extractedCallerId !== undefined) {
|
|
134
|
+
enrichedData.callerId = String(extractedCallerId);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
43
137
|
return {
|
|
44
138
|
type,
|
|
45
139
|
act,
|
|
46
140
|
act_type,
|
|
47
|
-
data,
|
|
141
|
+
data: enrichedData,
|
|
48
142
|
};
|
|
49
143
|
}
|
|
50
144
|
|
|
@@ -8,10 +8,15 @@ var utils = require('../../utils.cjs');
|
|
|
8
8
|
var wsCipher = require('../../crypto/ws-cipher.cjs');
|
|
9
9
|
|
|
10
10
|
async function handleRealtimeControlPacket(listener, ctx, selfListen, version, cmd, subCmd, parsed, cipherKey) {
|
|
11
|
-
if (version == 1 && cmd == 601 && subCmd == 0) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
11
|
+
if (version == 1 && (cmd == 601 || cmd == 603 || cmd == 604) && subCmd == 0) {
|
|
12
|
+
const decoded = await wsCipher.decodeEventData(parsed, cipherKey);
|
|
13
|
+
const parsedData = decoded?.data;
|
|
14
|
+
const controls = parsedData?.controls;
|
|
15
|
+
if (!Array.isArray(controls))
|
|
16
|
+
return false;
|
|
14
17
|
for (const control of controls) {
|
|
18
|
+
if (!control?.content)
|
|
19
|
+
continue;
|
|
15
20
|
if (control.content.act_type == "file_done") {
|
|
16
21
|
const data = {
|
|
17
22
|
fileUrl: control.content.data.url,
|
|
@@ -62,6 +67,15 @@ async function handleRealtimeControlPacket(listener, ctx, selfListen, version, c
|
|
|
62
67
|
const callEventData = typeof control.content.data == "string"
|
|
63
68
|
? JSON.parse(control.content.data)
|
|
64
69
|
: control.content.data;
|
|
70
|
+
// Bỏ qua các gói mời gọi cũ (> 60s) nằm trong hàng đợi offline (cmd 603 / 604)
|
|
71
|
+
if ((cmd == 603 || cmd == 604) &&
|
|
72
|
+
(control.content.act == "request" || control.content.act == "group_request") &&
|
|
73
|
+
callEventData?.ts) {
|
|
74
|
+
const eventTs = Number.parseInt(String(callEventData.ts), 10);
|
|
75
|
+
if (Number.isFinite(eventTs) && Date.now() - eventTs > 60_000) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
65
79
|
const callEvent = CallEvent.initializeCallEvent(callEventData, control.content.act, control.content.act_type);
|
|
66
80
|
listener.emit("call_event", callEvent);
|
|
67
81
|
}
|
|
@@ -43,6 +43,7 @@ class Listener extends EventEmitter {
|
|
|
43
43
|
retryTimeout;
|
|
44
44
|
watchdogTimeout;
|
|
45
45
|
consecutive1006Count = 0;
|
|
46
|
+
isManualStop = false;
|
|
46
47
|
id = 0;
|
|
47
48
|
constructor(ctx, urls) {
|
|
48
49
|
super();
|
|
@@ -168,6 +169,7 @@ class Listener extends EventEmitter {
|
|
|
168
169
|
utils.logger(this.ctx).verbose(`Rotating endpoint to ${this.wsURL}`);
|
|
169
170
|
}
|
|
170
171
|
start({ retryOnClose = false } = {}) {
|
|
172
|
+
this.isManualStop = false;
|
|
171
173
|
if (this.retryTimeout) {
|
|
172
174
|
clearTimeout(this.retryTimeout);
|
|
173
175
|
this.retryTimeout = undefined;
|
|
@@ -191,6 +193,10 @@ class Listener extends EventEmitter {
|
|
|
191
193
|
t: Date.now(),
|
|
192
194
|
});
|
|
193
195
|
const cookie = this.ctx.cookie.getCookieStringSync(domains.ZALO_DOMAINS.CHAT_WEB);
|
|
196
|
+
const wsAgent = this.ctx.options.agent &&
|
|
197
|
+
typeof this.ctx.options.agent.dispatch !== "function"
|
|
198
|
+
? this.ctx.options.agent
|
|
199
|
+
: undefined;
|
|
194
200
|
const ws = new WebSocket(this.wsURL, {
|
|
195
201
|
headers: {
|
|
196
202
|
"accept-language": utils.getBrowserLanguage(this.ctx.language),
|
|
@@ -205,7 +211,7 @@ class Listener extends EventEmitter {
|
|
|
205
211
|
"user-agent": this.userAgent,
|
|
206
212
|
cookie,
|
|
207
213
|
},
|
|
208
|
-
agent:
|
|
214
|
+
...(wsAgent ? { agent: wsAgent } : {}),
|
|
209
215
|
});
|
|
210
216
|
this.ws = ws;
|
|
211
217
|
ws.onopen = () => {
|
|
@@ -218,7 +224,8 @@ class Listener extends EventEmitter {
|
|
|
218
224
|
ws.onclose = (event) => {
|
|
219
225
|
this.reset();
|
|
220
226
|
this.emit("disconnected", event.code, event.reason);
|
|
221
|
-
const retry =
|
|
227
|
+
const retry = !this.isManualStop &&
|
|
228
|
+
retryOnClose &&
|
|
222
229
|
this.isRetryable(event.code) &&
|
|
223
230
|
this.canRetry(event.code);
|
|
224
231
|
if (retry && retryOnClose) {
|
|
@@ -262,6 +269,7 @@ class Listener extends EventEmitter {
|
|
|
262
269
|
if (version == 1 && cmd == 1 && subCmd == 1 && utils.hasOwn(parsed, "key")) {
|
|
263
270
|
this.cipherKey = parsed.key;
|
|
264
271
|
this.emit("cipher_key", this.cipherKey);
|
|
272
|
+
this.requestOfflineVoipControls();
|
|
265
273
|
if (this.pingInterval)
|
|
266
274
|
clearInterval(this.pingInterval);
|
|
267
275
|
const ping = () => {
|
|
@@ -304,19 +312,24 @@ class Listener extends EventEmitter {
|
|
|
304
312
|
};
|
|
305
313
|
}
|
|
306
314
|
stop() {
|
|
307
|
-
|
|
315
|
+
this.isManualStop = true;
|
|
316
|
+
if (this.retryTimeout) {
|
|
308
317
|
clearTimeout(this.retryTimeout);
|
|
309
|
-
|
|
318
|
+
this.retryTimeout = undefined;
|
|
319
|
+
}
|
|
320
|
+
if (this.watchdogTimeout) {
|
|
310
321
|
clearTimeout(this.watchdogTimeout);
|
|
322
|
+
this.watchdogTimeout = undefined;
|
|
323
|
+
}
|
|
311
324
|
if (this.ws) {
|
|
312
|
-
if (this.ws.readyState !== WebSocket.CLOSED) {
|
|
325
|
+
if (this.ws.readyState !== WebSocket.CLOSED && this.ws.readyState !== WebSocket.CLOSING) {
|
|
313
326
|
this.ws.close(types.CloseReason.ManualClosure);
|
|
314
327
|
}
|
|
315
328
|
}
|
|
316
329
|
this.reset();
|
|
317
330
|
}
|
|
318
331
|
sendWs(payload, requireId = true) {
|
|
319
|
-
if (this.ws) {
|
|
332
|
+
if (this.ws && (this.ws.readyState === undefined || this.ws.readyState === WebSocket.OPEN)) {
|
|
320
333
|
if (requireId)
|
|
321
334
|
payload.data["req_id"] = `req_${this.id++}`;
|
|
322
335
|
const encodedData = new TextEncoder().encode(JSON.stringify(payload.data));
|
|
@@ -362,6 +375,24 @@ class Listener extends EventEmitter {
|
|
|
362
375
|
};
|
|
363
376
|
this.sendWs(payload);
|
|
364
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Kích hoạt và kéo hàng đợi sự kiện điều khiển / VoIP (`cmd 603` CTRL_PULL_CTRL và `cmd 604` CTRL_PULL_VOIP).
|
|
380
|
+
* Giúp nhận ngay các cuộc gọi đến đang đổ chuông ngay cả khi vừa mở kết nối WebSocket.
|
|
381
|
+
*/
|
|
382
|
+
requestOfflineVoipControls() {
|
|
383
|
+
this.sendWs({
|
|
384
|
+
version: 1,
|
|
385
|
+
cmd: 604,
|
|
386
|
+
subCmd: 0,
|
|
387
|
+
data: { first: true, lastId: 1, preIds: [] },
|
|
388
|
+
});
|
|
389
|
+
this.sendWs({
|
|
390
|
+
version: 1,
|
|
391
|
+
cmd: 603,
|
|
392
|
+
subCmd: 0,
|
|
393
|
+
data: { first: true, lastId: "1", preIds: [] },
|
|
394
|
+
});
|
|
395
|
+
}
|
|
365
396
|
reset() {
|
|
366
397
|
this.ws = null;
|
|
367
398
|
this.cipherKey = undefined;
|
package/dist/cjs/update.cjs
CHANGED
|
@@ -10,6 +10,9 @@ const NPM_REGISTRY = domains.ZALO_DOMAINS.NPM_REGISTRY;
|
|
|
10
10
|
async function checkUpdate(ctx) {
|
|
11
11
|
if (!ctx.options.checkUpdate)
|
|
12
12
|
return;
|
|
13
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
14
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
15
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
13
16
|
const _options = {
|
|
14
17
|
...(utils.isBun
|
|
15
18
|
? {
|
|
@@ -17,7 +20,13 @@ async function checkUpdate(ctx) {
|
|
|
17
20
|
// @ts-ignore
|
|
18
21
|
proxy: ctx.options.agent?.proxy?.href,
|
|
19
22
|
}
|
|
20
|
-
: {
|
|
23
|
+
: {
|
|
24
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
25
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
26
|
+
}),
|
|
27
|
+
...(typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function"
|
|
28
|
+
? { signal: AbortSignal.timeout(3000) }
|
|
29
|
+
: {}),
|
|
21
30
|
};
|
|
22
31
|
const response = await ctx.options.polyfill(NPM_REGISTRY, _options).catch(() => null);
|
|
23
32
|
if (!response || !response.ok)
|
package/dist/cjs/utils.cjs
CHANGED
|
@@ -15,8 +15,7 @@ var protocol = require('./constants/protocol.cjs');
|
|
|
15
15
|
var domains = require('./constants/domains.cjs');
|
|
16
16
|
var defaults = require('./constants/defaults.cjs');
|
|
17
17
|
var aes = require('./crypto/aes.cjs');
|
|
18
|
-
require('
|
|
19
|
-
require('json-bigint');
|
|
18
|
+
var wsCipher = require('./crypto/ws-cipher.cjs');
|
|
20
19
|
|
|
21
20
|
const isBun = typeof Bun !== "undefined";
|
|
22
21
|
function hasOwn(obj, key) {
|
|
@@ -166,8 +165,20 @@ async function request(ctx, url, options, raw = false) {
|
|
|
166
165
|
options = { ...(options || {}), headers: defaultHeaders };
|
|
167
166
|
}
|
|
168
167
|
}
|
|
168
|
+
const timeoutMs = ctx.options?.requestTimeout;
|
|
169
|
+
const defaultSignal = !options?.signal &&
|
|
170
|
+
typeof timeoutMs === "number" &&
|
|
171
|
+
timeoutMs > 0 &&
|
|
172
|
+
typeof AbortSignal !== "undefined" &&
|
|
173
|
+
typeof AbortSignal.timeout === "function"
|
|
174
|
+
? AbortSignal.timeout(timeoutMs)
|
|
175
|
+
: undefined;
|
|
176
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
177
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
178
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
169
179
|
const _options = {
|
|
170
180
|
...(options ?? {}),
|
|
181
|
+
...(defaultSignal ? { signal: defaultSignal } : {}),
|
|
171
182
|
...(isBun
|
|
172
183
|
? {
|
|
173
184
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -175,8 +186,8 @@ async function request(ctx, url, options, raw = false) {
|
|
|
175
186
|
proxy: ctx.options.agent?.proxy?.href,
|
|
176
187
|
}
|
|
177
188
|
: {
|
|
178
|
-
agent:
|
|
179
|
-
dispatcher:
|
|
189
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
190
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
180
191
|
}),
|
|
181
192
|
};
|
|
182
193
|
const response = await ctx.options.polyfill(url, _options);
|
|
@@ -452,67 +463,6 @@ function getFriendEventType(act) {
|
|
|
452
463
|
return FriendEvent.FriendEventType.PIN_CREATE;
|
|
453
464
|
return FriendEvent.FriendEventType.UNKNOWN;
|
|
454
465
|
}
|
|
455
|
-
const DEFAULT_BIGINT_ID_FIELDS = [
|
|
456
|
-
"owner_id",
|
|
457
|
-
"group_id",
|
|
458
|
-
"uidFrom",
|
|
459
|
-
"uidTo",
|
|
460
|
-
"uid",
|
|
461
|
-
"ownerId",
|
|
462
|
-
"destId",
|
|
463
|
-
"srcId",
|
|
464
|
-
"fromUid",
|
|
465
|
-
"threadId",
|
|
466
|
-
"globalMsgId",
|
|
467
|
-
"global_msg_id",
|
|
468
|
-
"globalDelMsgId",
|
|
469
|
-
"msgId",
|
|
470
|
-
"refMessageId",
|
|
471
|
-
"cliMsgId",
|
|
472
|
-
"client_msg_id",
|
|
473
|
-
"actionId",
|
|
474
|
-
"lastActionIdOther",
|
|
475
|
-
"lastActionId",
|
|
476
|
-
"resetLastActionId",
|
|
477
|
-
"lastId",
|
|
478
|
-
"ids",
|
|
479
|
-
"topicId",
|
|
480
|
-
"reminderId",
|
|
481
|
-
"eventId",
|
|
482
|
-
];
|
|
483
|
-
/**
|
|
484
|
-
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
485
|
-
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
486
|
-
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
487
|
-
*/
|
|
488
|
-
function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
|
|
489
|
-
if (!jsonStr || typeof jsonStr !== "string")
|
|
490
|
-
return jsonStr;
|
|
491
|
-
const alwaysSet = new Set(alwaysStringFields);
|
|
492
|
-
const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
|
|
493
|
-
if (allFields.length === 0)
|
|
494
|
-
return jsonStr;
|
|
495
|
-
const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
496
|
-
const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
|
|
497
|
-
return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
|
|
498
|
-
const forceString = alwaysSet.has(key);
|
|
499
|
-
if (rawVal.startsWith("[")) {
|
|
500
|
-
const inner = rawVal.slice(1, -1);
|
|
501
|
-
const parts = inner.split(",").map((part) => {
|
|
502
|
-
const trimmed = part.trim();
|
|
503
|
-
if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
|
|
504
|
-
return `"${trimmed}"`;
|
|
505
|
-
}
|
|
506
|
-
return trimmed;
|
|
507
|
-
});
|
|
508
|
-
return `"${key}"${sep}[${parts.join(",")}]`;
|
|
509
|
-
}
|
|
510
|
-
if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
|
|
511
|
-
return `"${key}"${sep}"${rawVal}"`;
|
|
512
|
-
}
|
|
513
|
-
return fullMatch;
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
466
|
async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
517
467
|
const result = {
|
|
518
468
|
data: null,
|
|
@@ -542,7 +492,7 @@ async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
|
542
492
|
result.data = {};
|
|
543
493
|
return result;
|
|
544
494
|
}
|
|
545
|
-
const safeJsonStr = isEncrypted ? preParseJsonIds(decodedStr) : null;
|
|
495
|
+
const safeJsonStr = isEncrypted ? wsCipher.preParseJsonIds(decodedStr) : null;
|
|
546
496
|
const decodedData = isEncrypted ? JSON.parse(safeJsonStr) : jsonData;
|
|
547
497
|
if (decodedData.error_code != 0) {
|
|
548
498
|
result.error = {
|
|
@@ -616,7 +566,11 @@ exports.decryptResp = aes.decryptResp;
|
|
|
616
566
|
exports.encodeAES = aes.encodeAES;
|
|
617
567
|
exports.encryptPin = aes.encryptPin;
|
|
618
568
|
exports.validatePin = aes.validatePin;
|
|
619
|
-
exports.DEFAULT_BIGINT_ID_FIELDS = DEFAULT_BIGINT_ID_FIELDS;
|
|
569
|
+
exports.DEFAULT_BIGINT_ID_FIELDS = wsCipher.DEFAULT_BIGINT_ID_FIELDS;
|
|
570
|
+
exports.decodeBase64ToBuffer = wsCipher.decodeBase64ToBuffer;
|
|
571
|
+
exports.decodeEventData = wsCipher.decodeEventData;
|
|
572
|
+
exports.decodeUnit8Array = wsCipher.decodeUnit8Array;
|
|
573
|
+
exports.preParseJsonIds = wsCipher.preParseJsonIds;
|
|
620
574
|
exports.apiFactory = apiFactory;
|
|
621
575
|
exports.formatTime = formatTime;
|
|
622
576
|
exports.generateZaloUUID = generateZaloUUID;
|
|
@@ -642,7 +596,6 @@ exports.isBun = isBun;
|
|
|
642
596
|
exports.logger = logger;
|
|
643
597
|
exports.makeURL = makeURL;
|
|
644
598
|
exports.normalizeHolderName = normalizeHolderName;
|
|
645
|
-
exports.preParseJsonIds = preParseJsonIds;
|
|
646
599
|
exports.removeUndefinedKeys = removeUndefinedKeys;
|
|
647
600
|
exports.request = request;
|
|
648
601
|
exports.resolveResponse = resolveResponse;
|
|
@@ -10,7 +10,7 @@ export declare const ZALO_PROTOCOL: {
|
|
|
10
10
|
readonly API_VERSION: 689;
|
|
11
11
|
readonly DEFAULT_API_VERSION: 689;
|
|
12
12
|
/** Phiên bản SDK hiện tại */
|
|
13
|
-
readonly SDK_VERSION: "2.3.
|
|
13
|
+
readonly SDK_VERSION: "2.3.5";
|
|
14
14
|
/** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
|
|
15
15
|
readonly VOICECALL_API_TYPE: 24;
|
|
16
16
|
/** Phiên bản mã hóa ZCID (ParamDecryptor) */
|
|
@@ -10,7 +10,7 @@ export const ZALO_PROTOCOL = {
|
|
|
10
10
|
API_VERSION: 689,
|
|
11
11
|
DEFAULT_API_VERSION: 689,
|
|
12
12
|
/** Phiên bản SDK hiện tại */
|
|
13
|
-
SDK_VERSION: "2.3.
|
|
13
|
+
SDK_VERSION: "2.3.5",
|
|
14
14
|
/** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
|
|
15
15
|
VOICECALL_API_TYPE: 24,
|
|
16
16
|
/** Phiên bản mã hóa ZCID (ParamDecryptor) */
|
package/dist/context.d.ts
CHANGED
|
@@ -154,18 +154,28 @@ export type Options = {
|
|
|
154
154
|
apiType: number;
|
|
155
155
|
apiVersion: number;
|
|
156
156
|
agent?: Agent;
|
|
157
|
+
/**
|
|
158
|
+
* Bộ điều phối kết nối (Undici `Dispatcher` / `ProxyAgent`) dành cho `globalThis.fetch` mặc định của Node.js 18+.
|
|
159
|
+
*/
|
|
160
|
+
dispatcher?: unknown;
|
|
157
161
|
/**
|
|
158
162
|
* Optional fetch implementation for polyfills in non-standard environments.
|
|
159
163
|
* If using proxy, `node-fetch` is highly recommended.
|
|
160
164
|
*/
|
|
161
165
|
polyfill: typeof fetch;
|
|
162
166
|
imageMetadataGetter?: ImageMetadataGetter;
|
|
167
|
+
/**
|
|
168
|
+
* Thời gian chờ tối đa cho mỗi HTTP request tính bằng mili-giây (mặc định: `30000`ms = 30s, đặt `0` để tắt).
|
|
169
|
+
*/
|
|
170
|
+
requestTimeout?: number;
|
|
163
171
|
};
|
|
164
172
|
declare class CallbacksMap extends Map<string, UploadCallback> {
|
|
173
|
+
private timers;
|
|
165
174
|
/**
|
|
166
175
|
* @param ttl Time to live in milliseconds. Default is 5 minutes.
|
|
167
176
|
*/
|
|
168
177
|
set(key: string, value: UploadCallback, ttl?: number): this;
|
|
178
|
+
delete(key: string): boolean;
|
|
169
179
|
}
|
|
170
180
|
export type ViewerKeyCacheEntry = {
|
|
171
181
|
viewer_key: string;
|
package/dist/context.js
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { ZALO_DEFAULTS, ZALO_PROTOCOL } from "./constants/index.js";
|
|
2
2
|
const _5_MINUTES = ZALO_DEFAULTS.UPLOAD.CALLBACK_TTL_MS;
|
|
3
3
|
class CallbacksMap extends Map {
|
|
4
|
+
timers = new Map();
|
|
4
5
|
/**
|
|
5
6
|
* @param ttl Time to live in milliseconds. Default is 5 minutes.
|
|
6
7
|
*/
|
|
7
8
|
set(key, value, ttl = _5_MINUTES) {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const existing = this.timers.get(key);
|
|
10
|
+
if (existing)
|
|
11
|
+
clearTimeout(existing);
|
|
12
|
+
const timer = setTimeout(() => {
|
|
13
|
+
this.timers.delete(key);
|
|
14
|
+
super.delete(key);
|
|
10
15
|
}, ttl);
|
|
16
|
+
if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function") {
|
|
17
|
+
timer.unref();
|
|
18
|
+
}
|
|
19
|
+
this.timers.set(key, timer);
|
|
11
20
|
return super.set(key, value);
|
|
12
21
|
}
|
|
22
|
+
delete(key) {
|
|
23
|
+
const existing = this.timers.get(key);
|
|
24
|
+
if (existing) {
|
|
25
|
+
clearTimeout(existing);
|
|
26
|
+
this.timers.delete(key);
|
|
27
|
+
}
|
|
28
|
+
return super.delete(key);
|
|
29
|
+
}
|
|
13
30
|
}
|
|
14
31
|
export const createContext = (apiType = ZALO_PROTOCOL.API_TYPE, apiVersion = ZALO_PROTOCOL.API_VERSION) => ({
|
|
15
32
|
API_TYPE: apiType,
|
|
@@ -20,6 +37,7 @@ export const createContext = (apiType = ZALO_PROTOCOL.API_TYPE, apiVersion = ZAL
|
|
|
20
37
|
checkUpdate: ZALO_DEFAULTS.OPTIONS.CHECK_UPDATE,
|
|
21
38
|
logging: ZALO_DEFAULTS.OPTIONS.LOGGING,
|
|
22
39
|
polyfill: global.fetch,
|
|
40
|
+
requestTimeout: 30000,
|
|
23
41
|
},
|
|
24
42
|
secretKey: null,
|
|
25
43
|
});
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export declare const DEFAULT_BIGINT_ID_FIELDS: readonly ["owner_id", "group_id", "uidFrom", "uidTo", "uid", "ownerId", "destId", "srcId", "fromUid", "threadId", "globalMsgId", "global_msg_id", "globalDelMsgId", "msgId", "refMessageId", "cliMsgId", "client_msg_id", "actionId", "lastActionIdOther", "lastActionId", "resetLastActionId", "lastId", "ids", "topicId", "reminderId", "eventId"];
|
|
2
|
+
/**
|
|
3
|
+
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
4
|
+
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
5
|
+
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
6
|
+
*/
|
|
7
|
+
export declare function preParseJsonIds(jsonStr: string, alwaysStringFields?: readonly string[], bigIntSafeFields?: readonly string[]): string;
|
|
1
8
|
export declare function decodeBase64ToBuffer(data: string): Buffer;
|
|
2
9
|
export declare function decodeUnit8Array(data: Uint8Array): string | null;
|
|
3
10
|
export declare function decodeEventData(parsed: Record<string, unknown>, cipherKey?: string): Promise<any>;
|
package/dist/crypto/ws-cipher.js
CHANGED
|
@@ -2,6 +2,68 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import pako from "pako";
|
|
3
3
|
import JSONBig from "json-bigint";
|
|
4
4
|
import { ZaloApiError } from "../Errors/index.js";
|
|
5
|
+
const jsonBigString = JSONBig({ storeAsString: true });
|
|
6
|
+
export const DEFAULT_BIGINT_ID_FIELDS = [
|
|
7
|
+
"owner_id",
|
|
8
|
+
"group_id",
|
|
9
|
+
"uidFrom",
|
|
10
|
+
"uidTo",
|
|
11
|
+
"uid",
|
|
12
|
+
"ownerId",
|
|
13
|
+
"destId",
|
|
14
|
+
"srcId",
|
|
15
|
+
"fromUid",
|
|
16
|
+
"threadId",
|
|
17
|
+
"globalMsgId",
|
|
18
|
+
"global_msg_id",
|
|
19
|
+
"globalDelMsgId",
|
|
20
|
+
"msgId",
|
|
21
|
+
"refMessageId",
|
|
22
|
+
"cliMsgId",
|
|
23
|
+
"client_msg_id",
|
|
24
|
+
"actionId",
|
|
25
|
+
"lastActionIdOther",
|
|
26
|
+
"lastActionId",
|
|
27
|
+
"resetLastActionId",
|
|
28
|
+
"lastId",
|
|
29
|
+
"ids",
|
|
30
|
+
"topicId",
|
|
31
|
+
"reminderId",
|
|
32
|
+
"eventId",
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
36
|
+
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
37
|
+
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
38
|
+
*/
|
|
39
|
+
export function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
|
|
40
|
+
if (!jsonStr || typeof jsonStr !== "string")
|
|
41
|
+
return jsonStr;
|
|
42
|
+
const alwaysSet = new Set(alwaysStringFields);
|
|
43
|
+
const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
|
|
44
|
+
if (allFields.length === 0)
|
|
45
|
+
return jsonStr;
|
|
46
|
+
const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
47
|
+
const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
|
|
48
|
+
return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
|
|
49
|
+
const forceString = alwaysSet.has(key);
|
|
50
|
+
if (rawVal.startsWith("[")) {
|
|
51
|
+
const inner = rawVal.slice(1, -1);
|
|
52
|
+
const parts = inner.split(",").map((part) => {
|
|
53
|
+
const trimmed = part.trim();
|
|
54
|
+
if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
|
|
55
|
+
return `"${trimmed}"`;
|
|
56
|
+
}
|
|
57
|
+
return trimmed;
|
|
58
|
+
});
|
|
59
|
+
return `"${key}"${sep}[${parts.join(",")}]`;
|
|
60
|
+
}
|
|
61
|
+
if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
|
|
62
|
+
return `"${key}"${sep}"${rawVal}"`;
|
|
63
|
+
}
|
|
64
|
+
return fullMatch;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
5
67
|
export function decodeBase64ToBuffer(data) {
|
|
6
68
|
return Buffer.from(data, "base64");
|
|
7
69
|
}
|
|
@@ -23,7 +85,7 @@ export async function decodeEventData(parsed, cipherKey) {
|
|
|
23
85
|
const rawData = parsed.data;
|
|
24
86
|
const encryptType = parsed.encrypt;
|
|
25
87
|
if (encryptType === 0)
|
|
26
|
-
return
|
|
88
|
+
return jsonBigString.parse(preParseJsonIds(rawData));
|
|
27
89
|
const decodedBuffer = decodeBase64ToBuffer(encryptType === 1 ? rawData : decodeURIComponent(rawData));
|
|
28
90
|
let decryptedBuffer = decodedBuffer;
|
|
29
91
|
if (encryptType !== 1) {
|
|
@@ -48,5 +110,5 @@ export async function decodeEventData(parsed, cipherKey) {
|
|
|
48
110
|
const decodedData = decodeUnit8Array(decompressedBuffer);
|
|
49
111
|
if (!decodedData)
|
|
50
112
|
return;
|
|
51
|
-
return
|
|
113
|
+
return jsonBigString.parse(preParseJsonIds(decodedData));
|
|
52
114
|
}
|