@softtynet/zca-js 2.2.1 → 2.2.2
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 +47 -21
- package/dist/apis/cancelPullMobile.d.ts +11 -0
- package/dist/apis/cancelPullMobile.js +33 -0
- package/dist/apis/cancelVoiceCall.d.ts +7 -0
- package/dist/apis/cancelVoiceCall.js +43 -0
- package/dist/apis/decryptGids.d.ts +2 -1
- package/dist/apis/decryptGids.js +2 -0
- package/dist/apis/endVoiceCall.d.ts +5 -0
- package/dist/apis/endVoiceCall.js +41 -0
- package/dist/apis/getNoisedIds.d.ts +9 -0
- package/dist/apis/getNoisedIds.js +67 -0
- package/dist/apis/getSyncData.d.ts +13 -0
- package/dist/apis/getSyncData.js +103 -0
- package/dist/apis/listen.d.ts +11 -3
- package/dist/apis/listen.js +71 -14
- package/dist/apis/preloadConversations.d.ts +20 -2
- package/dist/apis/preloadConversations.js +56 -3
- package/dist/apis/pullMobile.d.ts +15 -0
- package/dist/apis/pullMobile.js +38 -0
- package/dist/apis/requestSyncFromPhone.d.ts +17 -1
- package/dist/apis/requestSyncFromPhone.js +34 -20
- package/dist/apis/sendVoiceCall.d.ts +29 -0
- package/dist/apis/sendVoiceCall.js +105 -0
- package/dist/apis/uploadAttachment.js +6 -1
- package/dist/apis.d.ts +14 -0
- package/dist/apis.js +14 -0
- package/dist/cjs/apis/addReaction.cjs +2 -0
- package/dist/cjs/apis/addUnreadMark.cjs +2 -0
- package/dist/cjs/apis/cancelPullMobile.cjs +38 -0
- package/dist/cjs/apis/cancelVoiceCall.cjs +48 -0
- package/dist/cjs/apis/createReminder.cjs +2 -0
- package/dist/cjs/apis/decryptGids.cjs +2 -0
- package/dist/cjs/apis/deleteChat.cjs +2 -0
- package/dist/cjs/apis/deleteMessage.cjs +2 -0
- package/dist/cjs/apis/editReminder.cjs +2 -0
- package/dist/cjs/apis/endVoiceCall.cjs +46 -0
- package/dist/cjs/apis/findUser.cjs +2 -0
- package/dist/cjs/apis/findUserByUsername.cjs +2 -0
- package/dist/cjs/apis/forwardMessage.cjs +2 -0
- package/dist/cjs/apis/getAllFriends.cjs +2 -0
- package/dist/cjs/apis/getAvatarUrlProfile.cjs +2 -0
- package/dist/cjs/apis/getGroupChatHistory.cjs +2 -0
- package/dist/cjs/apis/getListBoard.cjs +2 -0
- package/dist/cjs/apis/getListReminder.cjs +2 -0
- package/dist/cjs/apis/getMultiUsersByPhones.cjs +2 -0
- package/dist/cjs/apis/getNoisedIds.cjs +72 -0
- package/dist/cjs/apis/getSyncData.cjs +108 -0
- package/dist/cjs/apis/getUserInfo.cjs +2 -0
- package/dist/cjs/apis/listen.cjs +71 -14
- package/dist/cjs/apis/preloadConversations.cjs +69 -3
- package/dist/cjs/apis/pullMobile.cjs +43 -0
- package/dist/cjs/apis/removeReminder.cjs +2 -0
- package/dist/cjs/apis/removeUnreadMark.cjs +2 -0
- package/dist/cjs/apis/requestSyncFromPhone.cjs +33 -19
- package/dist/cjs/apis/sendBankCard.cjs +2 -0
- package/dist/cjs/apis/sendCard.cjs +2 -0
- package/dist/cjs/apis/sendDeliveredEvent.cjs +2 -0
- package/dist/cjs/apis/sendLink.cjs +2 -0
- package/dist/cjs/apis/sendMessage.cjs +2 -0
- package/dist/cjs/apis/sendReport.cjs +2 -0
- package/dist/cjs/apis/sendSeenEvent.cjs +2 -0
- package/dist/cjs/apis/sendSticker.cjs +2 -0
- package/dist/cjs/apis/sendTypingEvent.cjs +2 -0
- package/dist/cjs/apis/sendVideo.cjs +2 -0
- package/dist/cjs/apis/sendVoice.cjs +2 -0
- package/dist/cjs/apis/sendVoiceCall.cjs +110 -0
- package/dist/cjs/apis/setHiddenConversations.cjs +2 -0
- package/dist/cjs/apis/setMute.cjs +2 -0
- package/dist/cjs/apis/setPinnedConversations.cjs +2 -0
- package/dist/cjs/apis/undo.cjs +2 -0
- package/dist/cjs/apis/updateAutoDeleteChat.cjs +2 -0
- package/dist/cjs/apis/uploadAttachment.cjs +8 -1
- package/dist/cjs/apis.cjs +14 -0
- package/dist/cjs/index.cjs +24 -0
- package/dist/cjs/models/CallEvent.cjs +51 -0
- package/dist/cjs/models/ClearUnread.cjs +17 -0
- package/dist/cjs/models/SyncEvent.cjs +54 -0
- package/dist/cjs/utils.cjs +153 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +2 -0
- package/dist/models/CallEvent.d.ts +30 -0
- package/dist/models/CallEvent.js +47 -0
- package/dist/models/ClearUnread.d.ts +22 -0
- package/dist/models/ClearUnread.js +12 -0
- package/dist/models/SyncData.d.ts +35 -0
- package/dist/models/SyncData.js +1 -0
- package/dist/models/SyncEvent.d.ts +83 -0
- package/dist/models/SyncEvent.js +50 -0
- package/dist/models/index.d.ts +4 -0
- package/dist/models/index.js +4 -0
- package/dist/utils.d.ts +34 -0
- package/dist/utils.js +148 -1
- package/docs/REA_REVERSE_ENGINEERING_PLAN.md +140 -0
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -19,6 +19,9 @@ var SeenMessage = require('./models/SeenMessage.cjs');
|
|
|
19
19
|
var Typing = require('./models/Typing.cjs');
|
|
20
20
|
var Undo = require('./models/Undo.cjs');
|
|
21
21
|
var ZBusiness = require('./models/ZBusiness.cjs');
|
|
22
|
+
var ClearUnread = require('./models/ClearUnread.cjs');
|
|
23
|
+
var SyncEvent = require('./models/SyncEvent.cjs');
|
|
24
|
+
var CallEvent = require('./models/CallEvent.cjs');
|
|
22
25
|
var zalo = require('./zalo.cjs');
|
|
23
26
|
var listen = require('./apis/listen.cjs');
|
|
24
27
|
var loginQR = require('./apis/loginQR.cjs');
|
|
@@ -30,6 +33,8 @@ var setMute = require('./apis/setMute.cjs');
|
|
|
30
33
|
var updateAutoDeleteChat = require('./apis/updateAutoDeleteChat.cjs');
|
|
31
34
|
var updateLang = require('./apis/updateLang.cjs');
|
|
32
35
|
var updateSettings = require('./apis/updateSettings.cjs');
|
|
36
|
+
var sendVoiceCall = require('./apis/sendVoiceCall.cjs');
|
|
37
|
+
var utils = require('./utils.cjs');
|
|
33
38
|
var apis = require('./apis.cjs');
|
|
34
39
|
|
|
35
40
|
|
|
@@ -107,6 +112,17 @@ Object.defineProperty(exports, "BusinessCategory", {
|
|
|
107
112
|
get: function () { return ZBusiness.BusinessCategory; }
|
|
108
113
|
});
|
|
109
114
|
exports.BusinessCategoryName = ZBusiness.BusinessCategoryName;
|
|
115
|
+
exports.ClearUnread = ClearUnread.ClearUnread;
|
|
116
|
+
Object.defineProperty(exports, "SyncEventType", {
|
|
117
|
+
enumerable: true,
|
|
118
|
+
get: function () { return SyncEvent.SyncEventType; }
|
|
119
|
+
});
|
|
120
|
+
exports.initializeSyncEvent = SyncEvent.initializeSyncEvent;
|
|
121
|
+
Object.defineProperty(exports, "CallEventType", {
|
|
122
|
+
enumerable: true,
|
|
123
|
+
get: function () { return CallEvent.CallEventType; }
|
|
124
|
+
});
|
|
125
|
+
exports.initializeCallEvent = CallEvent.initializeCallEvent;
|
|
110
126
|
exports.Zalo = zalo.Zalo;
|
|
111
127
|
Object.defineProperty(exports, "CloseReason", {
|
|
112
128
|
enumerable: true,
|
|
@@ -156,4 +172,12 @@ Object.defineProperty(exports, "UpdateSettingsType", {
|
|
|
156
172
|
enumerable: true,
|
|
157
173
|
get: function () { return updateSettings.UpdateSettingsType; }
|
|
158
174
|
});
|
|
175
|
+
Object.defineProperty(exports, "CallType", {
|
|
176
|
+
enumerable: true,
|
|
177
|
+
get: function () { return sendVoiceCall.CallType; }
|
|
178
|
+
});
|
|
179
|
+
exports.decryptWithPrivateKey = utils.decryptWithPrivateKey;
|
|
180
|
+
exports.decryptZdbBuffer = utils.decryptZdbBuffer;
|
|
181
|
+
exports.deriveZdbAesKey = utils.deriveZdbAesKey;
|
|
182
|
+
exports.generateRSAKeyPair = utils.generateRSAKeyPair;
|
|
159
183
|
exports.API = apis.API;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.CallEventType = void 0;
|
|
4
|
+
(function (CallEventType) {
|
|
5
|
+
CallEventType["REQUEST"] = "request";
|
|
6
|
+
CallEventType["ANSWER"] = "answer";
|
|
7
|
+
CallEventType["CANCEL"] = "cancel";
|
|
8
|
+
CallEventType["END"] = "end";
|
|
9
|
+
CallEventType["RINGRING"] = "ringring";
|
|
10
|
+
CallEventType["GROUP_REQUEST"] = "group_request";
|
|
11
|
+
CallEventType["GROUP_ANSWER"] = "group_answer";
|
|
12
|
+
CallEventType["UNKNOWN"] = "unknown";
|
|
13
|
+
})(exports.CallEventType || (exports.CallEventType = {}));
|
|
14
|
+
function initializeCallEvent(data, act, act_type) {
|
|
15
|
+
let type = exports.CallEventType.UNKNOWN;
|
|
16
|
+
switch (act) {
|
|
17
|
+
case "request":
|
|
18
|
+
type = exports.CallEventType.REQUEST;
|
|
19
|
+
break;
|
|
20
|
+
case "answer":
|
|
21
|
+
type = exports.CallEventType.ANSWER;
|
|
22
|
+
break;
|
|
23
|
+
case "cancel":
|
|
24
|
+
type = exports.CallEventType.CANCEL;
|
|
25
|
+
break;
|
|
26
|
+
case "end":
|
|
27
|
+
case "endcall":
|
|
28
|
+
type = exports.CallEventType.END;
|
|
29
|
+
break;
|
|
30
|
+
case "ringring":
|
|
31
|
+
type = exports.CallEventType.RINGRING;
|
|
32
|
+
break;
|
|
33
|
+
case "group_request":
|
|
34
|
+
type = exports.CallEventType.GROUP_REQUEST;
|
|
35
|
+
break;
|
|
36
|
+
case "group_answer":
|
|
37
|
+
type = exports.CallEventType.GROUP_ANSWER;
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
type = exports.CallEventType.UNKNOWN;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
type,
|
|
45
|
+
act,
|
|
46
|
+
act_type,
|
|
47
|
+
data,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
exports.initializeCallEvent = initializeCallEvent;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Enum = require('./Enum.cjs');
|
|
4
|
+
|
|
5
|
+
class ClearUnread {
|
|
6
|
+
constructor(data) {
|
|
7
|
+
this.idTo = data.idTo;
|
|
8
|
+
this.userName = data.userName;
|
|
9
|
+
this.lastMsgId = data.lastMsgId;
|
|
10
|
+
this.isGroup = data.isGroup === 1;
|
|
11
|
+
this.threadType = data.isGroup === 1 ? Enum.ThreadType.Group : Enum.ThreadType.User;
|
|
12
|
+
this.ts = data.ts;
|
|
13
|
+
this.type = data.type;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.ClearUnread = ClearUnread;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.SyncEventType = void 0;
|
|
4
|
+
(function (SyncEventType) {
|
|
5
|
+
SyncEventType["USER_CONFIRM"] = "user_confirm";
|
|
6
|
+
SyncEventType["SYNCMSG_INFO"] = "syncmsg_info";
|
|
7
|
+
SyncEventType["TRANSFER_ERROR"] = "transfer_error";
|
|
8
|
+
SyncEventType["TRANSFER_AFTER_LOGIN"] = "transfer_after_login";
|
|
9
|
+
SyncEventType["UNKNOWN"] = "unknown";
|
|
10
|
+
})(exports.SyncEventType || (exports.SyncEventType = {}));
|
|
11
|
+
function initializeSyncEvent(data, act, act_type) {
|
|
12
|
+
if (act === "user_confirm") {
|
|
13
|
+
return {
|
|
14
|
+
type: exports.SyncEventType.USER_CONFIRM,
|
|
15
|
+
data: data,
|
|
16
|
+
act,
|
|
17
|
+
act_type,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else if (act === "syncmsg_info") {
|
|
21
|
+
return {
|
|
22
|
+
type: exports.SyncEventType.SYNCMSG_INFO,
|
|
23
|
+
data: data,
|
|
24
|
+
act,
|
|
25
|
+
act_type,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
else if (act === "transfer_error") {
|
|
29
|
+
return {
|
|
30
|
+
type: exports.SyncEventType.TRANSFER_ERROR,
|
|
31
|
+
data: data,
|
|
32
|
+
act,
|
|
33
|
+
act_type,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
else if (act === "transfer_after_login") {
|
|
37
|
+
return {
|
|
38
|
+
type: exports.SyncEventType.TRANSFER_AFTER_LOGIN,
|
|
39
|
+
data: data,
|
|
40
|
+
act,
|
|
41
|
+
act_type,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return {
|
|
46
|
+
type: exports.SyncEventType.UNKNOWN,
|
|
47
|
+
data,
|
|
48
|
+
act,
|
|
49
|
+
act_type,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports.initializeSyncEvent = initializeSyncEvent;
|
package/dist/cjs/utils.cjs
CHANGED
|
@@ -683,7 +683,16 @@ async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
|
683
683
|
};
|
|
684
684
|
return result;
|
|
685
685
|
}
|
|
686
|
-
|
|
686
|
+
if (isEncrypted && (!jsonData.data || jsonData.data.length === 0)) {
|
|
687
|
+
result.data = {};
|
|
688
|
+
return result;
|
|
689
|
+
}
|
|
690
|
+
const decodedStr = isEncrypted ? decodeAES(ctx.secretKey, jsonData.data) : null;
|
|
691
|
+
if (isEncrypted && (!decodedStr || decodedStr.length === 0)) {
|
|
692
|
+
result.data = {};
|
|
693
|
+
return result;
|
|
694
|
+
}
|
|
695
|
+
const decodedData = isEncrypted ? JSON.parse(decodedStr) : jsonData;
|
|
687
696
|
if (decodedData.error_code != 0) {
|
|
688
697
|
result.error = {
|
|
689
698
|
message: decodedData.error_message,
|
|
@@ -754,6 +763,144 @@ function normalizeHolderName(input) {
|
|
|
754
763
|
.trim();
|
|
755
764
|
return normalized.length >= 5 ? normalized : undefined;
|
|
756
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* Generates an RSA 2048-bit key pair for mobile message synchronization (`pull_mobile_msg`)
|
|
768
|
+
* @returns Object containing public and private keys in both PEM and Base64 formats
|
|
769
|
+
*/
|
|
770
|
+
function generateRSAKeyPair() {
|
|
771
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
772
|
+
modulusLength: 2048,
|
|
773
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
774
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
775
|
+
});
|
|
776
|
+
const publicKeyBase64 = publicKey
|
|
777
|
+
.toString()
|
|
778
|
+
.replace(/-----BEGIN PUBLIC KEY-----/g, "")
|
|
779
|
+
.replace(/-----END PUBLIC KEY-----/g, "")
|
|
780
|
+
.replace(/\s+/g, "");
|
|
781
|
+
const privateKeyBase64 = privateKey
|
|
782
|
+
.toString()
|
|
783
|
+
.replace(/-----BEGIN PRIVATE KEY-----/g, "")
|
|
784
|
+
.replace(/-----END PRIVATE KEY-----/g, "")
|
|
785
|
+
.replace(/\s+/g, "");
|
|
786
|
+
return { publicKeyBase64, privateKeyBase64, publicKey: publicKey.toString(), privateKey: privateKey.toString() };
|
|
787
|
+
}
|
|
788
|
+
function b64urlToBigInt(value) {
|
|
789
|
+
return BigInt("0x" + Buffer.from(value, "base64url").toString("hex"));
|
|
790
|
+
}
|
|
791
|
+
function modPow(base, exp, mod) {
|
|
792
|
+
const zero = BigInt(0);
|
|
793
|
+
const one = BigInt(1);
|
|
794
|
+
let result = one;
|
|
795
|
+
base %= mod;
|
|
796
|
+
while (exp > zero) {
|
|
797
|
+
if (exp & one)
|
|
798
|
+
result = (result * base) % mod;
|
|
799
|
+
base = (base * base) % mod;
|
|
800
|
+
exp >>= one;
|
|
801
|
+
}
|
|
802
|
+
return result;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Pure-BigInt RSA CRT PKCS#1 v1.5 decryption fallback for Node.js environments
|
|
806
|
+
* where OpenSSL blocks `RSA_PKCS1_PADDING` in `crypto.privateDecrypt` (CVE-2023-46809).
|
|
807
|
+
*/
|
|
808
|
+
function rsaDecryptPkcs1Manual(privateKeyPem, cipher) {
|
|
809
|
+
const jwk = crypto.createPrivateKey(privateKeyPem).export({ format: "jwk" });
|
|
810
|
+
const n = b64urlToBigInt(jwk.n);
|
|
811
|
+
const p = b64urlToBigInt(jwk.p);
|
|
812
|
+
const q = b64urlToBigInt(jwk.q);
|
|
813
|
+
const dp = b64urlToBigInt(jwk.dp);
|
|
814
|
+
const dq = b64urlToBigInt(jwk.dq);
|
|
815
|
+
const qi = b64urlToBigInt(jwk.qi);
|
|
816
|
+
const c = BigInt("0x" + cipher.toString("hex"));
|
|
817
|
+
const m1 = modPow(c, dp, p);
|
|
818
|
+
const m2 = modPow(c, dq, q);
|
|
819
|
+
const h = (qi * (((m1 - m2) % p) + p)) % p;
|
|
820
|
+
const m = m2 + h * q;
|
|
821
|
+
const k = Math.ceil(n.toString(16).length / 2);
|
|
822
|
+
const em = Buffer.from(m.toString(16).padStart(k * 2, "0"), "hex");
|
|
823
|
+
if (em[0] !== 0x00 || em[1] !== 0x02)
|
|
824
|
+
throw new ZaloApiError.ZaloApiError("Invalid RSA PKCS#1 v1.5 padding");
|
|
825
|
+
const sep = em.indexOf(0x00, 2);
|
|
826
|
+
if (sep < 10)
|
|
827
|
+
throw new ZaloApiError.ZaloApiError("Invalid RSA PKCS#1 v1.5 padding separator");
|
|
828
|
+
return em.subarray(sep + 1);
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Decrypt `encrypted_key` from `syncmsg_info` using RSA private key with PKCS#1 v1.5 scheme.
|
|
832
|
+
* Automatically falls back to pure-BigInt CRT decryption if OpenSSL disables `RSA_PKCS1_PADDING`.
|
|
833
|
+
*
|
|
834
|
+
* @param privateKey - RSA private key in PEM format
|
|
835
|
+
* @param encryptedBase64 - Base64 encoded `encrypted_key` from `syncmsg_info`
|
|
836
|
+
* @returns Raw decrypted bytes (typically 16-32 bytes; use `deriveZdbAesKey` for ZDB4.0 AES-256-CBC key)
|
|
837
|
+
*/
|
|
838
|
+
function decryptWithPrivateKey(privateKey, encryptedBase64) {
|
|
839
|
+
const cleanKey = privateKey.replace(/\\n/g, "\n");
|
|
840
|
+
const encryptedBuffer = Buffer.from(encryptedBase64, "base64");
|
|
841
|
+
try {
|
|
842
|
+
return crypto.privateDecrypt({
|
|
843
|
+
key: cleanKey,
|
|
844
|
+
padding: crypto.constants.RSA_PKCS1_PADDING,
|
|
845
|
+
}, encryptedBuffer);
|
|
846
|
+
}
|
|
847
|
+
catch (err) {
|
|
848
|
+
const errorObj = err;
|
|
849
|
+
const code = String((errorObj === null || errorObj === void 0 ? void 0 : errorObj.code) || "");
|
|
850
|
+
const msg = String((errorObj === null || errorObj === void 0 ? void 0 : errorObj.message) || "");
|
|
851
|
+
if (code.includes("INVALID_ARG") || /RSA_PKCS1_PADDING|security-revert|not supported/i.test(msg)) {
|
|
852
|
+
return rsaDecryptPkcs1Manual(cleanKey, encryptedBuffer);
|
|
853
|
+
}
|
|
854
|
+
throw err;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Derives the 32-byte AES-256-CBC key for Zalo ZDB4.0 (`.db.crypt`) backup files
|
|
859
|
+
* from the raw RSA-decrypted bytes: first 32 uppercase hex characters as ASCII bytes.
|
|
860
|
+
*/
|
|
861
|
+
function deriveZdbAesKey(decryptedRsaBytes) {
|
|
862
|
+
const upperHex = decryptedRsaBytes.toString("hex").toUpperCase();
|
|
863
|
+
if (upperHex.length < 32) {
|
|
864
|
+
throw new ZaloApiError.ZaloApiError(`Decrypted RSA key hex is too short (${upperHex.length} chars, expected >= 32)`);
|
|
865
|
+
}
|
|
866
|
+
return Buffer.from(upperHex.slice(0, 32), "ascii");
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Decrypts a Zalo ZDB4.0 (`.db.crypt`) backup buffer into its plaintext ZDB4.0 container
|
|
870
|
+
* (header + table of contents + XZ stream) using 64KB independent AES-256-CBC chunks (`IV = 0`).
|
|
871
|
+
*/
|
|
872
|
+
function decryptZdbBuffer(zdbBuffer, aesKey) {
|
|
873
|
+
const ZDB_MAGIC = Buffer.from("ZDB4.0", "ascii");
|
|
874
|
+
const CHUNK_SIZE = 0x10000;
|
|
875
|
+
const zeroIv = Buffer.alloc(16, 0);
|
|
876
|
+
for (const startOffset of [0, 4]) {
|
|
877
|
+
const encryptedLength = Math.floor((zdbBuffer.length - startOffset) / 16) * 16;
|
|
878
|
+
if (encryptedLength < 16)
|
|
879
|
+
continue;
|
|
880
|
+
const firstChunkLen = Math.min(CHUNK_SIZE, encryptedLength);
|
|
881
|
+
const firstDecipher = crypto.createDecipheriv("aes-256-cbc", aesKey, zeroIv);
|
|
882
|
+
firstDecipher.setAutoPadding(false);
|
|
883
|
+
const firstPlain = Buffer.concat([
|
|
884
|
+
firstDecipher.update(zdbBuffer.subarray(startOffset, startOffset + firstChunkLen)),
|
|
885
|
+
firstDecipher.final(),
|
|
886
|
+
]);
|
|
887
|
+
if (!firstPlain.subarray(0, ZDB_MAGIC.length).equals(ZDB_MAGIC)) {
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
const chunks = [firstPlain];
|
|
891
|
+
for (let offset = CHUNK_SIZE; offset < encryptedLength; offset += CHUNK_SIZE) {
|
|
892
|
+
const len = Math.min(CHUNK_SIZE, encryptedLength - offset);
|
|
893
|
+
const decipher = crypto.createDecipheriv("aes-256-cbc", aesKey, zeroIv);
|
|
894
|
+
decipher.setAutoPadding(false);
|
|
895
|
+
chunks.push(Buffer.concat([
|
|
896
|
+
decipher.update(zdbBuffer.subarray(startOffset + offset, startOffset + offset + len)),
|
|
897
|
+
decipher.final(),
|
|
898
|
+
]));
|
|
899
|
+
}
|
|
900
|
+
return Buffer.concat(chunks);
|
|
901
|
+
}
|
|
902
|
+
throw new ZaloApiError.ZaloApiError("Invalid AES key or buffer is not in ZDB4.0 format");
|
|
903
|
+
}
|
|
757
904
|
|
|
758
905
|
exports.ParamsEncryptor = ParamsEncryptor;
|
|
759
906
|
exports.apiFactory = apiFactory;
|
|
@@ -762,9 +909,13 @@ exports.decodeBase64ToBuffer = decodeBase64ToBuffer;
|
|
|
762
909
|
exports.decodeEventData = decodeEventData;
|
|
763
910
|
exports.decodeUnit8Array = decodeUnit8Array;
|
|
764
911
|
exports.decryptResp = decryptResp;
|
|
912
|
+
exports.decryptWithPrivateKey = decryptWithPrivateKey;
|
|
913
|
+
exports.decryptZdbBuffer = decryptZdbBuffer;
|
|
914
|
+
exports.deriveZdbAesKey = deriveZdbAesKey;
|
|
765
915
|
exports.encodeAES = encodeAES;
|
|
766
916
|
exports.encryptPin = encryptPin;
|
|
767
917
|
exports.formatTime = formatTime;
|
|
918
|
+
exports.generateRSAKeyPair = generateRSAKeyPair;
|
|
768
919
|
exports.generateZaloUUID = generateZaloUUID;
|
|
769
920
|
exports.getBrowserLanguage = getBrowserLanguage;
|
|
770
921
|
exports.getChromeVersionFromUA = getChromeVersionFromUA;
|
|
@@ -791,4 +942,5 @@ exports.normalizeHolderName = normalizeHolderName;
|
|
|
791
942
|
exports.removeUndefinedKeys = removeUndefinedKeys;
|
|
792
943
|
exports.request = request;
|
|
793
944
|
exports.resolveResponse = resolveResponse;
|
|
945
|
+
exports.rsaDecryptPkcs1Manual = rsaDecryptPkcs1Manual;
|
|
794
946
|
exports.strPadLeft = strPadLeft;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export type { AddUnreadMarkResponse } from "./apis/addUnreadMark.js";
|
|
|
12
12
|
export type { AddUserToGroupResponse } from "./apis/addUserToGroup.js";
|
|
13
13
|
export type { BlockUserResponse } from "./apis/blockUser.js";
|
|
14
14
|
export type { BlockViewFeedResponse } from "./apis/blockViewFeed.js";
|
|
15
|
+
export type { CancelPullMobileParams, CancelPullMobileResponse } from "./apis/cancelPullMobile.js";
|
|
16
|
+
export type { CancelVoiceCallOptions, CancelVoiceCallResponse } from "./apis/cancelVoiceCall.js";
|
|
15
17
|
export type { ChangeAccountAvatarResponse } from "./apis/changeAccountAvatar.js";
|
|
16
18
|
export type { ChangeFriendAliasResponse } from "./apis/changeFriendAlias.js";
|
|
17
19
|
export type { ChangeGroupAvatarResponse } from "./apis/changeGroupAvatar.js";
|
|
@@ -40,6 +42,7 @@ export type { DisperseGroupResponse } from "./apis/disperseGroup.js";
|
|
|
40
42
|
export type { EditNoteOptions, EditNoteResponse } from "./apis/editNote.js";
|
|
41
43
|
export type { EditReminderGroup, EditReminderUser, EditReminderOptions, EditReminderResponse } from "./apis/editReminder.js";
|
|
42
44
|
export type { EnableGroupLinkResponse } from "./apis/enableGroupLink.js";
|
|
45
|
+
export type { EndVoiceCallOptions, EndVoiceCallResponse } from "./apis/endVoiceCall.js";
|
|
43
46
|
export type { FetchAccountInfoResponse } from "./apis/fetchAccountInfo.js";
|
|
44
47
|
export type { FindUserResponse } from "./apis/findUser.js";
|
|
45
48
|
export type { FindUserByUsernameResponse } from "./apis/findUserByUsername.js";
|
|
@@ -77,6 +80,7 @@ export type { GetListDeviceResponse } from "./apis/getListDevice.js";
|
|
|
77
80
|
export type { GetListReminderResponse, ListReminderOptions, ReminderListGroup, ReminderListUser } from "./apis/getListReminder.js";
|
|
78
81
|
export type { GetMultiUsersByPhonesResponse } from "./apis/getMultiUsersByPhones.js";
|
|
79
82
|
export type { GetMuteResponse, MuteEntriesInfo } from "./apis/getMute.js";
|
|
83
|
+
export type { GetNoisedIdsParams, GetNoisedIdsResponse } from "./apis/getNoisedIds.js";
|
|
80
84
|
export type { GetPendingGroupMembersResponse, GetPendingGroupMembersUserInfo } from "./apis/getPendingGroupMembers.js";
|
|
81
85
|
export type { GetPinConversationsResponse } from "./apis/getPinConversations.js";
|
|
82
86
|
export type { PollDetailResponse } from "./apis/getPollDetail.js";
|
|
@@ -90,6 +94,7 @@ export type { GetSentFriendRequestResponse, SentFriendRequestInfo } from "./apis
|
|
|
90
94
|
export type { GetSettingsResponse } from "./apis/getSettings.js";
|
|
91
95
|
export type { GetStickerCategoryDetailResponse } from "./apis/getStickerCategoryDetail.js";
|
|
92
96
|
export type { StickerDetailResponse } from "./apis/getStickersDetail.js";
|
|
97
|
+
export type { GetSyncDataParams } from "./apis/getSyncData.js";
|
|
93
98
|
export type { GetUnreadMarkResponse, UnreadMark } from "./apis/getUnreadMark.js";
|
|
94
99
|
export type { ProfileInfo, UserInfoResponse } from "./apis/getUserInfo.js";
|
|
95
100
|
export type { InviteUserToGroupsResponse } from "./apis/inviteUserToGroups.js";
|
|
@@ -102,6 +107,8 @@ export type { LockPollResponse } from "./apis/lockPoll.js";
|
|
|
102
107
|
export type { LoginQRCallback, LoginQRCallbackEvent } from "./apis/loginQR.js";
|
|
103
108
|
export type { LostFocusResponse } from "./apis/lostFocus.js";
|
|
104
109
|
export type { ParseLinkErrorMaps, ParseLinkResponse } from "./apis/parseLink.js";
|
|
110
|
+
export type { PreloadConversationsRawResponse, PreloadConversationsResponse } from "./apis/preloadConversations.js";
|
|
111
|
+
export type { PullMobileParams, PullMobileResponse } from "./apis/pullMobile.js";
|
|
105
112
|
export type { RegisterCatalogResponse } from "./apis/registerCatalog.js";
|
|
106
113
|
export type { RejectFriendRequestResponse } from "./apis/rejectFriendRequest.js";
|
|
107
114
|
export type { RemoveFriendResponse } from "./apis/removeFriend.js";
|
|
@@ -112,7 +119,7 @@ export type { RemoveQuickMessageResponse } from "./apis/removeQuickMessage.js";
|
|
|
112
119
|
export type { RemoveReminderResponse } from "./apis/removeReminder.js";
|
|
113
120
|
export type { RemoveUnreadMarkResponse } from "./apis/removeUnreadMark.js";
|
|
114
121
|
export type { RemoveUserFromGroupResponse } from "./apis/removeUserFromGroup.js";
|
|
115
|
-
export type { RequestSyncFromPhoneResponse } from "./apis/requestSyncFromPhone.js";
|
|
122
|
+
export type { RequestSyncFromPhoneOptions, RequestSyncFromPhoneResponse } from "./apis/requestSyncFromPhone.js";
|
|
116
123
|
export type { ResetHiddenConversPinResponse } from "./apis/resetHiddenConversPin.js";
|
|
117
124
|
export type { ReuseAvatarResponse } from "./apis/reuseAvatar.js";
|
|
118
125
|
export type { ReviewPendingMemberRequestPayload, ReviewPendingMemberRequestResponse } from "./apis/reviewPendingMemberRequest.js";
|
|
@@ -130,6 +137,7 @@ export type { SendStickerResponse, SendStickerPayload } from "./apis/sendSticker
|
|
|
130
137
|
export type { SendTypingEventResponse } from "./apis/sendTypingEvent.js";
|
|
131
138
|
export type { SendVideoOptions, SendVideoResponse } from "./apis/sendVideo.js";
|
|
132
139
|
export type { SendVoiceOptions, SendVoiceResponse } from "./apis/sendVoice.js";
|
|
140
|
+
export type { RequestCallServerInfo, SendVoiceCallOptions, SendVoiceCallResponse } from "./apis/sendVoiceCall.js";
|
|
133
141
|
export type { SetHiddenConversationsResponse } from "./apis/setHiddenConversations.js";
|
|
134
142
|
export type { SetMuteParams, SetMuteResponse } from "./apis/setMute.js";
|
|
135
143
|
export type { SetPinnedConversationsResponse } from "./apis/setPinnedConversations.js";
|
|
@@ -167,3 +175,5 @@ export { MuteAction, MuteDuration } from "./apis/setMute.js";
|
|
|
167
175
|
export { ChatTTL } from "./apis/updateAutoDeleteChat.js";
|
|
168
176
|
export { UpdateLangAvailableLanguages } from "./apis/updateLang.js";
|
|
169
177
|
export { UpdateSettingsType } from "./apis/updateSettings.js";
|
|
178
|
+
export { CallType } from "./apis/sendVoiceCall.js";
|
|
179
|
+
export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer } from "./utils.js";
|
package/dist/index.js
CHANGED
|
@@ -12,3 +12,5 @@ export { MuteAction, MuteDuration } from "./apis/setMute.js";
|
|
|
12
12
|
export { ChatTTL } from "./apis/updateAutoDeleteChat.js";
|
|
13
13
|
export { UpdateLangAvailableLanguages } from "./apis/updateLang.js";
|
|
14
14
|
export { UpdateSettingsType } from "./apis/updateSettings.js";
|
|
15
|
+
export { CallType } from "./apis/sendVoiceCall.js";
|
|
16
|
+
export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer } from "./utils.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare enum CallEventType {
|
|
2
|
+
REQUEST = "request",
|
|
3
|
+
ANSWER = "answer",
|
|
4
|
+
CANCEL = "cancel",
|
|
5
|
+
END = "end",
|
|
6
|
+
RINGRING = "ringring",
|
|
7
|
+
GROUP_REQUEST = "group_request",
|
|
8
|
+
GROUP_ANSWER = "group_answer",
|
|
9
|
+
UNKNOWN = "unknown"
|
|
10
|
+
}
|
|
11
|
+
export type TCallEventData = {
|
|
12
|
+
callId?: number;
|
|
13
|
+
call_id?: number;
|
|
14
|
+
uidN?: string | number;
|
|
15
|
+
callerId?: string | number;
|
|
16
|
+
calleeId?: string | number;
|
|
17
|
+
session?: string;
|
|
18
|
+
sessId?: string;
|
|
19
|
+
status?: number;
|
|
20
|
+
callType?: number;
|
|
21
|
+
ts?: number | string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
export type CallEvent = {
|
|
25
|
+
type: CallEventType;
|
|
26
|
+
act: string;
|
|
27
|
+
act_type: string;
|
|
28
|
+
data: TCallEventData;
|
|
29
|
+
};
|
|
30
|
+
export declare function initializeCallEvent(data: TCallEventData, act: string, act_type: string): CallEvent;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export var CallEventType;
|
|
2
|
+
(function (CallEventType) {
|
|
3
|
+
CallEventType["REQUEST"] = "request";
|
|
4
|
+
CallEventType["ANSWER"] = "answer";
|
|
5
|
+
CallEventType["CANCEL"] = "cancel";
|
|
6
|
+
CallEventType["END"] = "end";
|
|
7
|
+
CallEventType["RINGRING"] = "ringring";
|
|
8
|
+
CallEventType["GROUP_REQUEST"] = "group_request";
|
|
9
|
+
CallEventType["GROUP_ANSWER"] = "group_answer";
|
|
10
|
+
CallEventType["UNKNOWN"] = "unknown";
|
|
11
|
+
})(CallEventType || (CallEventType = {}));
|
|
12
|
+
export function initializeCallEvent(data, act, act_type) {
|
|
13
|
+
let type = CallEventType.UNKNOWN;
|
|
14
|
+
switch (act) {
|
|
15
|
+
case "request":
|
|
16
|
+
type = CallEventType.REQUEST;
|
|
17
|
+
break;
|
|
18
|
+
case "answer":
|
|
19
|
+
type = CallEventType.ANSWER;
|
|
20
|
+
break;
|
|
21
|
+
case "cancel":
|
|
22
|
+
type = CallEventType.CANCEL;
|
|
23
|
+
break;
|
|
24
|
+
case "end":
|
|
25
|
+
case "endcall":
|
|
26
|
+
type = CallEventType.END;
|
|
27
|
+
break;
|
|
28
|
+
case "ringring":
|
|
29
|
+
type = CallEventType.RINGRING;
|
|
30
|
+
break;
|
|
31
|
+
case "group_request":
|
|
32
|
+
type = CallEventType.GROUP_REQUEST;
|
|
33
|
+
break;
|
|
34
|
+
case "group_answer":
|
|
35
|
+
type = CallEventType.GROUP_ANSWER;
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
type = CallEventType.UNKNOWN;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
type,
|
|
43
|
+
act,
|
|
44
|
+
act_type,
|
|
45
|
+
data,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ThreadType } from "./Enum.js";
|
|
2
|
+
export type TClearUnreadItem = {
|
|
3
|
+
idTo: string;
|
|
4
|
+
userName?: string;
|
|
5
|
+
lastMsgId: string;
|
|
6
|
+
isGroup: number;
|
|
7
|
+
ts?: number;
|
|
8
|
+
type?: number;
|
|
9
|
+
};
|
|
10
|
+
export type TClearUnreads = {
|
|
11
|
+
clearUnreads: TClearUnreadItem[];
|
|
12
|
+
};
|
|
13
|
+
export declare class ClearUnread {
|
|
14
|
+
idTo: string;
|
|
15
|
+
userName?: string;
|
|
16
|
+
lastMsgId: string;
|
|
17
|
+
isGroup: boolean;
|
|
18
|
+
threadType: ThreadType;
|
|
19
|
+
ts?: number;
|
|
20
|
+
type?: number;
|
|
21
|
+
constructor(data: TClearUnreadItem);
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ThreadType } from "./Enum.js";
|
|
2
|
+
export class ClearUnread {
|
|
3
|
+
constructor(data) {
|
|
4
|
+
this.idTo = data.idTo;
|
|
5
|
+
this.userName = data.userName;
|
|
6
|
+
this.lastMsgId = data.lastMsgId;
|
|
7
|
+
this.isGroup = data.isGroup === 1;
|
|
8
|
+
this.threadType = data.isGroup === 1 ? ThreadType.Group : ThreadType.User;
|
|
9
|
+
this.ts = data.ts;
|
|
10
|
+
this.type = data.type;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type SyncData = {
|
|
2
|
+
file_path: string;
|
|
3
|
+
encrypted_key: string;
|
|
4
|
+
metadata: {
|
|
5
|
+
file_name: string;
|
|
6
|
+
file_size: number;
|
|
7
|
+
checksum_code: string;
|
|
8
|
+
from_seq_id: number;
|
|
9
|
+
is_full_transfer: number;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export type SyncDataStream = {
|
|
13
|
+
stream: ReadableStream<Uint8Array> | null;
|
|
14
|
+
metadata: {
|
|
15
|
+
file_name: string;
|
|
16
|
+
file_size: number;
|
|
17
|
+
checksum_code: string;
|
|
18
|
+
from_seq_id: number;
|
|
19
|
+
is_full_transfer: number;
|
|
20
|
+
encrypted_key: string;
|
|
21
|
+
};
|
|
22
|
+
response?: {
|
|
23
|
+
status: number;
|
|
24
|
+
statusText: string;
|
|
25
|
+
url: string;
|
|
26
|
+
contentType: string | null;
|
|
27
|
+
contentLength: string | null;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export type SyncDataResponse = {
|
|
31
|
+
success: boolean;
|
|
32
|
+
data?: SyncData;
|
|
33
|
+
stream?: SyncDataStream;
|
|
34
|
+
error?: string;
|
|
35
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export declare enum SyncEventType {
|
|
2
|
+
USER_CONFIRM = "user_confirm",
|
|
3
|
+
SYNCMSG_INFO = "syncmsg_info",
|
|
4
|
+
TRANSFER_ERROR = "transfer_error",
|
|
5
|
+
TRANSFER_AFTER_LOGIN = "transfer_after_login",
|
|
6
|
+
UNKNOWN = "unknown"
|
|
7
|
+
}
|
|
8
|
+
export type DatabaseBackupInfo = {
|
|
9
|
+
backup_db?: {
|
|
10
|
+
msg_total: number;
|
|
11
|
+
msg_thread: number;
|
|
12
|
+
};
|
|
13
|
+
origin_db?: {
|
|
14
|
+
msg_total: number;
|
|
15
|
+
msg_thread: number;
|
|
16
|
+
};
|
|
17
|
+
db_format?: number;
|
|
18
|
+
};
|
|
19
|
+
export type TSyncEventUserConfirm = {
|
|
20
|
+
user_action: number;
|
|
21
|
+
public_key: string;
|
|
22
|
+
pc_name: string;
|
|
23
|
+
};
|
|
24
|
+
export type TSyncEventSyncMsgInfo = {
|
|
25
|
+
uid: number;
|
|
26
|
+
url: string;
|
|
27
|
+
time: number;
|
|
28
|
+
device_type: number;
|
|
29
|
+
device_name: string;
|
|
30
|
+
client_version: number;
|
|
31
|
+
file_name: string;
|
|
32
|
+
checksum_code: string;
|
|
33
|
+
checksum?: string;
|
|
34
|
+
file_size: number;
|
|
35
|
+
client_time: number;
|
|
36
|
+
from_seq_id: number;
|
|
37
|
+
public_key: string;
|
|
38
|
+
encrypted_key: string;
|
|
39
|
+
trigger_reason: number;
|
|
40
|
+
is_full_transfer: number;
|
|
41
|
+
db_info: string | DatabaseBackupInfo;
|
|
42
|
+
};
|
|
43
|
+
export type TSyncEventTransferError = {
|
|
44
|
+
public_key: string;
|
|
45
|
+
pc_name: string;
|
|
46
|
+
can_retry?: number;
|
|
47
|
+
status?: number;
|
|
48
|
+
error_msg?: string;
|
|
49
|
+
error_code?: number;
|
|
50
|
+
};
|
|
51
|
+
export type TSyncEventTransferAfterLogin = {
|
|
52
|
+
temp_key: string;
|
|
53
|
+
imei: string;
|
|
54
|
+
[key: string]: unknown;
|
|
55
|
+
};
|
|
56
|
+
export type TSyncEvent = TSyncEventUserConfirm | TSyncEventSyncMsgInfo | TSyncEventTransferError | TSyncEventTransferAfterLogin;
|
|
57
|
+
export type SyncEvent = {
|
|
58
|
+
type: SyncEventType.USER_CONFIRM;
|
|
59
|
+
data: TSyncEventUserConfirm;
|
|
60
|
+
act: string;
|
|
61
|
+
act_type: string;
|
|
62
|
+
} | {
|
|
63
|
+
type: SyncEventType.SYNCMSG_INFO;
|
|
64
|
+
data: TSyncEventSyncMsgInfo;
|
|
65
|
+
act: string;
|
|
66
|
+
act_type: string;
|
|
67
|
+
} | {
|
|
68
|
+
type: SyncEventType.TRANSFER_ERROR;
|
|
69
|
+
data: TSyncEventTransferError;
|
|
70
|
+
act: string;
|
|
71
|
+
act_type: string;
|
|
72
|
+
} | {
|
|
73
|
+
type: SyncEventType.TRANSFER_AFTER_LOGIN;
|
|
74
|
+
data: TSyncEventTransferAfterLogin;
|
|
75
|
+
act: string;
|
|
76
|
+
act_type: string;
|
|
77
|
+
} | {
|
|
78
|
+
type: SyncEventType.UNKNOWN;
|
|
79
|
+
data: unknown;
|
|
80
|
+
act: string;
|
|
81
|
+
act_type: string;
|
|
82
|
+
};
|
|
83
|
+
export declare function initializeSyncEvent(data: TSyncEvent, act: string, act_type: string): SyncEvent;
|