@softtynet/zca-js 2.3.4 → 2.3.6

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 (129) hide show
  1. package/README.md +47 -11
  2. package/dist/apis/call/addUserGroupCall.d.ts +11 -0
  3. package/dist/apis/call/addUserGroupCall.js +48 -0
  4. package/dist/apis/call/answerAckVoiceCall.d.ts +5 -0
  5. package/dist/apis/call/answerAckVoiceCall.js +38 -0
  6. package/dist/apis/call/answerGroupCall.d.ts +10 -0
  7. package/dist/apis/call/answerGroupCall.js +45 -0
  8. package/dist/apis/call/answerVoiceCall.d.ts +11 -0
  9. package/dist/apis/call/answerVoiceCall.js +50 -0
  10. package/dist/apis/call/broadcastGroupCallState.d.ts +10 -0
  11. package/dist/apis/call/broadcastGroupCallState.js +45 -0
  12. package/dist/apis/call/cancelGroupCall.d.ts +10 -0
  13. package/dist/apis/call/cancelGroupCall.js +45 -0
  14. package/dist/apis/call/cancelVoiceCall.d.ts +1 -1
  15. package/dist/apis/call/cancelVoiceCall.js +5 -1
  16. package/dist/apis/call/createController.d.ts +7 -0
  17. package/dist/apis/call/createController.js +9 -0
  18. package/dist/apis/call/createRtcSession.d.ts +8 -0
  19. package/dist/apis/call/createRtcSession.js +10 -0
  20. package/dist/apis/call/endGroupCall.d.ts +10 -0
  21. package/dist/apis/call/endGroupCall.js +45 -0
  22. package/dist/apis/call/finishGroupCall.d.ts +12 -0
  23. package/dist/apis/call/finishGroupCall.js +47 -0
  24. package/dist/apis/call/getGroupCallState.d.ts +3 -0
  25. package/dist/apis/call/getGroupCallState.js +38 -0
  26. package/dist/apis/call/holdVoiceCall.d.ts +5 -0
  27. package/dist/apis/call/holdVoiceCall.js +34 -0
  28. package/dist/apis/call/joinGroupCall.d.ts +11 -0
  29. package/dist/apis/call/joinGroupCall.js +46 -0
  30. package/dist/apis/call/logEndVoiceCall.d.ts +8 -0
  31. package/dist/apis/call/logEndVoiceCall.js +46 -0
  32. package/dist/apis/call/notifyGroupCall.d.ts +9 -0
  33. package/dist/apis/call/notifyGroupCall.js +44 -0
  34. package/dist/apis/call/pingGroupCall.d.ts +10 -0
  35. package/dist/apis/call/pingGroupCall.js +45 -0
  36. package/dist/apis/call/requestAudioToVideoCall.d.ts +5 -0
  37. package/dist/apis/call/requestAudioToVideoCall.js +37 -0
  38. package/dist/apis/call/requestGroupCall.d.ts +9 -0
  39. package/dist/apis/call/requestGroupCall.js +46 -0
  40. package/dist/apis/call/requestShareScreenCall.d.ts +5 -0
  41. package/dist/apis/call/requestShareScreenCall.js +37 -0
  42. package/dist/apis/call/requestVoiceCall.d.ts +10 -0
  43. package/dist/apis/call/requestVoiceCall.js +47 -0
  44. package/dist/apis/call/ringRingGroupCall.d.ts +10 -0
  45. package/dist/apis/call/ringRingGroupCall.js +45 -0
  46. package/dist/apis/call/ringRingVoiceCall.d.ts +5 -0
  47. package/dist/apis/call/ringRingVoiceCall.js +38 -0
  48. package/dist/apis/call/sendRequestGroupCall.d.ts +11 -0
  49. package/dist/apis/call/sendRequestGroupCall.js +48 -0
  50. package/dist/apis/call/sendRequestVoiceCall.d.ts +11 -0
  51. package/dist/apis/call/sendRequestVoiceCall.js +51 -0
  52. package/dist/apis/call/sendVoiceCall.d.ts +8 -1
  53. package/dist/apis/call/sendVoiceCall.js +10 -8
  54. package/dist/apis/call/shareScreenGroupCall.d.ts +10 -0
  55. package/dist/apis/call/shareScreenGroupCall.js +45 -0
  56. package/dist/apis/call/unholdVoiceCall.d.ts +5 -0
  57. package/dist/apis/call/unholdVoiceCall.js +34 -0
  58. package/dist/apis/call/updateCallMediaState.d.ts +7 -0
  59. package/dist/apis/call/updateCallMediaState.js +61 -0
  60. package/dist/apis/sync/downloadTransferSync.js +19 -1
  61. package/dist/apis.d.ts +81 -0
  62. package/dist/apis.js +135 -0
  63. package/dist/call-engine/ZRTPPacketCodec.d.ts +262 -0
  64. package/dist/call-engine/ZRTPPacketCodec.js +506 -0
  65. package/dist/call-engine/ZaloCallController.d.ts +134 -0
  66. package/dist/call-engine/ZaloCallController.js +638 -0
  67. package/dist/call-engine/ZaloCallTransport.d.ts +83 -0
  68. package/dist/call-engine/ZaloCallTransport.js +259 -0
  69. package/dist/call-engine/ZaloRtcSession.d.ts +609 -0
  70. package/dist/call-engine/ZaloRtcSession.js +2939 -0
  71. package/dist/call-engine/ZaloSrtpSession.d.ts +80 -0
  72. package/dist/call-engine/ZaloSrtpSession.js +278 -0
  73. package/dist/call-engine/index.d.ts +18 -0
  74. package/dist/call-engine/index.js +24 -0
  75. package/dist/cjs/apis/call/addUserGroupCall.cjs +53 -0
  76. package/dist/cjs/apis/call/answerAckVoiceCall.cjs +43 -0
  77. package/dist/cjs/apis/call/answerGroupCall.cjs +50 -0
  78. package/dist/cjs/apis/call/answerVoiceCall.cjs +55 -0
  79. package/dist/cjs/apis/call/broadcastGroupCallState.cjs +50 -0
  80. package/dist/cjs/apis/call/cancelGroupCall.cjs +50 -0
  81. package/dist/cjs/apis/call/cancelVoiceCall.cjs +5 -1
  82. package/dist/cjs/apis/call/createController.cjs +14 -0
  83. package/dist/cjs/apis/call/createRtcSession.cjs +15 -0
  84. package/dist/cjs/apis/call/endGroupCall.cjs +50 -0
  85. package/dist/cjs/apis/call/finishGroupCall.cjs +52 -0
  86. package/dist/cjs/apis/call/getGroupCallState.cjs +43 -0
  87. package/dist/cjs/apis/call/holdVoiceCall.cjs +39 -0
  88. package/dist/cjs/apis/call/joinGroupCall.cjs +51 -0
  89. package/dist/cjs/apis/call/logEndVoiceCall.cjs +51 -0
  90. package/dist/cjs/apis/call/notifyGroupCall.cjs +49 -0
  91. package/dist/cjs/apis/call/pingGroupCall.cjs +50 -0
  92. package/dist/cjs/apis/call/requestAudioToVideoCall.cjs +42 -0
  93. package/dist/cjs/apis/call/requestGroupCall.cjs +51 -0
  94. package/dist/cjs/apis/call/requestShareScreenCall.cjs +42 -0
  95. package/dist/cjs/apis/call/requestVoiceCall.cjs +52 -0
  96. package/dist/cjs/apis/call/ringRingGroupCall.cjs +50 -0
  97. package/dist/cjs/apis/call/ringRingVoiceCall.cjs +43 -0
  98. package/dist/cjs/apis/call/sendRequestGroupCall.cjs +53 -0
  99. package/dist/cjs/apis/call/sendRequestVoiceCall.cjs +56 -0
  100. package/dist/cjs/apis/call/sendVoiceCall.cjs +10 -8
  101. package/dist/cjs/apis/call/shareScreenGroupCall.cjs +50 -0
  102. package/dist/cjs/apis/call/unholdVoiceCall.cjs +39 -0
  103. package/dist/cjs/apis/call/updateCallMediaState.cjs +66 -0
  104. package/dist/cjs/apis/sync/downloadTransferSync.cjs +19 -1
  105. package/dist/cjs/apis.cjs +135 -0
  106. package/dist/cjs/call-engine/ZRTPPacketCodec.cjs +525 -0
  107. package/dist/cjs/call-engine/ZaloCallController.cjs +643 -0
  108. package/dist/cjs/call-engine/ZaloCallTransport.cjs +265 -0
  109. package/dist/cjs/call-engine/ZaloRtcSession.cjs +2945 -0
  110. package/dist/cjs/call-engine/ZaloSrtpSession.cjs +287 -0
  111. package/dist/cjs/constants/protocol.cjs +1 -1
  112. package/dist/cjs/crypto/aes.cjs +3 -1
  113. package/dist/cjs/crypto/zdb-cipher.cjs +10 -3
  114. package/dist/cjs/index.cjs +61 -11
  115. package/dist/cjs/models/CallEvent.cjs +95 -1
  116. package/dist/cjs/realtime/handlers/control.handler.cjs +17 -3
  117. package/dist/cjs/realtime/listener.cjs +19 -0
  118. package/dist/constants/protocol.d.ts +1 -1
  119. package/dist/constants/protocol.js +1 -1
  120. package/dist/crypto/aes.js +3 -1
  121. package/dist/crypto/zdb-cipher.js +10 -3
  122. package/dist/index.d.ts +32 -4
  123. package/dist/index.js +2 -0
  124. package/dist/models/CallEvent.d.ts +15 -0
  125. package/dist/models/CallEvent.js +95 -1
  126. package/dist/realtime/handlers/control.handler.js +17 -3
  127. package/dist/realtime/listener.d.ts +5 -0
  128. package/dist/realtime/listener.js +19 -0
  129. package/package.json +2 -1
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('node:crypto');
4
+ var EventEmitter = require('node:events');
5
+ var fs = require('node:fs');
6
+ var net = require('node:net');
7
+ var node_buffer = require('node:buffer');
8
+
9
+ /**
10
+ * Khoá AES-128-CBC tĩnh chuẩn trong module `4KIH` của Zalo PC và binary `ZaloCall` (`yjAF9oqMWl6XfXYJn9mA7w==`).
11
+ */
12
+ const DEFAULT_ZALOCALL_IPC_KEY_BASE64 = "yjAF9oqMWl6XfXYJn9mA7w==";
13
+ const MAX_IPC_CHUNK_LENGTH = 4000;
14
+ const MAX_IPC_RECEIVE_BUFFER_LENGTH = 4 * 1024 * 1024;
15
+ /**
16
+ * Tầng giao thức IPC双kênh (`receiveSocketPath` & `sendSocketPath`) mã hoá AES-128-CBC (Hex + `$` framing + 4000-char chunking)
17
+ * khớp 100% với module `3Zc2` / `4KIH` của Zalo PC và `zrtc_call::ZIpcClientMac` (`0x10012eb50`).
18
+ */
19
+ class ZaloCallTransport extends EventEmitter {
20
+ socketId;
21
+ sendSocketPath;
22
+ receiveSocketPath;
23
+ keyBase64;
24
+ keyBuffer;
25
+ ivBuffer;
26
+ ackTimeoutMs;
27
+ sendServer = null;
28
+ receiveServer = null;
29
+ sendClient = null;
30
+ receiveClient = null;
31
+ receiveBuffer = "";
32
+ outgoingQueue = [];
33
+ waitingForAck = false;
34
+ ackTimer = null;
35
+ emittedConnected = false;
36
+ constructor(options = {}) {
37
+ super();
38
+ this.socketId = options.socketId ?? `${process.pid}_${Math.floor(Math.random() * 10000)}`;
39
+ this.keyBase64 = options.keyBase64 ?? DEFAULT_ZALOCALL_IPC_KEY_BASE64;
40
+ this.ackTimeoutMs = options.ackTimeoutMs ?? 250;
41
+ const decodedKey = node_buffer.Buffer.from(this.keyBase64, "base64");
42
+ this.keyBuffer = node_buffer.Buffer.alloc(16, 0);
43
+ decodedKey.copy(this.keyBuffer, 0, 0, Math.min(16, decodedKey.length));
44
+ this.ivBuffer = node_buffer.Buffer.alloc(16, 0);
45
+ if (process.platform === "win32") {
46
+ this.receiveSocketPath = `\\\\.\\pipe\\receive_socket_${this.socketId}`;
47
+ this.sendSocketPath = `\\\\.\\pipe\\send_socket_${this.socketId}`;
48
+ }
49
+ else {
50
+ this.receiveSocketPath = `/tmp/zcall_r_${this.socketId}`;
51
+ this.sendSocketPath = `/tmp/zcall_s_${this.socketId}`;
52
+ }
53
+ }
54
+ /**
55
+ * Mã hoá đối tượng JSON thành mảng các mảnh Hex (tối đa 4000 ký tự/mảnh, mảnh cuối kết thúc bằng `$`).
56
+ */
57
+ encryptFrames(payload) {
58
+ const json = typeof payload === "string" ? payload : JSON.stringify(payload);
59
+ const cipher = crypto.createCipheriv("aes-128-cbc", this.keyBuffer, this.ivBuffer);
60
+ const encryptedHex = cipher.update(json, "utf-8", "hex") + cipher.final("hex");
61
+ const chunks = [];
62
+ let offset = 0;
63
+ while (offset < encryptedHex.length) {
64
+ chunks.push(encryptedHex.slice(offset, offset + MAX_IPC_CHUNK_LENGTH));
65
+ offset += MAX_IPC_CHUNK_LENGTH;
66
+ }
67
+ if (chunks.length === 0) {
68
+ chunks.push("$");
69
+ }
70
+ else {
71
+ chunks[chunks.length - 1] += "$";
72
+ }
73
+ return chunks;
74
+ }
75
+ /**
76
+ * Giải mã một khung chuỗi Hex (không bao gồm ký tự `$`) thành đối tượng JSON.
77
+ */
78
+ decryptFrame(encryptedHex) {
79
+ const clean = encryptedHex.endsWith("$") ? encryptedHex.slice(0, -1) : encryptedHex;
80
+ const decipher = crypto.createDecipheriv("aes-128-cbc", this.keyBuffer, this.ivBuffer);
81
+ const plain = decipher.update(clean, "hex", "utf-8") + decipher.final("utf-8");
82
+ return JSON.parse(plain);
83
+ }
84
+ /**
85
+ * Khởi tạo 2 máy chủ IPC (`receiveSocketPath` và `sendSocketPath`) sẵn sàng đón tiến trình `ZaloCall`.
86
+ */
87
+ async start() {
88
+ this.unlinkUnixSockets();
89
+ this.emittedConnected = false;
90
+ this.sendServer = net.createServer((socket) => {
91
+ this.sendClient = socket;
92
+ socket.on("data", (chunk) => {
93
+ const text = chunk.toString("utf-8");
94
+ if (text.includes("ack")) {
95
+ this.emit("raw_ack");
96
+ this.onAckReceived();
97
+ }
98
+ });
99
+ socket.on("error", (err) => this.emit("error", err));
100
+ this.checkBothConnected();
101
+ this.flushOutgoingQueue();
102
+ });
103
+ this.receiveServer = net.createServer((socket) => {
104
+ this.receiveClient = socket;
105
+ socket.on("data", (chunk) => {
106
+ this.handleReceiveChunk(chunk.toString("utf-8"));
107
+ });
108
+ socket.on("error", (err) => this.emit("error", err));
109
+ this.checkBothConnected();
110
+ });
111
+ await Promise.all([
112
+ new Promise((resolve, reject) => {
113
+ this.receiveServer.once("error", reject);
114
+ this.receiveServer.listen(this.receiveSocketPath, () => {
115
+ if (process.platform !== "win32") {
116
+ try {
117
+ fs.chmodSync(this.receiveSocketPath, 0o600);
118
+ }
119
+ catch {
120
+ // Ignore chmod error if unsupported
121
+ }
122
+ }
123
+ resolve();
124
+ });
125
+ }),
126
+ new Promise((resolve, reject) => {
127
+ this.sendServer.once("error", reject);
128
+ this.sendServer.listen(this.sendSocketPath, () => {
129
+ if (process.platform !== "win32") {
130
+ try {
131
+ fs.chmodSync(this.sendSocketPath, 0o600);
132
+ }
133
+ catch {
134
+ // Ignore chmod error if unsupported
135
+ }
136
+ }
137
+ resolve();
138
+ });
139
+ }),
140
+ ]);
141
+ this.emit("ready");
142
+ }
143
+ /**
144
+ * Gửi một thông điệp IPC đã mã hoá AES-128-CBC xuống tiến trình `ZaloCall` (qua hàng đợi `"ack"`).
145
+ */
146
+ send(message) {
147
+ const frames = this.encryptFrames(message);
148
+ this.outgoingQueue.push(...frames);
149
+ this.flushOutgoingQueue();
150
+ }
151
+ isConnected() {
152
+ return Boolean(this.sendClient &&
153
+ !this.sendClient.destroyed &&
154
+ this.receiveClient &&
155
+ !this.receiveClient.destroyed);
156
+ }
157
+ /**
158
+ * Đóng toàn bộ kết nối và dọn dẹp file socket trên đĩa.
159
+ */
160
+ async close() {
161
+ if (this.ackTimer) {
162
+ clearTimeout(this.ackTimer);
163
+ this.ackTimer = null;
164
+ }
165
+ this.outgoingQueue = [];
166
+ this.waitingForAck = false;
167
+ this.emittedConnected = false;
168
+ if (this.sendClient) {
169
+ this.sendClient.destroy();
170
+ this.sendClient = null;
171
+ }
172
+ if (this.receiveClient) {
173
+ this.receiveClient.destroy();
174
+ this.receiveClient = null;
175
+ }
176
+ await Promise.all([
177
+ new Promise((resolve) => {
178
+ if (this.sendServer)
179
+ this.sendServer.close(() => resolve());
180
+ else
181
+ resolve();
182
+ }),
183
+ new Promise((resolve) => {
184
+ if (this.receiveServer)
185
+ this.receiveServer.close(() => resolve());
186
+ else
187
+ resolve();
188
+ }),
189
+ ]);
190
+ this.sendServer = null;
191
+ this.receiveServer = null;
192
+ this.unlinkUnixSockets();
193
+ this.emit("close");
194
+ }
195
+ checkBothConnected() {
196
+ if (this.isConnected() && !this.emittedConnected) {
197
+ this.emittedConnected = true;
198
+ this.emit("client_connected");
199
+ }
200
+ }
201
+ onAckReceived() {
202
+ if (this.ackTimer) {
203
+ clearTimeout(this.ackTimer);
204
+ this.ackTimer = null;
205
+ }
206
+ this.waitingForAck = false;
207
+ this.flushOutgoingQueue();
208
+ }
209
+ flushOutgoingQueue() {
210
+ if (this.waitingForAck || !this.sendClient || this.sendClient.destroyed) {
211
+ return;
212
+ }
213
+ const nextFrame = this.outgoingQueue.shift();
214
+ if (!nextFrame)
215
+ return;
216
+ this.waitingForAck = true;
217
+ this.sendClient.write(nextFrame, "utf-8");
218
+ this.ackTimer = setTimeout(() => {
219
+ this.waitingForAck = false;
220
+ this.flushOutgoingQueue();
221
+ }, this.ackTimeoutMs);
222
+ if (typeof this.ackTimer.unref === "function") {
223
+ this.ackTimer.unref();
224
+ }
225
+ }
226
+ handleReceiveChunk(chunk) {
227
+ if (this.receiveBuffer.length + chunk.length > MAX_IPC_RECEIVE_BUFFER_LENGTH) {
228
+ this.receiveBuffer = "";
229
+ this.emit("error", new Error("IPC receive buffer exceeded maximum allowed size (4MB)"));
230
+ return;
231
+ }
232
+ this.receiveBuffer += chunk;
233
+ let dollarIdx = this.receiveBuffer.indexOf("$");
234
+ while (dollarIdx !== -1) {
235
+ const frame = this.receiveBuffer.slice(0, dollarIdx);
236
+ this.receiveBuffer = this.receiveBuffer.slice(dollarIdx + 1);
237
+ if (frame.length > 0) {
238
+ try {
239
+ const parsed = this.decryptFrame(frame);
240
+ this.emit("message", parsed);
241
+ }
242
+ catch (err) {
243
+ this.emit("error", err);
244
+ }
245
+ }
246
+ dollarIdx = this.receiveBuffer.indexOf("$");
247
+ }
248
+ }
249
+ unlinkUnixSockets() {
250
+ if (process.platform === "win32")
251
+ return;
252
+ for (const p of [this.sendSocketPath, this.receiveSocketPath]) {
253
+ try {
254
+ if (fs.existsSync(p))
255
+ fs.unlinkSync(p);
256
+ }
257
+ catch {
258
+ // Ignore unlink errors
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ exports.DEFAULT_ZALOCALL_IPC_KEY_BASE64 = DEFAULT_ZALOCALL_IPC_KEY_BASE64;
265
+ exports.ZaloCallTransport = ZaloCallTransport;