@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.
Files changed (184) hide show
  1. package/README.md +99 -21
  2. package/dist/apis/auth/exportSession.d.ts +7 -0
  3. package/dist/apis/auth/exportSession.js +17 -0
  4. package/dist/apis/call/addUserGroupCall.d.ts +11 -0
  5. package/dist/apis/call/addUserGroupCall.js +48 -0
  6. package/dist/apis/call/answerAckVoiceCall.d.ts +5 -0
  7. package/dist/apis/call/answerAckVoiceCall.js +38 -0
  8. package/dist/apis/call/answerGroupCall.d.ts +10 -0
  9. package/dist/apis/call/answerGroupCall.js +45 -0
  10. package/dist/apis/call/answerVoiceCall.d.ts +11 -0
  11. package/dist/apis/call/answerVoiceCall.js +50 -0
  12. package/dist/apis/call/broadcastGroupCallState.d.ts +10 -0
  13. package/dist/apis/call/broadcastGroupCallState.js +45 -0
  14. package/dist/apis/call/cancelGroupCall.d.ts +10 -0
  15. package/dist/apis/call/cancelGroupCall.js +45 -0
  16. package/dist/apis/call/cancelVoiceCall.d.ts +1 -1
  17. package/dist/apis/call/cancelVoiceCall.js +5 -1
  18. package/dist/apis/call/createController.d.ts +7 -0
  19. package/dist/apis/call/createController.js +9 -0
  20. package/dist/apis/call/createRtcSession.d.ts +8 -0
  21. package/dist/apis/call/createRtcSession.js +10 -0
  22. package/dist/apis/call/endGroupCall.d.ts +10 -0
  23. package/dist/apis/call/endGroupCall.js +45 -0
  24. package/dist/apis/call/finishGroupCall.d.ts +12 -0
  25. package/dist/apis/call/finishGroupCall.js +47 -0
  26. package/dist/apis/call/getGroupCallState.d.ts +3 -0
  27. package/dist/apis/call/getGroupCallState.js +38 -0
  28. package/dist/apis/call/holdVoiceCall.d.ts +5 -0
  29. package/dist/apis/call/holdVoiceCall.js +34 -0
  30. package/dist/apis/call/joinGroupCall.d.ts +11 -0
  31. package/dist/apis/call/joinGroupCall.js +46 -0
  32. package/dist/apis/call/logEndVoiceCall.d.ts +8 -0
  33. package/dist/apis/call/logEndVoiceCall.js +46 -0
  34. package/dist/apis/call/notifyGroupCall.d.ts +9 -0
  35. package/dist/apis/call/notifyGroupCall.js +44 -0
  36. package/dist/apis/call/pingGroupCall.d.ts +10 -0
  37. package/dist/apis/call/pingGroupCall.js +45 -0
  38. package/dist/apis/call/requestAudioToVideoCall.d.ts +5 -0
  39. package/dist/apis/call/requestAudioToVideoCall.js +37 -0
  40. package/dist/apis/call/requestGroupCall.d.ts +9 -0
  41. package/dist/apis/call/requestGroupCall.js +46 -0
  42. package/dist/apis/call/requestShareScreenCall.d.ts +5 -0
  43. package/dist/apis/call/requestShareScreenCall.js +37 -0
  44. package/dist/apis/call/requestVoiceCall.d.ts +10 -0
  45. package/dist/apis/call/requestVoiceCall.js +47 -0
  46. package/dist/apis/call/ringRingGroupCall.d.ts +10 -0
  47. package/dist/apis/call/ringRingGroupCall.js +45 -0
  48. package/dist/apis/call/ringRingVoiceCall.d.ts +5 -0
  49. package/dist/apis/call/ringRingVoiceCall.js +38 -0
  50. package/dist/apis/call/sendRequestGroupCall.d.ts +11 -0
  51. package/dist/apis/call/sendRequestGroupCall.js +48 -0
  52. package/dist/apis/call/sendRequestVoiceCall.d.ts +11 -0
  53. package/dist/apis/call/sendRequestVoiceCall.js +51 -0
  54. package/dist/apis/call/sendVoiceCall.d.ts +8 -1
  55. package/dist/apis/call/sendVoiceCall.js +10 -8
  56. package/dist/apis/call/shareScreenGroupCall.d.ts +10 -0
  57. package/dist/apis/call/shareScreenGroupCall.js +45 -0
  58. package/dist/apis/call/unholdVoiceCall.d.ts +5 -0
  59. package/dist/apis/call/unholdVoiceCall.js +34 -0
  60. package/dist/apis/call/updateCallMediaState.d.ts +7 -0
  61. package/dist/apis/call/updateCallMediaState.js +61 -0
  62. package/dist/apis/chat/getDirectMessageStatus.d.ts +14 -0
  63. package/dist/apis/chat/getDirectMessageStatus.js +52 -0
  64. package/dist/apis/chat/getSuggestedConversations.d.ts +5 -0
  65. package/dist/apis/chat/getSuggestedConversations.js +24 -0
  66. package/dist/apis/chat/updatePinConversations.d.ts +24 -0
  67. package/dist/apis/chat/updatePinConversations.js +40 -0
  68. package/dist/apis/friend/getFriendProfilesV2.d.ts +26 -0
  69. package/dist/apis/friend/getFriendProfilesV2.js +38 -0
  70. package/dist/apis/friend/getFriendsActivePCWeb.d.ts +6 -0
  71. package/dist/apis/friend/getFriendsActivePCWeb.js +15 -0
  72. package/dist/apis/friend/verifyFriend.d.ts +11 -0
  73. package/dist/apis/friend/verifyFriend.js +37 -0
  74. package/dist/apis/group/analyseGroup.d.ts +4 -0
  75. package/dist/apis/group/analyseGroup.js +28 -0
  76. package/dist/apis/group/checkQuotaCommunityMember.d.ts +6 -0
  77. package/dist/apis/group/checkQuotaCommunityMember.js +34 -0
  78. package/dist/apis/group/getE2eeGroupList.d.ts +7 -0
  79. package/dist/apis/group/getE2eeGroupList.js +15 -0
  80. package/dist/apis/group/getGroupCloudMessagePath.d.ts +19 -0
  81. package/dist/apis/group/getGroupCloudMessagePath.js +51 -0
  82. package/dist/apis/group/getMultiGroupCloudMessages.d.ts +5 -0
  83. package/dist/apis/group/getMultiGroupCloudMessages.js +29 -0
  84. package/dist/apis/media/getPersonalMedia.d.ts +8 -0
  85. package/dist/apis/media/getPersonalMedia.js +31 -0
  86. package/dist/apis/media/getPersonalMediaPreview.d.ts +3 -0
  87. package/dist/apis/media/getPersonalMediaPreview.js +24 -0
  88. package/dist/apis/media/removePersonalMedia.d.ts +9 -0
  89. package/dist/apis/media/removePersonalMedia.js +28 -0
  90. package/dist/apis.d.ts +126 -0
  91. package/dist/apis.js +210 -0
  92. package/dist/call-engine/ZRTPPacketCodec.d.ts +262 -0
  93. package/dist/call-engine/ZRTPPacketCodec.js +506 -0
  94. package/dist/call-engine/ZaloCallController.d.ts +134 -0
  95. package/dist/call-engine/ZaloCallController.js +638 -0
  96. package/dist/call-engine/ZaloCallTransport.d.ts +83 -0
  97. package/dist/call-engine/ZaloCallTransport.js +233 -0
  98. package/dist/call-engine/ZaloRtcSession.d.ts +609 -0
  99. package/dist/call-engine/ZaloRtcSession.js +2931 -0
  100. package/dist/call-engine/ZaloSrtpSession.d.ts +80 -0
  101. package/dist/call-engine/ZaloSrtpSession.js +278 -0
  102. package/dist/call-engine/index.d.ts +18 -0
  103. package/dist/call-engine/index.js +24 -0
  104. package/dist/cjs/apis/auth/exportSession.cjs +22 -0
  105. package/dist/cjs/apis/call/addUserGroupCall.cjs +53 -0
  106. package/dist/cjs/apis/call/answerAckVoiceCall.cjs +43 -0
  107. package/dist/cjs/apis/call/answerGroupCall.cjs +50 -0
  108. package/dist/cjs/apis/call/answerVoiceCall.cjs +55 -0
  109. package/dist/cjs/apis/call/broadcastGroupCallState.cjs +50 -0
  110. package/dist/cjs/apis/call/cancelGroupCall.cjs +50 -0
  111. package/dist/cjs/apis/call/cancelVoiceCall.cjs +5 -1
  112. package/dist/cjs/apis/call/createController.cjs +14 -0
  113. package/dist/cjs/apis/call/createRtcSession.cjs +15 -0
  114. package/dist/cjs/apis/call/endGroupCall.cjs +50 -0
  115. package/dist/cjs/apis/call/finishGroupCall.cjs +52 -0
  116. package/dist/cjs/apis/call/getGroupCallState.cjs +43 -0
  117. package/dist/cjs/apis/call/holdVoiceCall.cjs +39 -0
  118. package/dist/cjs/apis/call/joinGroupCall.cjs +51 -0
  119. package/dist/cjs/apis/call/logEndVoiceCall.cjs +51 -0
  120. package/dist/cjs/apis/call/notifyGroupCall.cjs +49 -0
  121. package/dist/cjs/apis/call/pingGroupCall.cjs +50 -0
  122. package/dist/cjs/apis/call/requestAudioToVideoCall.cjs +42 -0
  123. package/dist/cjs/apis/call/requestGroupCall.cjs +51 -0
  124. package/dist/cjs/apis/call/requestShareScreenCall.cjs +42 -0
  125. package/dist/cjs/apis/call/requestVoiceCall.cjs +52 -0
  126. package/dist/cjs/apis/call/ringRingGroupCall.cjs +50 -0
  127. package/dist/cjs/apis/call/ringRingVoiceCall.cjs +43 -0
  128. package/dist/cjs/apis/call/sendRequestGroupCall.cjs +53 -0
  129. package/dist/cjs/apis/call/sendRequestVoiceCall.cjs +56 -0
  130. package/dist/cjs/apis/call/sendVoiceCall.cjs +10 -8
  131. package/dist/cjs/apis/call/shareScreenGroupCall.cjs +50 -0
  132. package/dist/cjs/apis/call/unholdVoiceCall.cjs +39 -0
  133. package/dist/cjs/apis/call/updateCallMediaState.cjs +66 -0
  134. package/dist/cjs/apis/chat/getDirectMessageStatus.cjs +58 -0
  135. package/dist/cjs/apis/chat/getSuggestedConversations.cjs +29 -0
  136. package/dist/cjs/apis/chat/updatePinConversations.cjs +45 -0
  137. package/dist/cjs/apis/friend/getFriendProfilesV2.cjs +43 -0
  138. package/dist/cjs/apis/friend/getFriendsActivePCWeb.cjs +20 -0
  139. package/dist/cjs/apis/friend/verifyFriend.cjs +42 -0
  140. package/dist/cjs/apis/group/analyseGroup.cjs +33 -0
  141. package/dist/cjs/apis/group/checkQuotaCommunityMember.cjs +39 -0
  142. package/dist/cjs/apis/group/getE2eeGroupList.cjs +20 -0
  143. package/dist/cjs/apis/group/getGroupChatHistory.cjs +8 -7
  144. package/dist/cjs/apis/group/getGroupCloudMessagePath.cjs +69 -0
  145. package/dist/cjs/apis/group/getGroupHistoryLegacy.cjs +7 -6
  146. package/dist/cjs/apis/group/getGroupMessageStatus.cjs +7 -6
  147. package/dist/cjs/apis/group/getMultiGroupCloudMessages.cjs +34 -0
  148. package/dist/cjs/apis/media/getPersonalMedia.cjs +36 -0
  149. package/dist/cjs/apis/media/getPersonalMediaPreview.cjs +29 -0
  150. package/dist/cjs/apis/media/removePersonalMedia.cjs +33 -0
  151. package/dist/cjs/apis.cjs +210 -0
  152. package/dist/cjs/call-engine/ZRTPPacketCodec.cjs +525 -0
  153. package/dist/cjs/call-engine/ZaloCallController.cjs +643 -0
  154. package/dist/cjs/call-engine/ZaloCallTransport.cjs +239 -0
  155. package/dist/cjs/call-engine/ZaloRtcSession.cjs +2937 -0
  156. package/dist/cjs/call-engine/ZaloSrtpSession.cjs +287 -0
  157. package/dist/cjs/constants/protocol.cjs +1 -1
  158. package/dist/cjs/context.cjs +20 -2
  159. package/dist/cjs/core/zcloud-client.cjs +1 -2
  160. package/dist/cjs/crypto/ws-cipher.cjs +66 -2
  161. package/dist/cjs/index.cjs +63 -6
  162. package/dist/cjs/models/CallEvent.cjs +95 -1
  163. package/dist/cjs/realtime/handlers/control.handler.cjs +17 -3
  164. package/dist/cjs/realtime/listener.cjs +37 -6
  165. package/dist/cjs/update.cjs +10 -1
  166. package/dist/cjs/utils.cjs +21 -68
  167. package/dist/constants/protocol.d.ts +1 -1
  168. package/dist/constants/protocol.js +1 -1
  169. package/dist/context.d.ts +10 -0
  170. package/dist/context.js +20 -2
  171. package/dist/crypto/ws-cipher.d.ts +7 -0
  172. package/dist/crypto/ws-cipher.js +64 -2
  173. package/dist/index.d.ts +47 -4
  174. package/dist/index.js +2 -0
  175. package/dist/models/CallEvent.d.ts +15 -0
  176. package/dist/models/CallEvent.js +95 -1
  177. package/dist/realtime/handlers/control.handler.js +17 -3
  178. package/dist/realtime/listener.d.ts +6 -0
  179. package/dist/realtime/listener.js +37 -6
  180. package/dist/update.js +10 -1
  181. package/dist/utils.d.ts +0 -7
  182. package/dist/utils.js +15 -64
  183. package/index.d.ts +1 -1
  184. package/package.json +16 -5
@@ -0,0 +1,287 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('node:crypto');
4
+ var node_buffer = require('node:buffer');
5
+ var ZaloApiError = require('../Errors/ZaloApiError.cjs');
6
+
7
+ /**
8
+ * Sinh ngẫu nhiên khoá Master Key (16 bytes) + Master Salt (14 bytes) = 30 bytes,
9
+ * mã hoá thành chuỗi Base64 40 ký tự chuẩn `zrtc::SrtpTransport` của Zalo.
10
+ */
11
+ function generateSrtpMasterKeyBase64() {
12
+ return crypto.randomBytes(30).toString("base64");
13
+ }
14
+ /**
15
+ * Đóng gói gói tin chuẩn WebRTC RTP (12-byte header + payload).
16
+ */
17
+ function buildRtpPacket(options) {
18
+ const header = node_buffer.Buffer.allocUnsafe(12);
19
+ header.writeUInt8(0x80, 0); // Version = 2, P = 0, X = 0, CC = 0
20
+ const ptByte = ((options.marker ? 0x80 : 0x00) | ((options.payloadType ?? 112) & 0x7f)) & 0xff;
21
+ header.writeUInt8(ptByte, 1);
22
+ header.writeUInt16BE(options.sequenceNumber & 0xffff, 2);
23
+ header.writeUInt32BE(options.timestamp >>> 0, 4);
24
+ header.writeUInt32BE(options.ssrc >>> 0, 8);
25
+ return node_buffer.Buffer.concat([header, options.payload]);
26
+ }
27
+ /**
28
+ * Phân tích gói tin chuẩn WebRTC RTP (RFC 3550).
29
+ */
30
+ function parseRtpPacket(packet) {
31
+ if (!packet || packet.length < 12) {
32
+ throw new ZaloApiError.ZaloApiError(`Invalid RTP packet length: ${packet?.length ?? 0}`);
33
+ }
34
+ const firstByte = packet.readUInt8(0);
35
+ const secondByte = packet.readUInt8(1);
36
+ const version = (firstByte >> 6) & 0x03;
37
+ const padding = ((firstByte >> 5) & 0x01) === 1;
38
+ const extension = ((firstByte >> 4) & 0x01) === 1;
39
+ const csrcCount = firstByte & 0x0f;
40
+ const marker = ((secondByte >> 7) & 0x01) === 1;
41
+ const payloadType = secondByte & 0x7f;
42
+ const sequenceNumber = packet.readUInt16BE(2);
43
+ const timestamp = packet.readUInt32BE(4);
44
+ const ssrc = packet.readUInt32BE(8);
45
+ let headerLength = 12 + csrcCount * 4;
46
+ if (packet.length < headerLength) {
47
+ throw new ZaloApiError.ZaloApiError("RTP packet shorter than CSRC header length");
48
+ }
49
+ if (extension) {
50
+ if (packet.length < headerLength + 4) {
51
+ throw new ZaloApiError.ZaloApiError("RTP packet shorter than extension header");
52
+ }
53
+ const extLenWords = packet.readUInt16BE(headerLength + 2);
54
+ headerLength += 4 + extLenWords * 4;
55
+ if (packet.length < headerLength) {
56
+ throw new ZaloApiError.ZaloApiError("RTP packet shorter than extension payload");
57
+ }
58
+ }
59
+ let payloadEnd = packet.length;
60
+ if (padding && packet.length > headerLength) {
61
+ const paddingLen = packet.readUInt8(packet.length - 1);
62
+ if (paddingLen > 0 && headerLength + paddingLen <= packet.length) {
63
+ payloadEnd = packet.length - paddingLen;
64
+ }
65
+ }
66
+ return {
67
+ version,
68
+ padding,
69
+ extension,
70
+ csrcCount,
71
+ marker,
72
+ payloadType,
73
+ sequenceNumber,
74
+ timestamp,
75
+ ssrc,
76
+ headerLength,
77
+ header: packet.subarray(0, headerLength),
78
+ payload: packet.subarray(headerLength, payloadEnd),
79
+ };
80
+ }
81
+ /**
82
+ * Thuật toán dẫn xuất khoá phiên SRTP/SRTCP theo RFC 3711 Mục 4.3.1 (AES-CM PRF).
83
+ */
84
+ function deriveSrtpSessionKey(masterKey, masterSalt, label, outByteLength) {
85
+ const iv = node_buffer.Buffer.alloc(16, 0);
86
+ masterSalt.copy(iv, 0, 0, 14);
87
+ // label nằm tại byte thứ 7 (tức (label << 48) trong khối 112-bit salt)
88
+ iv[7] ^= label & 0xff;
89
+ const cipher = crypto.createCipheriv("aes-128-ctr", masterKey, iv);
90
+ const zeroBlock = node_buffer.Buffer.alloc(outByteLength, 0);
91
+ return node_buffer.Buffer.concat([cipher.update(zeroBlock), cipher.final()]).subarray(0, outByteLength);
92
+ }
93
+ function buildSrtpCtrIv(sessionSalt, ssrc, roc, seqNum) {
94
+ const iv = node_buffer.Buffer.alloc(16, 0);
95
+ sessionSalt.copy(iv, 0, 0, 14);
96
+ const ssrcBuf = node_buffer.Buffer.allocUnsafe(4);
97
+ ssrcBuf.writeUInt32BE(ssrc >>> 0, 0);
98
+ for (let i = 0; i < 4; i++) {
99
+ iv[4 + i] ^= ssrcBuf[i];
100
+ }
101
+ const rocBuf = node_buffer.Buffer.allocUnsafe(4);
102
+ rocBuf.writeUInt32BE(roc >>> 0, 0);
103
+ for (let i = 0; i < 4; i++) {
104
+ iv[8 + i] ^= rocBuf[i];
105
+ }
106
+ iv[12] ^= (seqNum >>> 8) & 0xff;
107
+ iv[13] ^= seqNum & 0xff;
108
+ return iv;
109
+ }
110
+ function buildSrtcpCtrIv(sessionSalt, ssrc, srtcpIndex) {
111
+ const iv = node_buffer.Buffer.alloc(16, 0);
112
+ sessionSalt.copy(iv, 0, 0, 14);
113
+ const ssrcBuf = node_buffer.Buffer.allocUnsafe(4);
114
+ ssrcBuf.writeUInt32BE(ssrc >>> 0, 0);
115
+ for (let i = 0; i < 4; i++) {
116
+ iv[4 + i] ^= ssrcBuf[i];
117
+ }
118
+ const idxBuf = node_buffer.Buffer.allocUnsafe(4);
119
+ idxBuf.writeUInt32BE((srtcpIndex & 0x7fffffff) >>> 0, 0);
120
+ for (let i = 0; i < 4; i++) {
121
+ iv[10 + i] ^= idxBuf[i];
122
+ }
123
+ return iv;
124
+ }
125
+ /**
126
+ * Phiên mã hoá / giải mã SRTP & SRTCP thuần Node.js (`node:crypto`)
127
+ * tương thích 100% với `zrtc::SrtpTransport` (`AES_CM_128_HMAC_SHA1_80` / `AES_CM_128_HMAC_SHA1_32`).
128
+ */
129
+ class ZaloSrtpSession {
130
+ masterKey;
131
+ masterSalt;
132
+ masterKeyBase64;
133
+ suite;
134
+ tagLength;
135
+ rtpKey;
136
+ rtpAuthKey;
137
+ rtpSalt;
138
+ rtcpKey;
139
+ rtcpAuthKey;
140
+ rtcpSalt;
141
+ sendRoc = 0;
142
+ recvRoc = 0;
143
+ lastSendSeq = -1;
144
+ lastRecvSeq = -1;
145
+ srtcpIndex = 0;
146
+ constructor(masterKeyInput, suite = "AES_CM_128_HMAC_SHA1_80") {
147
+ const raw = typeof masterKeyInput === "string"
148
+ ? node_buffer.Buffer.from(masterKeyInput, "base64")
149
+ : node_buffer.Buffer.from(masterKeyInput);
150
+ if (raw.length < 30) {
151
+ throw new ZaloApiError.ZaloApiError(`SRTP master key + salt must be at least 30 bytes (got ${raw.length} bytes)`);
152
+ }
153
+ this.masterKey = raw.subarray(0, 16);
154
+ this.masterSalt = raw.subarray(16, 30);
155
+ this.masterKeyBase64 = raw.subarray(0, 30).toString("base64");
156
+ this.suite = suite;
157
+ this.tagLength = suite === "AES_CM_128_HMAC_SHA1_32" ? 4 : 10;
158
+ this.rtpKey = deriveSrtpSessionKey(this.masterKey, this.masterSalt, 0x00, 16);
159
+ this.rtpAuthKey = deriveSrtpSessionKey(this.masterKey, this.masterSalt, 0x01, 20);
160
+ this.rtpSalt = deriveSrtpSessionKey(this.masterKey, this.masterSalt, 0x02, 14);
161
+ this.rtcpKey = deriveSrtpSessionKey(this.masterKey, this.masterSalt, 0x03, 16);
162
+ this.rtcpAuthKey = deriveSrtpSessionKey(this.masterKey, this.masterSalt, 0x04, 20);
163
+ this.rtcpSalt = deriveSrtpSessionKey(this.masterKey, this.masterSalt, 0x05, 14);
164
+ }
165
+ /**
166
+ * Mã hoá gói tin RTP thành SRTP (AES-128-CTR + HMAC-SHA1 tag).
167
+ */
168
+ protectRtp(rtpPacket, explicitRoc) {
169
+ const parsed = parseRtpPacket(rtpPacket);
170
+ let roc = explicitRoc ?? this.sendRoc;
171
+ if (explicitRoc === undefined) {
172
+ if (this.lastSendSeq !== -1 && parsed.sequenceNumber < this.lastSendSeq && this.lastSendSeq - parsed.sequenceNumber > 0x8000) {
173
+ this.sendRoc = (this.sendRoc + 1) >>> 0;
174
+ roc = this.sendRoc;
175
+ }
176
+ this.lastSendSeq = parsed.sequenceNumber;
177
+ }
178
+ const iv = buildSrtpCtrIv(this.rtpSalt, parsed.ssrc, roc, parsed.sequenceNumber);
179
+ const cipher = crypto.createCipheriv("aes-128-ctr", this.rtpKey, iv);
180
+ const encryptedPayload = node_buffer.Buffer.concat([cipher.update(parsed.payload), cipher.final()]);
181
+ const rocBuf = node_buffer.Buffer.allocUnsafe(4);
182
+ rocBuf.writeUInt32BE(roc >>> 0, 0);
183
+ const hmac = crypto.createHmac("sha1", this.rtpAuthKey);
184
+ hmac.update(parsed.header);
185
+ hmac.update(encryptedPayload);
186
+ hmac.update(rocBuf);
187
+ const authTag = hmac.digest().subarray(0, this.tagLength);
188
+ return node_buffer.Buffer.concat([parsed.header, encryptedPayload, authTag]);
189
+ }
190
+ /**
191
+ * Xác thực HMAC-SHA1 và giải mã gói tin SRTP về RTP thuần.
192
+ */
193
+ unprotectRtp(srtpPacket, explicitRoc) {
194
+ if (!srtpPacket || srtpPacket.length < 12 + this.tagLength) {
195
+ throw new ZaloApiError.ZaloApiError(`Invalid SRTP packet length: ${srtpPacket?.length ?? 0}`);
196
+ }
197
+ const rtpPortion = srtpPacket.subarray(0, srtpPacket.length - this.tagLength);
198
+ const receivedTag = srtpPacket.subarray(srtpPacket.length - this.tagLength);
199
+ const parsed = parseRtpPacket(rtpPortion);
200
+ let roc = explicitRoc ?? this.recvRoc;
201
+ if (explicitRoc === undefined && this.lastRecvSeq !== -1) {
202
+ if (parsed.sequenceNumber < this.lastRecvSeq && this.lastRecvSeq - parsed.sequenceNumber > 0x8000) {
203
+ roc = (this.recvRoc + 1) >>> 0;
204
+ }
205
+ }
206
+ const rocBuf = node_buffer.Buffer.allocUnsafe(4);
207
+ rocBuf.writeUInt32BE(roc >>> 0, 0);
208
+ const hmac = crypto.createHmac("sha1", this.rtpAuthKey);
209
+ hmac.update(parsed.header);
210
+ hmac.update(parsed.payload);
211
+ hmac.update(rocBuf);
212
+ const expectedTag = hmac.digest().subarray(0, this.tagLength);
213
+ if (!crypto.timingSafeEqual(receivedTag, expectedTag)) {
214
+ throw new ZaloApiError.ZaloApiError("SRTP authentication tag verification failed");
215
+ }
216
+ if (explicitRoc === undefined) {
217
+ this.recvRoc = roc;
218
+ this.lastRecvSeq = parsed.sequenceNumber;
219
+ }
220
+ const iv = buildSrtpCtrIv(this.rtpSalt, parsed.ssrc, roc, parsed.sequenceNumber);
221
+ const decipher = crypto.createDecipheriv("aes-128-ctr", this.rtpKey, iv);
222
+ const decryptedPayload = node_buffer.Buffer.concat([decipher.update(parsed.payload), decipher.final()]);
223
+ return node_buffer.Buffer.concat([parsed.header, decryptedPayload]);
224
+ }
225
+ /**
226
+ * Mã hoá gói tin RTCP thành SRTCP (RFC 3711 Mục 3.4).
227
+ */
228
+ protectRtcp(rtcpPacket) {
229
+ if (!rtcpPacket || rtcpPacket.length < 8) {
230
+ throw new ZaloApiError.ZaloApiError(`Invalid RTCP packet length: ${rtcpPacket?.length ?? 0}`);
231
+ }
232
+ const header = rtcpPacket.subarray(0, 8);
233
+ const payload = rtcpPacket.subarray(8);
234
+ const ssrc = rtcpPacket.readUInt32BE(4);
235
+ const index = (this.srtcpIndex++ & 0x7fffffff) >>> 0;
236
+ const iv = buildSrtcpCtrIv(this.rtcpSalt, ssrc, index);
237
+ const cipher = crypto.createCipheriv("aes-128-ctr", this.rtcpKey, iv);
238
+ const encryptedPayload = node_buffer.Buffer.concat([cipher.update(payload), cipher.final()]);
239
+ const indexTrailer = node_buffer.Buffer.allocUnsafe(4);
240
+ indexTrailer.writeUInt32BE((0x80000000 | index) >>> 0, 0);
241
+ const hmac = crypto.createHmac("sha1", this.rtcpAuthKey);
242
+ hmac.update(header);
243
+ hmac.update(encryptedPayload);
244
+ hmac.update(indexTrailer);
245
+ const authTag = hmac.digest().subarray(0, this.tagLength);
246
+ return node_buffer.Buffer.concat([header, encryptedPayload, indexTrailer, authTag]);
247
+ }
248
+ /**
249
+ * Xác thực và giải mã gói tin SRTCP về RTCP thuần.
250
+ */
251
+ unprotectRtcp(srtcpPacket) {
252
+ if (!srtcpPacket || srtcpPacket.length < 8 + 4 + this.tagLength) {
253
+ throw new ZaloApiError.ZaloApiError(`Invalid SRTCP packet length: ${srtcpPacket?.length ?? 0}`);
254
+ }
255
+ const tagStart = srtcpPacket.length - this.tagLength;
256
+ const indexStart = tagStart - 4;
257
+ const header = srtcpPacket.subarray(0, 8);
258
+ const encryptedPayload = srtcpPacket.subarray(8, indexStart);
259
+ const indexTrailer = srtcpPacket.subarray(indexStart, tagStart);
260
+ const receivedTag = srtcpPacket.subarray(tagStart);
261
+ const hmac = crypto.createHmac("sha1", this.rtcpAuthKey);
262
+ hmac.update(header);
263
+ hmac.update(encryptedPayload);
264
+ hmac.update(indexTrailer);
265
+ const expectedTag = hmac.digest().subarray(0, this.tagLength);
266
+ if (!crypto.timingSafeEqual(receivedTag, expectedTag)) {
267
+ throw new ZaloApiError.ZaloApiError("SRTCP authentication tag verification failed");
268
+ }
269
+ const eAndIndex = indexTrailer.readUInt32BE(0);
270
+ const isEncrypted = (eAndIndex & 0x80000000) !== 0;
271
+ const index = eAndIndex & 0x7fffffff;
272
+ if (!isEncrypted) {
273
+ return node_buffer.Buffer.concat([header, encryptedPayload]);
274
+ }
275
+ const ssrc = header.readUInt32BE(4);
276
+ const iv = buildSrtcpCtrIv(this.rtcpSalt, ssrc, index);
277
+ const decipher = crypto.createDecipheriv("aes-128-ctr", this.rtcpKey, iv);
278
+ const decryptedPayload = node_buffer.Buffer.concat([decipher.update(encryptedPayload), decipher.final()]);
279
+ return node_buffer.Buffer.concat([header, decryptedPayload]);
280
+ }
281
+ }
282
+
283
+ exports.ZaloSrtpSession = ZaloSrtpSession;
284
+ exports.buildRtpPacket = buildRtpPacket;
285
+ exports.deriveSrtpSessionKey = deriveSrtpSessionKey;
286
+ exports.generateSrtpMasterKeyBase64 = generateSrtpMasterKeyBase64;
287
+ exports.parseRtpPacket = parseRtpPacket;
@@ -12,7 +12,7 @@ const ZALO_PROTOCOL = {
12
12
  API_VERSION: 689,
13
13
  DEFAULT_API_VERSION: 689,
14
14
  /** Phiên bản SDK hiện tại */
15
- SDK_VERSION: "2.3.3",
15
+ SDK_VERSION: "2.3.5",
16
16
  /** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
17
17
  VOICECALL_API_TYPE: 24,
18
18
  /** Phiên bản mã hóa ZCID (ParamDecryptor) */
@@ -5,15 +5,32 @@ var defaults = require('./constants/defaults.cjs');
5
5
 
6
6
  const _5_MINUTES = defaults.ZALO_DEFAULTS.UPLOAD.CALLBACK_TTL_MS;
7
7
  class CallbacksMap extends Map {
8
+ timers = new Map();
8
9
  /**
9
10
  * @param ttl Time to live in milliseconds. Default is 5 minutes.
10
11
  */
11
12
  set(key, value, ttl = _5_MINUTES) {
12
- setTimeout(() => {
13
- this.delete(key);
13
+ const existing = this.timers.get(key);
14
+ if (existing)
15
+ clearTimeout(existing);
16
+ const timer = setTimeout(() => {
17
+ this.timers.delete(key);
18
+ super.delete(key);
14
19
  }, ttl);
20
+ if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function") {
21
+ timer.unref();
22
+ }
23
+ this.timers.set(key, timer);
15
24
  return super.set(key, value);
16
25
  }
26
+ delete(key) {
27
+ const existing = this.timers.get(key);
28
+ if (existing) {
29
+ clearTimeout(existing);
30
+ this.timers.delete(key);
31
+ }
32
+ return super.delete(key);
33
+ }
17
34
  }
18
35
  const createContext = (apiType = protocol.ZALO_PROTOCOL.API_TYPE, apiVersion = protocol.ZALO_PROTOCOL.API_VERSION) => ({
19
36
  API_TYPE: apiType,
@@ -24,6 +41,7 @@ const createContext = (apiType = protocol.ZALO_PROTOCOL.API_TYPE, apiVersion = p
24
41
  checkUpdate: defaults.ZALO_DEFAULTS.OPTIONS.CHECK_UPDATE,
25
42
  logging: defaults.ZALO_DEFAULTS.OPTIONS.LOGGING,
26
43
  polyfill: global.fetch,
44
+ requestTimeout: 30000,
27
45
  },
28
46
  secretKey: null,
29
47
  });
@@ -4,8 +4,7 @@ var ZaloApiError = require('../Errors/ZaloApiError.cjs');
4
4
  require('crypto-js');
5
5
  require('node:crypto');
6
6
  var zcloudCipher = require('../crypto/zcloud-cipher.cjs');
7
- require('pako');
8
- require('json-bigint');
7
+ require('../crypto/ws-cipher.cjs');
9
8
 
10
9
  /**
11
10
  * Thực thi request tới hệ sinh thái ZCloud (`zcld.chat.zalo.me`) kèm cơ chế:
@@ -5,6 +5,68 @@ var pako = require('pako');
5
5
  var JSONBig = require('json-bigint');
6
6
  var ZaloApiError = require('../Errors/ZaloApiError.cjs');
7
7
 
8
+ const jsonBigString = JSONBig({ storeAsString: true });
9
+ const DEFAULT_BIGINT_ID_FIELDS = [
10
+ "owner_id",
11
+ "group_id",
12
+ "uidFrom",
13
+ "uidTo",
14
+ "uid",
15
+ "ownerId",
16
+ "destId",
17
+ "srcId",
18
+ "fromUid",
19
+ "threadId",
20
+ "globalMsgId",
21
+ "global_msg_id",
22
+ "globalDelMsgId",
23
+ "msgId",
24
+ "refMessageId",
25
+ "cliMsgId",
26
+ "client_msg_id",
27
+ "actionId",
28
+ "lastActionIdOther",
29
+ "lastActionId",
30
+ "resetLastActionId",
31
+ "lastId",
32
+ "ids",
33
+ "topicId",
34
+ "reminderId",
35
+ "eventId",
36
+ ];
37
+ /**
38
+ * 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).
39
+ * 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ố
40
+ * 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.
41
+ */
42
+ function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
43
+ if (!jsonStr || typeof jsonStr !== "string")
44
+ return jsonStr;
45
+ const alwaysSet = new Set(alwaysStringFields);
46
+ const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
47
+ if (allFields.length === 0)
48
+ return jsonStr;
49
+ const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
50
+ const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
51
+ return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
52
+ const forceString = alwaysSet.has(key);
53
+ if (rawVal.startsWith("[")) {
54
+ const inner = rawVal.slice(1, -1);
55
+ const parts = inner.split(",").map((part) => {
56
+ const trimmed = part.trim();
57
+ if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
58
+ return `"${trimmed}"`;
59
+ }
60
+ return trimmed;
61
+ });
62
+ return `"${key}"${sep}[${parts.join(",")}]`;
63
+ }
64
+ if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
65
+ return `"${key}"${sep}"${rawVal}"`;
66
+ }
67
+ return fullMatch;
68
+ });
69
+ }
8
70
  function decodeBase64ToBuffer(data) {
9
71
  return Buffer.from(data, "base64");
10
72
  }
@@ -26,7 +88,7 @@ async function decodeEventData(parsed, cipherKey) {
26
88
  const rawData = parsed.data;
27
89
  const encryptType = parsed.encrypt;
28
90
  if (encryptType === 0)
29
- return JSON.parse(rawData);
91
+ return jsonBigString.parse(preParseJsonIds(rawData));
30
92
  const decodedBuffer = decodeBase64ToBuffer(encryptType === 1 ? rawData : decodeURIComponent(rawData));
31
93
  let decryptedBuffer = decodedBuffer;
32
94
  if (encryptType !== 1) {
@@ -51,9 +113,11 @@ async function decodeEventData(parsed, cipherKey) {
51
113
  const decodedData = decodeUnit8Array(decompressedBuffer);
52
114
  if (!decodedData)
53
115
  return;
54
- return JSONBig.parse(decodedData);
116
+ return jsonBigString.parse(preParseJsonIds(decodedData));
55
117
  }
56
118
 
119
+ exports.DEFAULT_BIGINT_ID_FIELDS = DEFAULT_BIGINT_ID_FIELDS;
57
120
  exports.decodeBase64ToBuffer = decodeBase64ToBuffer;
58
121
  exports.decodeEventData = decodeEventData;
59
122
  exports.decodeUnit8Array = decodeUnit8Array;
123
+ exports.preParseJsonIds = preParseJsonIds;
@@ -32,11 +32,9 @@ var zdbCipher = require('./crypto/zdb-cipher.cjs');
32
32
  var wsCipher = require('./crypto/ws-cipher.cjs');
33
33
  var serviceRouter = require('./core/service-router.cjs');
34
34
  var zcloudClient = require('./core/zcloud-client.cjs');
35
- var zalo = require('./zalo.cjs');
36
35
  var types = require('./realtime/types.cjs');
37
- require('events');
38
- require('ws');
39
- var utils = require('./utils.cjs');
36
+ var listener = require('./realtime/listener.cjs');
37
+ var zalo = require('./zalo.cjs');
40
38
  var loginQR = require('./apis/loginQR.cjs');
41
39
  var getFriendRecommendations = require('./apis/friend/getFriendRecommendations.cjs');
42
40
  var reviewPendingMemberRequest = require('./apis/group/reviewPendingMemberRequest.cjs');
@@ -47,6 +45,18 @@ var updateAutoDeleteChat = require('./apis/chat/updateAutoDeleteChat.cjs');
47
45
  var updateLang = require('./apis/auth/updateLang.cjs');
48
46
  var updateSettings = require('./apis/profile/updateSettings.cjs');
49
47
  var sendVoiceCall = require('./apis/call/sendVoiceCall.cjs');
48
+ var ZaloCallController = require('./call-engine/ZaloCallController.cjs');
49
+ var ZaloRtcSession = require('./call-engine/ZaloRtcSession.cjs');
50
+ var ZRTPPacketCodec = require('./call-engine/ZRTPPacketCodec.cjs');
51
+ var ZaloSrtpSession = require('./call-engine/ZaloSrtpSession.cjs');
52
+ var ZaloCallTransport = require('./call-engine/ZaloCallTransport.cjs');
53
+ require('crypto-js');
54
+ require('node:crypto');
55
+ require('node:fs');
56
+ require('node:path');
57
+ require('spark-md5');
58
+ require('tough-cookie');
59
+ require('./context.cjs');
50
60
  var apis = require('./apis.cjs');
51
61
 
52
62
 
@@ -153,19 +163,21 @@ exports.deriveZdbAesKey = zdbCipher.deriveZdbAesKey;
153
163
  exports.generateRSAKeyPair = zdbCipher.generateRSAKeyPair;
154
164
  exports.parseZdbHeader = zdbCipher.parseZdbHeader;
155
165
  exports.rsaDecryptPkcs1Manual = zdbCipher.rsaDecryptPkcs1Manual;
166
+ exports.DEFAULT_BIGINT_ID_FIELDS = wsCipher.DEFAULT_BIGINT_ID_FIELDS;
156
167
  exports.decodeBase64ToBuffer = wsCipher.decodeBase64ToBuffer;
157
168
  exports.decodeEventData = wsCipher.decodeEventData;
158
169
  exports.decodeUnit8Array = wsCipher.decodeUnit8Array;
170
+ exports.preParseJsonIds = wsCipher.preParseJsonIds;
159
171
  exports.getServiceEndpoint = serviceRouter.getServiceEndpoint;
160
172
  exports.getServiceEndpoints = serviceRouter.getServiceEndpoints;
161
173
  exports.requestZCloudDecrypted = zcloudClient.requestZCloudDecrypted;
162
174
  exports.requestZFamilyDecrypted = zcloudClient.requestZFamilyDecrypted;
163
- exports.Zalo = zalo.Zalo;
164
175
  Object.defineProperty(exports, "CloseReason", {
165
176
  enumerable: true,
166
177
  get: function () { return types.CloseReason; }
167
178
  });
168
- exports.preParseJsonIds = utils.preParseJsonIds;
179
+ exports.Listener = listener.Listener;
180
+ exports.Zalo = zalo.Zalo;
169
181
  Object.defineProperty(exports, "LoginQRCallbackEventType", {
170
182
  enumerable: true,
171
183
  get: function () { return loginQR.LoginQRCallbackEventType; }
@@ -214,4 +226,49 @@ Object.defineProperty(exports, "CallType", {
214
226
  enumerable: true,
215
227
  get: function () { return sendVoiceCall.CallType; }
216
228
  });
229
+ exports.ZaloCallController = ZaloCallController.ZaloCallController;
230
+ exports.ZaloRtcSession = ZaloRtcSession.ZaloRtcSession;
231
+ exports.parseIncomingCallEvent = ZaloRtcSession.parseIncomingCallEvent;
232
+ exports.DEFAULT_ZALO_AUDIO_CODEC = ZRTPPacketCodec.DEFAULT_ZALO_AUDIO_CODEC;
233
+ exports.DEFAULT_ZALO_VIDEO_CODEC = ZRTPPacketCodec.DEFAULT_ZALO_VIDEO_CODEC;
234
+ Object.defineProperty(exports, "ZRTCMediaSubCommand", {
235
+ enumerable: true,
236
+ get: function () { return ZRTPPacketCodec.ZRTCMediaSubCommand; }
237
+ });
238
+ Object.defineProperty(exports, "ZRTCRole", {
239
+ enumerable: true,
240
+ get: function () { return ZRTPPacketCodec.ZRTCRole; }
241
+ });
242
+ Object.defineProperty(exports, "ZRTPControlCommand", {
243
+ enumerable: true,
244
+ get: function () { return ZRTPPacketCodec.ZRTPControlCommand; }
245
+ });
246
+ Object.defineProperty(exports, "ZRTPForwardSubCommand", {
247
+ enumerable: true,
248
+ get: function () { return ZRTPPacketCodec.ZRTPForwardSubCommand; }
249
+ });
250
+ Object.defineProperty(exports, "ZRTPLegacyMediaType", {
251
+ enumerable: true,
252
+ get: function () { return ZRTPPacketCodec.ZRTPLegacyMediaType; }
253
+ });
254
+ exports.buildEchoRequest = ZRTPPacketCodec.buildEchoRequest;
255
+ exports.buildEndCallRequest = ZRTPPacketCodec.buildEndCallRequest;
256
+ exports.buildInitCallRequest = ZRTPPacketCodec.buildInitCallRequest;
257
+ exports.buildInitCallResponse = ZRTPPacketCodec.buildInitCallResponse;
258
+ exports.buildPingRequest = ZRTPPacketCodec.buildPingRequest;
259
+ exports.buildPingResponse = ZRTPPacketCodec.buildPingResponse;
260
+ exports.buildRelayPingRequest = ZRTPPacketCodec.buildRelayPingRequest;
261
+ exports.buildRequestForwardPacket = ZRTPPacketCodec.buildRequestForwardPacket;
262
+ exports.buildZrtcExtendData = ZRTPPacketCodec.buildZrtcExtendData;
263
+ exports.parseZRTPPacket = ZRTPPacketCodec.parseZRTPPacket;
264
+ exports.uidToUint32 = ZRTPPacketCodec.uidToUint32;
265
+ exports.wrapLegacyMediaPacket = ZRTPPacketCodec.wrapLegacyMediaPacket;
266
+ exports.wrapZrtcMediaPacket = ZRTPPacketCodec.wrapZrtcMediaPacket;
267
+ exports.ZaloSrtpSession = ZaloSrtpSession.ZaloSrtpSession;
268
+ exports.buildRtpPacket = ZaloSrtpSession.buildRtpPacket;
269
+ exports.deriveSrtpSessionKey = ZaloSrtpSession.deriveSrtpSessionKey;
270
+ exports.generateSrtpMasterKeyBase64 = ZaloSrtpSession.generateSrtpMasterKeyBase64;
271
+ exports.parseRtpPacket = ZaloSrtpSession.parseRtpPacket;
272
+ exports.DEFAULT_ZALOCALL_IPC_KEY_BASE64 = ZaloCallTransport.DEFAULT_ZALOCALL_IPC_KEY_BASE64;
273
+ exports.ZaloCallTransport = ZaloCallTransport.ZaloCallTransport;
217
274
  exports.API = apis.API;