@softtynet/zca-js 2.2.3 → 2.2.4

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.
@@ -20,9 +20,8 @@ export const cancelVoiceCallFactory = apiFactory()((api, ctx, utils) => {
20
20
  throw new ZaloApiError("Missing callId");
21
21
  if (!voiceCallService)
22
22
  throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
23
- const numericCalleeId = Number.isNaN(Number(calleeId)) ? calleeId : Number(calleeId);
24
23
  const params = {
25
- callerId: numericCalleeId,
24
+ callerId: String(calleeId),
26
25
  callId,
27
26
  callType: (_a = options.callType) !== null && _a !== void 0 ? _a : CallType.Audio,
28
27
  status: (_b = options.status) !== null && _b !== void 0 ? _b : 0,
@@ -1,4 +1,5 @@
1
1
  export type DecryptGidsResponse = {
2
+ data?: Record<string, string>;
2
3
  gids?: Record<string, string>;
3
4
  [key: string]: unknown;
4
5
  };
@@ -19,9 +19,8 @@ export const endVoiceCallFactory = apiFactory()((api, ctx, utils) => {
19
19
  throw new ZaloApiError("Missing callId");
20
20
  if (!voiceCallService)
21
21
  throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
22
- const numericCalleeId = Number.isNaN(Number(calleeId)) ? calleeId : Number(calleeId);
23
22
  const params = {
24
- uidTo: numericCalleeId,
23
+ uidTo: String(calleeId),
25
24
  callId,
26
25
  status: (_a = options.status) !== null && _a !== void 0 ? _a : 3,
27
26
  imei: ctx.imei,
@@ -7,10 +7,24 @@ export type SendVoiceCallOptions = {
7
7
  callId?: number;
8
8
  codec?: string;
9
9
  };
10
+ export type RequestCallServerEntry = {
11
+ rtpaddr?: string;
12
+ rtcpaddr?: string;
13
+ rtpIPv6?: string;
14
+ rtcpIPv6?: string;
15
+ spTcp?: number;
16
+ bonus?: number;
17
+ [key: string]: unknown;
18
+ };
10
19
  export type RequestCallServerInfo = {
11
20
  sessId: string;
12
- rtpServer: string;
13
- rtcpServer: string;
21
+ rtpServer?: string;
22
+ rtcpServer?: string;
23
+ rtpIP?: string;
24
+ rtcpIP?: string;
25
+ rtpIPv6?: string;
26
+ rtcpIPv6?: string;
27
+ servers?: RequestCallServerEntry[];
14
28
  zrtpKey?: string;
15
29
  expiredTime?: number;
16
30
  codec?: string;
@@ -24,6 +38,7 @@ export type SendVoiceCallResponse = {
24
38
  zrtpKey?: string;
25
39
  expiredTime?: number;
26
40
  codec?: string;
41
+ serverInfo?: RequestCallServerInfo;
27
42
  requestResult?: unknown;
28
43
  };
29
44
  export declare const sendVoiceCallFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (calleeId: string, options?: SendVoiceCallOptions) => Promise<SendVoiceCallResponse>;
@@ -27,7 +27,7 @@ export const sendVoiceCallFactory = apiFactory()((api, ctx, utils) => {
27
27
  * @throws {ZaloApiError}
28
28
  */
29
29
  return async function sendVoiceCall(calleeId, options = {}) {
30
- var _a, _b, _c, _d, _e, _f, _g;
30
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
31
31
  if (!calleeId)
32
32
  throw new ZaloApiError("Missing calleeId");
33
33
  if (!voiceCallService)
@@ -35,10 +35,10 @@ export const sendVoiceCallFactory = apiFactory()((api, ctx, utils) => {
35
35
  const callType = (_a = options.callType) !== null && _a !== void 0 ? _a : CallType.Audio;
36
36
  const callId = (_b = options.callId) !== null && _b !== void 0 ? _b : Math.floor(Math.random() * 2000000000);
37
37
  const codec = (_c = options.codec) !== null && _c !== void 0 ? _c : "[]";
38
- const numericCalleeId = Number.isNaN(Number(calleeId)) ? calleeId : Number(calleeId);
38
+ const normalizedCalleeId = String(calleeId);
39
39
  // Step 1: Allocate call session & RTP/RTCP relay endpoints (/api/voicecall/requestcall, command 11300)
40
40
  const step1Params = {
41
- calleeId: numericCalleeId,
41
+ calleeId: normalizedCalleeId,
42
42
  callId,
43
43
  codec,
44
44
  typeRequest: callType,
@@ -58,10 +58,12 @@ export const sendVoiceCallFactory = apiFactory()((api, ctx, utils) => {
58
58
  const raw = result.data;
59
59
  return typeof raw === "string" ? JSON.parse(raw) : raw;
60
60
  });
61
- const rtp = parseServerEndpoint(serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpServer);
62
- const rtcp = parseServerEndpoint(serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpServer);
63
- const sessId = (_d = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.sessId) !== null && _d !== void 0 ? _d : `${numericCalleeId}_${callId}_401`;
64
- const resolvedCodec = (_e = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.codec) !== null && _e !== void 0 ? _e : codec;
61
+ const resolvedRtpServer = (_h = (_e = (_d = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpServer) !== null && _d !== void 0 ? _d : serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpIP) !== null && _e !== void 0 ? _e : (_g = (_f = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.servers) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.rtpaddr) !== null && _h !== void 0 ? _h : "";
62
+ const resolvedRtcpServer = (_o = (_k = (_j = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpServer) !== null && _j !== void 0 ? _j : serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpIP) !== null && _k !== void 0 ? _k : (_m = (_l = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.servers) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.rtcpaddr) !== null && _o !== void 0 ? _o : "";
63
+ const rtp = parseServerEndpoint(resolvedRtpServer);
64
+ const rtcp = parseServerEndpoint(resolvedRtcpServer);
65
+ const sessId = (_p = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.sessId) !== null && _p !== void 0 ? _p : `${normalizedCalleeId}_${callId}_401`;
66
+ const resolvedCodec = (_q = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.codec) !== null && _q !== void 0 ? _q : codec;
65
67
  // Step 2: Send ringing signaling request (/api/voicecall/request, command 11301)
66
68
  const extendData = JSON.stringify({
67
69
  rtcpDiff: 0,
@@ -70,7 +72,7 @@ export const sendVoiceCallFactory = apiFactory()((api, ctx, utils) => {
70
72
  status: 0,
71
73
  });
72
74
  const step2Params = {
73
- calleeId: numericCalleeId,
75
+ calleeId: normalizedCalleeId,
74
76
  rtcpAddress: rtcp.host,
75
77
  rtpAddress: rtp.host,
76
78
  codec: resolvedCodec,
@@ -94,11 +96,12 @@ export const sendVoiceCallFactory = apiFactory()((api, ctx, utils) => {
94
96
  return {
95
97
  callId,
96
98
  sessId,
97
- rtpServer: (_f = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpServer) !== null && _f !== void 0 ? _f : "",
98
- rtcpServer: (_g = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpServer) !== null && _g !== void 0 ? _g : "",
99
+ rtpServer: resolvedRtpServer,
100
+ rtcpServer: resolvedRtcpServer,
99
101
  zrtpKey: serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.zrtpKey,
100
102
  expiredTime: serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.expiredTime,
101
103
  codec: resolvedCodec,
104
+ serverInfo,
102
105
  requestResult,
103
106
  };
104
107
  };
@@ -23,9 +23,8 @@ const cancelVoiceCallFactory = utils.apiFactory()((api, ctx, utils) => {
23
23
  throw new ZaloApiError.ZaloApiError("Missing callId");
24
24
  if (!voiceCallService)
25
25
  throw new ZaloApiError.ZaloApiError("Missing voice_call service URL in zpwServiceMap");
26
- const numericCalleeId = Number.isNaN(Number(calleeId)) ? calleeId : Number(calleeId);
27
26
  const params = {
28
- callerId: numericCalleeId,
27
+ callerId: String(calleeId),
29
28
  callId,
30
29
  callType: (_a = options.callType) !== null && _a !== void 0 ? _a : sendVoiceCall.CallType.Audio,
31
30
  status: (_b = options.status) !== null && _b !== void 0 ? _b : 0,
@@ -22,9 +22,8 @@ const endVoiceCallFactory = utils.apiFactory()((api, ctx, utils) => {
22
22
  throw new ZaloApiError.ZaloApiError("Missing callId");
23
23
  if (!voiceCallService)
24
24
  throw new ZaloApiError.ZaloApiError("Missing voice_call service URL in zpwServiceMap");
25
- const numericCalleeId = Number.isNaN(Number(calleeId)) ? calleeId : Number(calleeId);
26
25
  const params = {
27
- uidTo: numericCalleeId,
26
+ uidTo: String(calleeId),
28
27
  callId,
29
28
  status: (_a = options.status) !== null && _a !== void 0 ? _a : 3,
30
29
  imei: ctx.imei,
@@ -30,7 +30,7 @@ const sendVoiceCallFactory = utils.apiFactory()((api, ctx, utils$1) => {
30
30
  * @throws {ZaloApiError}
31
31
  */
32
32
  return async function sendVoiceCall(calleeId, options = {}) {
33
- var _a, _b, _c, _d, _e, _f, _g;
33
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
34
34
  if (!calleeId)
35
35
  throw new ZaloApiError.ZaloApiError("Missing calleeId");
36
36
  if (!voiceCallService)
@@ -38,10 +38,10 @@ const sendVoiceCallFactory = utils.apiFactory()((api, ctx, utils$1) => {
38
38
  const callType = (_a = options.callType) !== null && _a !== void 0 ? _a : exports.CallType.Audio;
39
39
  const callId = (_b = options.callId) !== null && _b !== void 0 ? _b : Math.floor(Math.random() * 2000000000);
40
40
  const codec = (_c = options.codec) !== null && _c !== void 0 ? _c : "[]";
41
- const numericCalleeId = Number.isNaN(Number(calleeId)) ? calleeId : Number(calleeId);
41
+ const normalizedCalleeId = String(calleeId);
42
42
  // Step 1: Allocate call session & RTP/RTCP relay endpoints (/api/voicecall/requestcall, command 11300)
43
43
  const step1Params = {
44
- calleeId: numericCalleeId,
44
+ calleeId: normalizedCalleeId,
45
45
  callId,
46
46
  codec,
47
47
  typeRequest: callType,
@@ -61,10 +61,12 @@ const sendVoiceCallFactory = utils.apiFactory()((api, ctx, utils$1) => {
61
61
  const raw = result.data;
62
62
  return typeof raw === "string" ? JSON.parse(raw) : raw;
63
63
  });
64
- const rtp = parseServerEndpoint(serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpServer);
65
- const rtcp = parseServerEndpoint(serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpServer);
66
- const sessId = (_d = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.sessId) !== null && _d !== void 0 ? _d : `${numericCalleeId}_${callId}_401`;
67
- const resolvedCodec = (_e = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.codec) !== null && _e !== void 0 ? _e : codec;
64
+ const resolvedRtpServer = (_h = (_e = (_d = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpServer) !== null && _d !== void 0 ? _d : serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpIP) !== null && _e !== void 0 ? _e : (_g = (_f = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.servers) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.rtpaddr) !== null && _h !== void 0 ? _h : "";
65
+ const resolvedRtcpServer = (_o = (_k = (_j = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpServer) !== null && _j !== void 0 ? _j : serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpIP) !== null && _k !== void 0 ? _k : (_m = (_l = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.servers) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.rtcpaddr) !== null && _o !== void 0 ? _o : "";
66
+ const rtp = parseServerEndpoint(resolvedRtpServer);
67
+ const rtcp = parseServerEndpoint(resolvedRtcpServer);
68
+ const sessId = (_p = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.sessId) !== null && _p !== void 0 ? _p : `${normalizedCalleeId}_${callId}_401`;
69
+ const resolvedCodec = (_q = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.codec) !== null && _q !== void 0 ? _q : codec;
68
70
  // Step 2: Send ringing signaling request (/api/voicecall/request, command 11301)
69
71
  const extendData = JSON.stringify({
70
72
  rtcpDiff: 0,
@@ -73,7 +75,7 @@ const sendVoiceCallFactory = utils.apiFactory()((api, ctx, utils$1) => {
73
75
  status: 0,
74
76
  });
75
77
  const step2Params = {
76
- calleeId: numericCalleeId,
78
+ calleeId: normalizedCalleeId,
77
79
  rtcpAddress: rtcp.host,
78
80
  rtpAddress: rtp.host,
79
81
  codec: resolvedCodec,
@@ -97,11 +99,12 @@ const sendVoiceCallFactory = utils.apiFactory()((api, ctx, utils$1) => {
97
99
  return {
98
100
  callId,
99
101
  sessId,
100
- rtpServer: (_f = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtpServer) !== null && _f !== void 0 ? _f : "",
101
- rtcpServer: (_g = serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.rtcpServer) !== null && _g !== void 0 ? _g : "",
102
+ rtpServer: resolvedRtpServer,
103
+ rtcpServer: resolvedRtcpServer,
102
104
  zrtpKey: serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.zrtpKey,
103
105
  expiredTime: serverInfo === null || serverInfo === void 0 ? void 0 : serverInfo.expiredTime,
104
106
  codec: resolvedCodec,
107
+ serverInfo,
105
108
  requestResult,
106
109
  };
107
110
  };
@@ -180,4 +180,5 @@ exports.decryptWithPrivateKey = utils.decryptWithPrivateKey;
180
180
  exports.decryptZdbBuffer = utils.decryptZdbBuffer;
181
181
  exports.deriveZdbAesKey = utils.deriveZdbAesKey;
182
182
  exports.generateRSAKeyPair = utils.generateRSAKeyPair;
183
+ exports.parseZdbHeader = utils.parseZdbHeader;
183
184
  exports.API = apis.API;
@@ -901,6 +901,36 @@ function decryptZdbBuffer(zdbBuffer, aesKey) {
901
901
  }
902
902
  throw new ZaloApiError.ZaloApiError("Invalid AES key or buffer is not in ZDB4.0 format");
903
903
  }
904
+ /**
905
+ * Parses the Table of Contents (TOC) from a decrypted ZDB4.0 container buffer,
906
+ * returning the list of SQLite `.db` files (`<uid>.db` / `group_<gid>.db`) and the byte offset where the XZ stream starts.
907
+ */
908
+ function parseZdbHeader(zdbPlaintext) {
909
+ const ZDB_MAGIC = Buffer.from("ZDB4.0", "ascii");
910
+ const COUNT_OFFSET = 14;
911
+ if (zdbPlaintext.length < COUNT_OFFSET + 4 || !zdbPlaintext.subarray(0, ZDB_MAGIC.length).equals(ZDB_MAGIC)) {
912
+ throw new ZaloApiError.ZaloApiError("Buffer is not a valid decrypted ZDB4.0 container");
913
+ }
914
+ const count = zdbPlaintext.readUInt32BE(COUNT_OFFSET);
915
+ let offset = COUNT_OFFSET + 4;
916
+ const entries = [];
917
+ for (let i = 0; i < count; i++) {
918
+ if (offset + 4 > zdbPlaintext.length) {
919
+ throw new ZaloApiError.ZaloApiError("Truncated ZDB4.0 header while reading entry name length");
920
+ }
921
+ const nameLen = zdbPlaintext.readUInt32BE(offset);
922
+ if (offset + 4 + nameLen + 4 > zdbPlaintext.length) {
923
+ throw new ZaloApiError.ZaloApiError("Truncated ZDB4.0 header while reading entry metadata");
924
+ }
925
+ const name = zdbPlaintext
926
+ .toString("utf8", offset + 4, offset + 4 + nameLen)
927
+ .replace(/\0+$/, "");
928
+ const size = zdbPlaintext.readUInt32BE(offset + 4 + nameLen);
929
+ entries.push({ name, size });
930
+ offset += 4 + nameLen + 4;
931
+ }
932
+ return { entries, xzOffset: offset };
933
+ }
904
934
 
905
935
  exports.ParamsEncryptor = ParamsEncryptor;
906
936
  exports.apiFactory = apiFactory;
@@ -939,6 +969,7 @@ exports.isBun = isBun;
939
969
  exports.logger = logger;
940
970
  exports.makeURL = makeURL;
941
971
  exports.normalizeHolderName = normalizeHolderName;
972
+ exports.parseZdbHeader = parseZdbHeader;
942
973
  exports.removeUndefinedKeys = removeUndefinedKeys;
943
974
  exports.request = request;
944
975
  exports.resolveResponse = resolveResponse;
package/dist/index.d.ts CHANGED
@@ -176,4 +176,4 @@ export { ChatTTL } from "./apis/updateAutoDeleteChat.js";
176
176
  export { UpdateLangAvailableLanguages } from "./apis/updateLang.js";
177
177
  export { UpdateSettingsType } from "./apis/updateSettings.js";
178
178
  export { CallType } from "./apis/sendVoiceCall.js";
179
- export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer } from "./utils.js";
179
+ export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer, parseZdbHeader, type ZdbTocEntry, } from "./utils.js";
package/dist/index.js CHANGED
@@ -13,4 +13,4 @@ export { ChatTTL } from "./apis/updateAutoDeleteChat.js";
13
13
  export { UpdateLangAvailableLanguages } from "./apis/updateLang.js";
14
14
  export { UpdateSettingsType } from "./apis/updateSettings.js";
15
15
  export { CallType } from "./apis/sendVoiceCall.js";
16
- export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer } from "./utils.js";
16
+ export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer, parseZdbHeader, } from "./utils.js";
package/dist/utils.d.ts CHANGED
@@ -243,4 +243,16 @@ export declare function deriveZdbAesKey(decryptedRsaBytes: Buffer): Buffer;
243
243
  * (header + table of contents + XZ stream) using 64KB independent AES-256-CBC chunks (`IV = 0`).
244
244
  */
245
245
  export declare function decryptZdbBuffer(zdbBuffer: Buffer, aesKey: Buffer): Buffer;
246
+ export type ZdbTocEntry = {
247
+ name: string;
248
+ size: number;
249
+ };
250
+ /**
251
+ * Parses the Table of Contents (TOC) from a decrypted ZDB4.0 container buffer,
252
+ * returning the list of SQLite `.db` files (`<uid>.db` / `group_<gid>.db`) and the byte offset where the XZ stream starts.
253
+ */
254
+ export declare function parseZdbHeader(zdbPlaintext: Buffer): {
255
+ entries: ZdbTocEntry[];
256
+ xzOffset: number;
257
+ };
246
258
  export {};
package/dist/utils.js CHANGED
@@ -951,3 +951,33 @@ export function decryptZdbBuffer(zdbBuffer, aesKey) {
951
951
  }
952
952
  throw new ZaloApiError("Invalid AES key or buffer is not in ZDB4.0 format");
953
953
  }
954
+ /**
955
+ * Parses the Table of Contents (TOC) from a decrypted ZDB4.0 container buffer,
956
+ * returning the list of SQLite `.db` files (`<uid>.db` / `group_<gid>.db`) and the byte offset where the XZ stream starts.
957
+ */
958
+ export function parseZdbHeader(zdbPlaintext) {
959
+ const ZDB_MAGIC = Buffer.from("ZDB4.0", "ascii");
960
+ const COUNT_OFFSET = 14;
961
+ if (zdbPlaintext.length < COUNT_OFFSET + 4 || !zdbPlaintext.subarray(0, ZDB_MAGIC.length).equals(ZDB_MAGIC)) {
962
+ throw new ZaloApiError("Buffer is not a valid decrypted ZDB4.0 container");
963
+ }
964
+ const count = zdbPlaintext.readUInt32BE(COUNT_OFFSET);
965
+ let offset = COUNT_OFFSET + 4;
966
+ const entries = [];
967
+ for (let i = 0; i < count; i++) {
968
+ if (offset + 4 > zdbPlaintext.length) {
969
+ throw new ZaloApiError("Truncated ZDB4.0 header while reading entry name length");
970
+ }
971
+ const nameLen = zdbPlaintext.readUInt32BE(offset);
972
+ if (offset + 4 + nameLen + 4 > zdbPlaintext.length) {
973
+ throw new ZaloApiError("Truncated ZDB4.0 header while reading entry metadata");
974
+ }
975
+ const name = zdbPlaintext
976
+ .toString("utf8", offset + 4, offset + 4 + nameLen)
977
+ .replace(/\0+$/, "");
978
+ const size = zdbPlaintext.readUInt32BE(offset + 4 + nameLen);
979
+ entries.push({ name, size });
980
+ offset += 4 + nameLen + 4;
981
+ }
982
+ return { entries, xzOffset: offset };
983
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softtynet/zca-js",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "Unofficial Zalo API for JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",