@softtynet/zca-js 2.2.7 → 2.2.9
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 +160 -179
- package/dist/apis/clearUnreadFriendRequests.d.ts +2 -0
- package/dist/apis/clearUnreadFriendRequests.js +29 -0
- package/dist/apis/encryptGids.d.ts +4 -0
- package/dist/apis/encryptGids.js +24 -0
- package/dist/apis/getAliasListV2.d.ts +10 -0
- package/dist/apis/getAliasListV2.js +28 -0
- package/dist/apis/getBlockFriends.d.ts +6 -0
- package/dist/apis/getBlockFriends.js +28 -0
- package/dist/apis/getCloudInfo.d.ts +3 -0
- package/dist/apis/getCloudInfo.js +34 -0
- package/dist/apis/getCloudSettings.d.ts +10 -0
- package/dist/apis/getCloudSettings.js +34 -0
- package/dist/apis/getCloudViewerKey.d.ts +5 -0
- package/dist/apis/getCloudViewerKey.js +25 -0
- package/dist/apis/getConversationMedia.d.ts +26 -0
- package/dist/apis/getConversationMedia.js +39 -0
- package/dist/apis/getEmojiStatusConfig.d.ts +17 -0
- package/dist/apis/getEmojiStatusConfig.js +23 -0
- package/dist/apis/getExtraFriendInfo.d.ts +3 -0
- package/dist/apis/getExtraFriendInfo.js +31 -0
- package/dist/apis/getExtraGroupInfo.d.ts +7 -0
- package/dist/apis/getExtraGroupInfo.js +32 -0
- package/dist/apis/getFamilyProfile.d.ts +3 -0
- package/dist/apis/getFamilyProfile.js +34 -0
- package/dist/apis/getFamilyUsage.d.ts +7 -0
- package/dist/apis/getFamilyUsage.js +34 -0
- package/dist/apis/getFamilyViewerKey.d.ts +5 -0
- package/dist/apis/getFamilyViewerKey.js +25 -0
- package/dist/apis/getFriendsEmojiStatus.d.ts +17 -0
- package/dist/apis/getFriendsEmojiStatus.js +30 -0
- package/dist/apis/getGroupCloudMessageJump.d.ts +3 -0
- package/dist/apis/getGroupCloudMessageJump.js +46 -0
- package/dist/apis/getLastReadContactTab.d.ts +4 -0
- package/dist/apis/getLastReadContactTab.js +15 -0
- package/dist/apis/getLastSeen.d.ts +11 -0
- package/dist/apis/getLastSeen.js +40 -0
- package/dist/apis/getLastSeenReaction.d.ts +9 -0
- package/dist/apis/getLastSeenReaction.js +28 -0
- package/dist/apis/getListPinTopics.d.ts +5 -0
- package/dist/apis/getListPinTopics.js +28 -0
- package/dist/apis/getMediaStorePreview.d.ts +3 -0
- package/dist/apis/getMediaStorePreview.js +31 -0
- package/dist/apis/getMiniProfile.d.ts +13 -0
- package/dist/apis/getMiniProfile.js +34 -0
- package/dist/apis/getPersonalizedStickerList.d.ts +5 -0
- package/dist/apis/getPersonalizedStickerList.js +24 -0
- package/dist/apis/getPhonebookV2.d.ts +6 -0
- package/dist/apis/getPhonebookV2.js +21 -0
- package/dist/apis/getProfileRank.d.ts +5 -0
- package/dist/apis/getProfileRank.js +25 -0
- package/dist/apis/getProfileVerificationStatus.d.ts +5 -0
- package/dist/apis/getProfileVerificationStatus.js +20 -0
- package/dist/apis/getQuotaCommunity.d.ts +8 -0
- package/dist/apis/getQuotaCommunity.js +27 -0
- package/dist/apis/getRecentSearchList.d.ts +6 -0
- package/dist/apis/getRecentSearchList.js +25 -0
- package/dist/apis/getStickerCategoriesV2.d.ts +17 -0
- package/dist/apis/getStickerCategoriesV2.js +21 -0
- package/dist/apis/getStickerCategoryData.d.ts +3 -0
- package/dist/apis/getStickerCategoryData.js +25 -0
- package/dist/apis/getStickerHello.d.ts +16 -0
- package/dist/apis/getStickerHello.js +34 -0
- package/dist/apis/getStickerSuggestKeywords.d.ts +12 -0
- package/dist/apis/getStickerSuggestKeywords.js +24 -0
- package/dist/apis/getStickerSuggestion.d.ts +12 -0
- package/dist/apis/getStickerSuggestion.js +30 -0
- package/dist/apis/getUsageMyCloud.d.ts +7 -0
- package/dist/apis/getUsageMyCloud.js +34 -0
- package/dist/apis/getUsageZCloud.d.ts +11 -0
- package/dist/apis/getUsageZCloud.js +34 -0
- package/dist/apis/keepAlive.d.ts +2 -1
- package/dist/apis/keepAlive.js +5 -3
- package/dist/apis/listen.d.ts +13 -0
- package/dist/apis/listen.js +10 -0
- package/dist/apis/readContactTab.d.ts +2 -0
- package/dist/apis/readContactTab.js +26 -0
- package/dist/apis/removeConversationMedia.d.ts +8 -0
- package/dist/apis/removeConversationMedia.js +30 -0
- package/dist/apis/undoMultiMessage.d.ts +9 -0
- package/dist/apis/undoMultiMessage.js +46 -0
- package/dist/apis/updateRecentSearch.d.ts +11 -0
- package/dist/apis/updateRecentSearch.js +41 -0
- package/dist/apis/verifyCloudMedia.d.ts +14 -0
- package/dist/apis/verifyCloudMedia.js +43 -0
- package/dist/apis/voiceToText.d.ts +4 -0
- package/dist/apis/voiceToText.js +30 -0
- package/dist/apis.d.ts +82 -0
- package/dist/apis.js +82 -0
- package/dist/cjs/apis/clearUnreadFriendRequests.cjs +34 -0
- package/dist/cjs/apis/encryptGids.cjs +29 -0
- package/dist/cjs/apis/getAliasListV2.cjs +33 -0
- package/dist/cjs/apis/getBlockFriends.cjs +33 -0
- package/dist/cjs/apis/getCloudInfo.cjs +39 -0
- package/dist/cjs/apis/getCloudSettings.cjs +39 -0
- package/dist/cjs/apis/getCloudViewerKey.cjs +30 -0
- package/dist/cjs/apis/getConversationMedia.cjs +44 -0
- package/dist/cjs/apis/getEmojiStatusConfig.cjs +28 -0
- package/dist/cjs/apis/getExtraFriendInfo.cjs +36 -0
- package/dist/cjs/apis/getExtraGroupInfo.cjs +37 -0
- package/dist/cjs/apis/getFamilyProfile.cjs +39 -0
- package/dist/cjs/apis/getFamilyUsage.cjs +39 -0
- package/dist/cjs/apis/getFamilyViewerKey.cjs +30 -0
- package/dist/cjs/apis/getFriendsEmojiStatus.cjs +35 -0
- package/dist/cjs/apis/getGroupCloudMessageJump.cjs +63 -0
- package/dist/cjs/apis/getLastReadContactTab.cjs +20 -0
- package/dist/cjs/apis/getLastSeen.cjs +45 -0
- package/dist/cjs/apis/getLastSeenReaction.cjs +33 -0
- package/dist/cjs/apis/getListPinTopics.cjs +33 -0
- package/dist/cjs/apis/getMediaStorePreview.cjs +36 -0
- package/dist/cjs/apis/getMiniProfile.cjs +39 -0
- package/dist/cjs/apis/getPersonalizedStickerList.cjs +29 -0
- package/dist/cjs/apis/getPhonebookV2.cjs +26 -0
- package/dist/cjs/apis/getProfileRank.cjs +30 -0
- package/dist/cjs/apis/getProfileVerificationStatus.cjs +25 -0
- package/dist/cjs/apis/getQuotaCommunity.cjs +32 -0
- package/dist/cjs/apis/getRecentSearchList.cjs +30 -0
- package/dist/cjs/apis/getStickerCategoriesV2.cjs +26 -0
- package/dist/cjs/apis/getStickerCategoryData.cjs +30 -0
- package/dist/cjs/apis/getStickerHello.cjs +39 -0
- package/dist/cjs/apis/getStickerSuggestKeywords.cjs +29 -0
- package/dist/cjs/apis/getStickerSuggestion.cjs +35 -0
- package/dist/cjs/apis/getUsageMyCloud.cjs +39 -0
- package/dist/cjs/apis/getUsageZCloud.cjs +39 -0
- package/dist/cjs/apis/keepAlive.cjs +5 -3
- package/dist/cjs/apis/listen.cjs +10 -0
- package/dist/cjs/apis/readContactTab.cjs +31 -0
- package/dist/cjs/apis/removeConversationMedia.cjs +35 -0
- package/dist/cjs/apis/undoMultiMessage.cjs +62 -0
- package/dist/cjs/apis/updateRecentSearch.cjs +46 -0
- package/dist/cjs/apis/verifyCloudMedia.cjs +48 -0
- package/dist/cjs/apis/voiceToText.cjs +35 -0
- package/dist/cjs/apis.cjs +82 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/update.cjs +8 -6
- package/dist/cjs/utils.cjs +25 -0
- package/dist/context.d.ts +4 -0
- package/dist/index.d.ts +42 -1
- package/dist/index.js +1 -1
- package/dist/update.js +8 -6
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +23 -0
- package/docs/INTEGRATION_GUIDE_SYNC_AND_CALL.md +110 -0
- package/package.json +12 -9
- package/CODE_OF_CONDUCT.md +0 -163
- package/CONTRIBUTING.md +0 -470
- package/SECURITY.md +0 -83
package/README.md
CHANGED
|
@@ -1,54 +1,73 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @softtynet/zca-js — Softtynet Zalo API SDK for Node.js & Bun
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
>
|
|
6
|
-
|
|
3
|
+
<p align="left">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@softtynet/zca-js"><img src="https://img.shields.io/npm/v/@softtynet/zca-js.svg?label=%40softtynet%2Fzca-js&color=0068ff" alt="npm version" /></a>
|
|
5
|
+
<a href="https://github.com/softtyos/zca-js"><img src="https://img.shields.io/badge/Maintained%20by-Softtynet%20Co.%2C%20Ltd.-0a7cff" alt="Maintained by Softtynet" /></a>
|
|
6
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT" /></a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
**`@softtynet/zca-js`** là bộ thư viện Zalo API nâng cao dành cho Node.js / TypeScript / Bun, được phát triển, tối ưu hoá và duy trì bởi **Softtynet Co., Ltd.** nhằm đáp ứng các bài toán tích hợp chuyên sâu: **Đồng bộ dữ liệu đa thiết bị (Offline Catch-up & Mobile Backup Sync `ZDB4.0`)**, **Tín hiệu Gọi Thoại & Gọi Video (Voice / Video Call Signaling)**, và **Xử lý WebSocket thời gian thực độ tin cậy cao**.
|
|
7
10
|
|
|
8
11
|
> [!WARNING]
|
|
9
|
-
>
|
|
12
|
+
> Đây là thư viện tương tác không chính thức thông qua giao thức Zalo Web / Zalo PC dành cho tài khoản cá nhân. Vui lòng sử dụng có trách nhiệm và tuân thủ quy định an toàn tài khoản.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Mục lục
|
|
17
|
+
|
|
18
|
+
- [Điểm nổi bật trên phiên bản Softtynet (`@softtynet/zca-js`)](#-điểm-nổi-bật-trên-phiên-bản-softtynet-softtynetzca-js)
|
|
19
|
+
- [Cài đặt](#-cài-đặt)
|
|
20
|
+
- [Tài liệu chuyên sâu](#-tài-liệu-chuyên-sâu)
|
|
21
|
+
- [Hướng dẫn sử dụng nhanh](#-hướng-dẫn-sử-dụng-nhanh)
|
|
22
|
+
- [1. Đăng nhập & Lưu phiên](#1-đăng-nhập--lưu-phiên)
|
|
23
|
+
- [2. Lắng nghe tin nhắn thời gian thực](#2-lắng-nghe-tin-nhắn-thời-gian-thực)
|
|
24
|
+
- [3. Đồng bộ bù tin nhắn khi Offline (Catch-up Sync)](#3-đồng-bộ-bù-tin-nhắn-khi-offline-catch-up-sync)
|
|
25
|
+
- [4. Đồng bộ lịch sử sao lưu từ Điện thoại (`ZDB4.0`)](#4-đồng-bộ-lịch-sử-sao-lưu-từ-điện-thoại-zdb40)
|
|
26
|
+
- [5. Khởi tạo Cuộc gọi Thoại & Gọi Video](#5-khởi-tạo-cuộc-gọi-thoại--gọi-video)
|
|
27
|
+
- [6. Gửi tin nhắn & Sticker](#6-gửi-tin-nhắn--sticker)
|
|
28
|
+
- [Kiểm định & Chạy thử nghiệm](#-kiểm-định--chạy-thử-nghiệm)
|
|
29
|
+
- [Nguồn gốc & Ghi nhận (Credits & Attribution)](#-nguồn-gốc--ghi-nhận-credits--attribution)
|
|
30
|
+
- [Giấy phép (License)](#-giấy-phép-license)
|
|
10
31
|
|
|
11
32
|
---
|
|
12
33
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
34
|
+
## 🚀 Điểm nổi bật trên phiên bản Softtynet (`@softtynet/zca-js`)
|
|
35
|
+
|
|
36
|
+
So với phiên bản cộng đồng tiêu chuẩn, **`@softtynet/zca-js`** bổ sung các phân hệ cốt lõi đã được kiểm định trực tiếp trên máy chủ Zalo thật:
|
|
37
|
+
|
|
38
|
+
| Phân hệ | Tính năng trên `@softtynet/zca-js` |
|
|
39
|
+
| :--- | :--- |
|
|
40
|
+
| **Đồng bộ bù khi Offline (Catch-up Sync)** | Hỗ trợ [`api.preloadConversations()`](src/apis/preloadConversations.ts) (`cmd 10053`), kéo hàng đợi tin nhắn cá nhân & nhóm qua [`api.listener.requestOldMessages()`](src/apis/listen.ts) (`cmd 510` / `511`, cả `subCmd 0` & `1`), kèm cờ phân trang `hasMore`, tách biệt sự kiện thu hồi `undo` và đồng bộ trạng thái đã đọc `unread_cleared` (`cmd 504` / `524`). |
|
|
41
|
+
| **Đồng bộ sao lưu từ Điện thoại (`ZDB4.0`)** | Hỗ trợ trọn vẹn chu trình [`api.requestSyncFromPhone()`](src/apis/requestSyncFromPhone.ts) (`cmd 12000`), [`api.cancelPullMobile()`](src/apis/cancelPullMobile.ts) (`cmd 12700`), sự kiện `sync_event` (`user_confirm`, `syncmsg_info`, `transfer_after_login`), tải gói `.db.crypt` qua [`api.getSyncData()`](src/apis/getSyncData.ts) và giải mã RSA-2048 PKCS#1 v1.5 + AES-256-CBC đa khối 64KB + đọc mục lục SQLite (`parseZdbHeader`). |
|
|
42
|
+
| **Ánh xạ ID ẩn danh (Noised / Global ID)** | Hỗ trợ [`api.getNoisedIds()`](src/apis/getNoisedIds.ts) (`cmd 12390` kèm cơ chế tự động fallback sang `zwid.api.zalo.me`) và [`api.decryptGids()`](src/apis/decryptGids.ts) (`cmd 12054`) để ánh xạ tên file SQLite `3_<me>_<peer>.db` về User ID / Group ID thật. |
|
|
43
|
+
| **Gọi Thoại & Gọi Video (Signaling 2 bước)** | Hỗ trợ [`api.sendVoiceCall()`](src/apis/sendVoiceCall.ts) (`cmd 11300` + `11301`), [`api.cancelVoiceCall()`](src/apis/cancelVoiceCall.ts) (`cmd 11305`), [`api.endVoiceCall()`](src/apis/endVoiceCall.ts) (`cmd 11306`) và sự kiện `call_event` chuẩn giao thức C++ `ZaloCall` cho cả **Gọi Thoại (`CallType.Audio = 1`)** lẫn **Gọi Video (`CallType.Video = 3`, H.264)**. |
|
|
44
|
+
| **Hệ sinh thái ZCloud, ZFamily & AI (`26.7.10`)** | Hỗ trợ chuẩn mã hóa `98yS` (AES-256-CBC với 16-byte Random IV) cho ZCloud & ZFamily ([`getCloudViewerKey`](src/apis/getCloudViewerKey.ts), [`getUsageZCloud`](src/apis/getUsageZCloud.ts), [`getUsageMyCloud`](src/apis/getUsageMyCloud.ts), [`getCloudSettings`](src/apis/getCloudSettings.ts), [`getCloudInfo`](src/apis/getCloudInfo.ts), [`getFamilyUsage`](src/apis/getFamilyUsage.ts), [`verifyCloudMedia`](src/apis/verifyCloudMedia.ts), [`getFamilyViewerKey`](src/apis/getFamilyViewerKey.ts), [`getFamilyProfile`](src/apis/getFamilyProfile.ts)), AI chuyển giọng nói thành văn bản [`voiceToText`](src/apis/voiceToText.ts) (`cmd 13394` + `voice2text_event`), Emoji Status ([`getEmojiStatusConfig`](src/apis/getEmojiStatusConfig.ts), [`getFriendsEmojiStatus`](src/apis/getFriendsEmojiStatus.ts)), Kho Lưu Trữ Hội Thoại ([`getConversationMedia`](src/apis/getConversationMedia.ts), [`getMediaStorePreview`](src/apis/getMediaStorePreview.ts), [`removeConversationMedia`](src/apis/removeConversationMedia.ts)), Lịch sử tìm kiếm ([`getRecentSearchList`](src/apis/getRecentSearchList.ts), [`updateRecentSearch`](src/apis/updateRecentSearch.ts)) cùng 25+ API Nhóm, Hồ sơ, Danh bạ & Nhãn dán V2 đã kiểm định Live 100%. |
|
|
45
|
+
| **Độ ổn định & Bảo vệ bộ nhớ** | Tự động giải phóng bộ nhớ `uploadCallbacks` sau 5 phút trong [`uploadAttachment`](src/apis/uploadAttachment.ts), xử lý phản hồi rỗng hợp lệ (`error_code === 0, data === ""`) và bảo toàn độ chính xác chuỗi UID 19 chữ số. |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 📦 Cài đặt
|
|
31
50
|
|
|
32
51
|
```bash
|
|
33
|
-
|
|
52
|
+
npm install @softtynet/zca-js
|
|
53
|
+
# hoặc dùng Bun
|
|
54
|
+
bun add @softtynet/zca-js
|
|
34
55
|
```
|
|
35
56
|
|
|
36
|
-
###
|
|
57
|
+
### Cấu hình `imageMetadataGetter` (Khi gửi ảnh từ đường dẫn file)
|
|
37
58
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Example of custom `imageMetadataGetter` using `sharp`:
|
|
59
|
+
Từ kiến trúc V2, thư viện tách rời phụ thuộc xử lý ảnh để giữ dung lượng gọn nhẹ. Nếu ứng dụng của bạn gửi ảnh/GIF từ file nội bộ, hãy truyền hàm `imageMetadataGetter` (ví dụ dùng `sharp`):
|
|
41
60
|
|
|
42
61
|
```bash
|
|
43
|
-
|
|
62
|
+
npm install sharp
|
|
44
63
|
```
|
|
45
64
|
|
|
46
|
-
```
|
|
47
|
-
import { Zalo } from "zca-js";
|
|
65
|
+
```ts
|
|
66
|
+
import { Zalo } from "@softtynet/zca-js";
|
|
48
67
|
import sharp from "sharp";
|
|
49
68
|
import fs from "node:fs";
|
|
50
69
|
|
|
51
|
-
async function imageMetadataGetter(filePath) {
|
|
70
|
+
async function imageMetadataGetter(filePath: string) {
|
|
52
71
|
const data = await fs.promises.readFile(filePath);
|
|
53
72
|
const metadata = await sharp(data).metadata();
|
|
54
73
|
return {
|
|
@@ -58,80 +77,75 @@ async function imageMetadataGetter(filePath) {
|
|
|
58
77
|
};
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
const zalo = new Zalo({
|
|
62
|
-
imageMetadataGetter,
|
|
63
|
-
});
|
|
80
|
+
const zalo = new Zalo({ imageMetadataGetter });
|
|
64
81
|
```
|
|
65
82
|
|
|
66
83
|
---
|
|
67
84
|
|
|
68
|
-
##
|
|
85
|
+
## 📚 Tài liệu chuyên sâu
|
|
69
86
|
|
|
70
|
-
- [
|
|
71
|
-
- [
|
|
72
|
-
- [
|
|
87
|
+
- **[Hướng dẫn Tích hợp: Đồng bộ Tin nhắn Đa Thiết bị (`ZDB4.0`) & Gọi Thoại / Video](docs/INTEGRATION_GUIDE_SYNC_AND_CALL.md)** — Tài liệu đầy đủ kèm sơ đồ kiến trúc và code mẫu tích hợp thực tế của Softtynet.
|
|
88
|
+
- **[Kế hoạch & Hướng dẫn Dịch ngược Zalo bằng REA (`morluto/rea`)](docs/REA_REVERSE_ENGINEERING_PLAN.md)** — Tài liệu quy trình phân tích tĩnh Binary C++ (`ZaloCall`, `libzdatabase.dylib`) và ASAR.
|
|
89
|
+
- **[API Reference Cơ bản](https://zca-js.tdung.com)** — Tra cứu danh mục các API cơ bản.
|
|
73
90
|
|
|
74
91
|
---
|
|
75
92
|
|
|
76
|
-
##
|
|
93
|
+
## ⚡ Hướng dẫn sử dụng nhanh
|
|
77
94
|
|
|
78
|
-
###
|
|
95
|
+
### 1. Đăng nhập & Lưu phiên
|
|
79
96
|
|
|
80
|
-
```
|
|
81
|
-
import { Zalo } from "zca-js";
|
|
97
|
+
```ts
|
|
98
|
+
import { Zalo } from "@softtynet/zca-js";
|
|
82
99
|
|
|
83
|
-
const zalo = new Zalo();
|
|
100
|
+
const zalo = new Zalo({ selfListen: true });
|
|
84
101
|
const api = await zalo.loginQR();
|
|
102
|
+
console.log("Đã đăng nhập với UID:", api.getOwnId());
|
|
85
103
|
```
|
|
86
104
|
|
|
87
|
-
###
|
|
105
|
+
### 2. Lắng nghe tin nhắn thời gian thực
|
|
88
106
|
|
|
89
|
-
```
|
|
90
|
-
import { Zalo, ThreadType } from "zca-js";
|
|
107
|
+
```ts
|
|
108
|
+
import { Zalo, ThreadType } from "@softtynet/zca-js";
|
|
91
109
|
|
|
92
|
-
const zalo = new Zalo();
|
|
110
|
+
const zalo = new Zalo({ selfListen: true });
|
|
93
111
|
const api = await zalo.loginQR();
|
|
94
112
|
|
|
95
113
|
api.listener.on("message", (message) => {
|
|
96
114
|
const isPlainText = typeof message.data.content === "string";
|
|
115
|
+
if (!isPlainText) return;
|
|
97
116
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
case ThreadType.Group: {
|
|
106
|
-
if (isPlainText) {
|
|
107
|
-
// received plain text group message
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
117
|
+
if (message.type === ThreadType.User) {
|
|
118
|
+
console.log(`[Cá nhân] ${message.data.dName}: ${message.data.content}`);
|
|
119
|
+
} else if (message.type === ThreadType.Group) {
|
|
120
|
+
console.log(`[Nhóm ${message.threadId}] ${message.data.dName}: ${message.data.content}`);
|
|
111
121
|
}
|
|
112
122
|
});
|
|
113
123
|
|
|
114
|
-
api.listener.start();
|
|
124
|
+
api.listener.start({ retryOnClose: true });
|
|
115
125
|
```
|
|
116
126
|
|
|
117
127
|
> [!IMPORTANT]
|
|
118
|
-
>
|
|
128
|
+
> Mỗi tài khoản Zalo chỉ duy trì một kết nối WebSocket Web tại một thời điểm. Nếu bạn mở thêm tab Zalo Web trên trình duyệt, kết nối WebSocket cũ sẽ nhận sự kiện `duplicate_connection`.
|
|
119
129
|
|
|
120
|
-
###
|
|
130
|
+
### 3. Đồng bộ bù tin nhắn khi Offline (Catch-up Sync)
|
|
121
131
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
#### 1. Catch Up Missed Messages After Reconnect / Restart
|
|
125
|
-
```javascript
|
|
126
|
-
import { Zalo, ThreadType } from "zca-js";
|
|
132
|
+
```ts
|
|
133
|
+
import { ThreadType } from "@softtynet/zca-js";
|
|
127
134
|
|
|
135
|
+
// 1. Lấy nhanh các tin nhắn mới nhất & danh sách đã đọc qua HTTP (cmd 10053)
|
|
128
136
|
const preload = await api.preloadConversations();
|
|
129
|
-
console.log(`Preloaded ${preload.messages.length}
|
|
137
|
+
console.log(`Preloaded: ${preload.messages.length} tin nhắn, ${preload.unreadCleared.length} trạng thái đã đọc`);
|
|
130
138
|
|
|
139
|
+
// 2. Nhận tin nhắn từ hàng đợi WebSocket (cmd 510 & 511)
|
|
131
140
|
api.listener.on("old_messages", (messages, type, hasMore) => {
|
|
132
|
-
console.log(`
|
|
141
|
+
console.log(`Nhận ${messages.length} tin nhắn cũ (type=${type}, hasMore=${hasMore})`);
|
|
142
|
+
if (hasMore && messages.length > 0) {
|
|
143
|
+
const lastMsgId = messages[messages.length - 1].data.msgId;
|
|
144
|
+
api.listener.requestOldMessages(type, lastMsgId);
|
|
145
|
+
}
|
|
133
146
|
});
|
|
134
147
|
|
|
148
|
+
// 3. Kích hoạt kéo hàng đợi ngay khi nhận khoá giải mã WebSocket
|
|
135
149
|
api.listener.on("cipher_key", () => {
|
|
136
150
|
api.listener.requestOldMessages(ThreadType.User);
|
|
137
151
|
api.listener.requestOldMessages(ThreadType.Group);
|
|
@@ -140,155 +154,122 @@ api.listener.on("cipher_key", () => {
|
|
|
140
154
|
api.listener.start({ retryOnClose: true });
|
|
141
155
|
```
|
|
142
156
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
### 4. Đồng bộ lịch sử sao lưu từ Điện thoại (`ZDB4.0`)
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import fs from "node:fs";
|
|
161
|
+
import {
|
|
162
|
+
SyncEventType,
|
|
163
|
+
decryptWithPrivateKey,
|
|
164
|
+
deriveZdbAesKey,
|
|
165
|
+
decryptZdbBuffer,
|
|
166
|
+
parseZdbHeader,
|
|
167
|
+
} from "@softtynet/zca-js";
|
|
146
168
|
|
|
147
169
|
let privateKey = "";
|
|
148
170
|
|
|
149
171
|
api.listener.on("sync_event", async (event) => {
|
|
150
172
|
if (event.type === SyncEventType.USER_CONFIRM) {
|
|
151
|
-
console.log("
|
|
173
|
+
console.log("Người dùng đã bấm xác nhận trên điện thoại, đang chờ tải gói sao lưu...");
|
|
152
174
|
} else if (event.type === SyncEventType.SYNCMSG_INFO) {
|
|
153
175
|
const res = await api.getSyncData({ ...event.data, savePath: "./sync_data" });
|
|
154
176
|
if (res.success && res.data && privateKey) {
|
|
155
177
|
const rawRsa = decryptWithPrivateKey(privateKey, res.data.encrypted_key);
|
|
156
178
|
const aesKey = deriveZdbAesKey(rawRsa);
|
|
157
|
-
|
|
179
|
+
const zdbPlain = decryptZdbBuffer(fs.readFileSync(res.data.file_path), aesKey);
|
|
180
|
+
const toc = parseZdbHeader(zdbPlain);
|
|
181
|
+
console.log(`Giải mã thành công ZDB4.0 (${toc.entries.length} hội thoại SQLite):`, toc.entries.slice(0, 5));
|
|
158
182
|
}
|
|
159
183
|
}
|
|
160
184
|
});
|
|
161
185
|
|
|
162
|
-
api.listener.on("
|
|
163
|
-
const session = await api.requestSyncFromPhone();
|
|
186
|
+
api.listener.on("cipher_key", async () => {
|
|
187
|
+
const session = await api.requestSyncFromPhone({ pcName: "Web" });
|
|
164
188
|
privateKey = session.privateKey;
|
|
165
|
-
console.log("
|
|
189
|
+
console.log("Vui lòng mở điện thoại và bấm 'Đồng bộ ngay' trên thông báo Zalo!");
|
|
166
190
|
});
|
|
167
|
-
|
|
168
|
-
api.listener.start();
|
|
169
191
|
```
|
|
170
192
|
|
|
171
|
-
###
|
|
193
|
+
### 5. Khởi tạo Cuộc gọi Thoại & Gọi Video
|
|
172
194
|
|
|
173
|
-
```
|
|
174
|
-
import { CallType } from "zca-js";
|
|
195
|
+
```ts
|
|
196
|
+
import { CallType } from "@softtynet/zca-js";
|
|
175
197
|
|
|
176
|
-
|
|
177
|
-
const call = await api.sendVoiceCall("target_user_id", { callType: CallType.Audio });
|
|
178
|
-
console.log("Ringing callId:", call.callId, "session:", call.sessId);
|
|
179
|
-
|
|
180
|
-
// Cancel ringing or end an active call
|
|
181
|
-
await api.cancelVoiceCall("target_user_id", call.callId);
|
|
182
|
-
```
|
|
198
|
+
const targetUid = "5249661060655759359"; // Chuỗi UID 19 chữ số
|
|
183
199
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const zalo = new Zalo();
|
|
190
|
-
const api = await zalo.loginQR();
|
|
200
|
+
// Gọi Video (CallType.Video = 3, tự động đính kèm H.264 payload 97)
|
|
201
|
+
const videoCall = await api.sendVoiceCall(targetUid, {
|
|
202
|
+
callType: CallType.Video,
|
|
203
|
+
});
|
|
204
|
+
console.log("Đang đổ chuông Video:", videoCall.callId, videoCall.rtpServer);
|
|
191
205
|
|
|
192
|
-
//
|
|
193
|
-
api.
|
|
194
|
-
|
|
195
|
-
if (message.isSelf || !isPlainText) return;
|
|
196
|
-
|
|
197
|
-
switch (message.type) {
|
|
198
|
-
case ThreadType.User: {
|
|
199
|
-
api.sendMessage(
|
|
200
|
-
{
|
|
201
|
-
msg: "echo: " + message.data.content,
|
|
202
|
-
quote: message.data, // the message to reply to (optional)
|
|
203
|
-
},
|
|
204
|
-
message.threadId,
|
|
205
|
-
message.type, // ThreadType.User
|
|
206
|
-
);
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
case ThreadType.Group: {
|
|
210
|
-
api.sendMessage(
|
|
211
|
-
{
|
|
212
|
-
msg: "echo: " + message.data.content,
|
|
213
|
-
quote: message.data, // the message to reply to (optional)
|
|
214
|
-
},
|
|
215
|
-
message.threadId,
|
|
216
|
-
message.type, // ThreadType.Group
|
|
217
|
-
);
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
206
|
+
// Huỷ cuộc gọi khi đang đổ chuông
|
|
207
|
+
await api.cancelVoiceCall(targetUid, videoCall.callId, {
|
|
208
|
+
callType: CallType.Video,
|
|
221
209
|
});
|
|
222
210
|
|
|
223
|
-
|
|
211
|
+
// Hoặc gọi Thoại (CallType.Audio = 1)
|
|
212
|
+
const audioCall = await api.sendVoiceCall(targetUid, {
|
|
213
|
+
callType: CallType.Audio,
|
|
214
|
+
});
|
|
215
|
+
await api.cancelVoiceCall(targetUid, audioCall.callId);
|
|
224
216
|
```
|
|
225
217
|
|
|
226
|
-
###
|
|
227
|
-
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
|
|
218
|
+
### 6. Gửi tin nhắn & Sticker
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
// Trả lời tin nhắn văn bản
|
|
222
|
+
await api.sendMessage(
|
|
223
|
+
{
|
|
224
|
+
msg: "Xin chào từ hệ thống Softtynet!",
|
|
225
|
+
quote: message.data,
|
|
226
|
+
},
|
|
227
|
+
message.threadId,
|
|
228
|
+
message.type,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Tìm và gửi Sticker
|
|
232
|
+
const stickerIds = await api.getStickers("xin chào");
|
|
233
|
+
if (stickerIds.length > 0) {
|
|
231
234
|
const stickerObject = await api.getStickersDetail(stickerIds[0]);
|
|
232
|
-
api.sendMessageSticker(
|
|
233
|
-
|
|
234
|
-
message.threadId,
|
|
235
|
-
message.type, // ThreadType.User or ThreadType.Group
|
|
236
|
-
);
|
|
237
|
-
});
|
|
235
|
+
await api.sendMessageSticker(stickerObject, message.threadId, message.type);
|
|
236
|
+
}
|
|
238
237
|
```
|
|
239
238
|
|
|
240
239
|
---
|
|
241
240
|
|
|
242
|
-
##
|
|
243
|
-
|
|
244
|
-
See [examples](examples) folder for more details.
|
|
245
|
-
|
|
246
|
-
---
|
|
241
|
+
## 🧪 Kiểm định & Chạy thử nghiệm
|
|
247
242
|
|
|
248
|
-
|
|
243
|
+
Dự án đi kèm bộ kiểm định 2 lớp trong thư mục [`test/`](test):
|
|
249
244
|
|
|
250
|
-
|
|
245
|
+
1. **Kiểm định tự động (Offline / Unit Verification Suite)**:
|
|
246
|
+
```bash
|
|
247
|
+
npm run test:verify
|
|
248
|
+
```
|
|
249
|
+
Kiểm tra tự động toàn bộ 6 hạng mục: `preloadConversations`, `requestSyncFromPhone` / `pullMobile` / `cancelPullMobile`, `getNoisedIds` / `decryptGids`, giải mã `RSA-2048` + `ZDB4.0` đa khối 64KB, `sendVoiceCall` (Audio & Video) / `cancelVoiceCall` / `endVoiceCall`, và các sự kiện WebSocket (`510`, `511`, `504`, `601`).
|
|
251
250
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| [**n8n-nodes-zalo-tools**](https://github.com/ChickenAI/zalo-node) | N8N node for personal Zalo account. |
|
|
257
|
-
| [**Zalo-F12**](https://github.com/ElectroHeavenVN/Zalo-F12) | A collection of JavaScript code snippets to paste into DevTools to change how Zalo Web/PC works. |
|
|
258
|
-
| [**Zalo-F12-Tools**](https://github.com/JustKemForFun/Zalo-F12-Tools) | Toggle hidden modes for Zalo Web. |
|
|
251
|
+
2. **Kiểm định trực tiếp trên tài khoản Zalo thật (Live Verification Suite)**:
|
|
252
|
+
```bash
|
|
253
|
+
# Chạy toàn bộ 6 bước (Quét QR -> Preload -> ZNoise -> OldMessages -> Đồng bộ ZDB4.0 từ ĐT -> Voice/Video Call)
|
|
254
|
+
npm run test:live
|
|
259
255
|
|
|
260
|
-
|
|
256
|
+
# Chỉ test nhanh Gọi Thoại + Gọi Video tới 1 UID bạn bè
|
|
257
|
+
npm run test:live -- --only-call --call <UID_BAN_BE>
|
|
258
|
+
```
|
|
261
259
|
|
|
262
260
|
---
|
|
263
261
|
|
|
264
|
-
##
|
|
265
|
-
|
|
266
|
-
We welcome contributions from the community! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to:
|
|
267
|
-
|
|
268
|
-
- 🐛 Report bugs and issues
|
|
269
|
-
- ✨ Suggest new features
|
|
270
|
-
- 🔧 Submit code contributions
|
|
271
|
-
- 📚 Improve documentation
|
|
272
|
-
- 🧪 Add or improve tests
|
|
273
|
-
- 🔒 Report security vulnerabilities
|
|
262
|
+
## 🤝 Nguồn gốc & Ghi nhận (Credits & Attribution)
|
|
274
263
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
---
|
|
264
|
+
Dự án **`@softtynet/zca-js`** được phát triển, nâng cấp và duy trì bởi **Softtynet Co., Ltd.** ([`softtyos/zca-js`](https://github.com/softtyos/zca-js)), kế thừa nền tảng mã nguồn mở từ dự án gốc:
|
|
278
265
|
|
|
279
|
-
|
|
266
|
+
- **Dự án gốc**: [RFS-ADRENO/zca-js](https://github.com/RFS-ADRENO/zca-js)
|
|
267
|
+
- **Tác giả nền tảng gốc**: RFS-ADRENO, truong9c2208, JustKemForFun cùng các thành viên đóng góp từ cộng đồng mã nguồn mở.
|
|
280
268
|
|
|
281
|
-
|
|
269
|
+
Chúng tôi trân trọng cảm ơn các tác giả của dự án gốc đã xây dựng nền tảng ban đầu cho cộng đồng JavaScript/TypeScript.
|
|
282
270
|
|
|
283
271
|
---
|
|
284
272
|
|
|
285
|
-
##
|
|
273
|
+
## 📄 Giấy phép (License)
|
|
286
274
|
|
|
287
|
-
|
|
288
|
-
- 🔄 **Share** with your network to help us grow
|
|
289
|
-
- 💡 **Contribute** your ideas and code
|
|
290
|
-
- ☕ **A coffee**:
|
|
291
|
-
- [Buy Me a Coffee](https://ko-fi.com/grosse)
|
|
292
|
-
- [Paypal](https://www.paypal.com/paypalme/dungto213)
|
|
293
|
-
- [VietQR](https://github.com/user-attachments/assets/e1f319d6-9d11-4082-8248-55b55e645caa)
|
|
294
|
-
- [Momo](https://me.momo.vn/gMIMulsaUqsbf6iAiXt3)
|
|
275
|
+
Phát hành theo giấy phép [MIT License](LICENSE).
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type ClearUnreadFriendRequestsResponse = Record<string, unknown> | string;
|
|
2
|
+
export declare const clearUnreadFriendRequestsFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (uidsSeen?: string[]) => Promise<ClearUnreadFriendRequestsResponse>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ZaloApiError } from "../Errors/ZaloApiError.js";
|
|
2
|
+
import { apiFactory } from "../utils.js";
|
|
3
|
+
export const clearUnreadFriendRequestsFactory = apiFactory()((api, _ctx, utils) => {
|
|
4
|
+
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/recommendsv2/read-requests`);
|
|
5
|
+
/**
|
|
6
|
+
* Đánh dấu đã xem danh sách lời mời kết bạn chưa đọc (command 12232)
|
|
7
|
+
*
|
|
8
|
+
* @param uidsSeen Danh sách UID đã xem lời mời kết bạn (mặc định `[]`)
|
|
9
|
+
* @throws {ZaloApiError}
|
|
10
|
+
*/
|
|
11
|
+
return async function clearUnreadFriendRequests(uidsSeen = []) {
|
|
12
|
+
if (!uidsSeen || uidsSeen.length === 0) {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
const params = {
|
|
16
|
+
uids_seen: uidsSeen,
|
|
17
|
+
};
|
|
18
|
+
const encryptedParams = utils.encodeAES(JSON.stringify(params));
|
|
19
|
+
if (!encryptedParams)
|
|
20
|
+
throw new ZaloApiError("Failed to encrypt params");
|
|
21
|
+
const response = await utils.request(serviceURL, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: new URLSearchParams({
|
|
24
|
+
params: encryptedParams,
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
return utils.resolve(response);
|
|
28
|
+
};
|
|
29
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ZaloApiError } from "../Errors/ZaloApiError.js";
|
|
2
|
+
import { apiFactory } from "../utils.js";
|
|
3
|
+
export const encryptGidsFactory = apiFactory()((api, _ctx, utils) => {
|
|
4
|
+
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/gid/encrypt`);
|
|
5
|
+
/**
|
|
6
|
+
* Mã hóa danh sách UID thật sang định danh ẩn danh Global Noise ID (`OTDAKO...`) (command 12053)
|
|
7
|
+
*
|
|
8
|
+
* @param uids Mảng chuỗi các UID cần mã hóa
|
|
9
|
+
* @throws {ZaloApiError}
|
|
10
|
+
*/
|
|
11
|
+
return async function encryptGids(uids) {
|
|
12
|
+
if (!Array.isArray(uids) || uids.length === 0) {
|
|
13
|
+
return { data: {} };
|
|
14
|
+
}
|
|
15
|
+
const encryptedParams = utils.encodeAES(JSON.stringify({ noiseUids: uids }));
|
|
16
|
+
if (!encryptedParams) {
|
|
17
|
+
throw new ZaloApiError("Failed to encrypt params");
|
|
18
|
+
}
|
|
19
|
+
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
|
|
20
|
+
method: "GET",
|
|
21
|
+
});
|
|
22
|
+
return utils.resolve(response);
|
|
23
|
+
};
|
|
24
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type AliasItemV2 = {
|
|
2
|
+
userId: string;
|
|
3
|
+
alias: string;
|
|
4
|
+
};
|
|
5
|
+
export type GetAliasListV2Response = {
|
|
6
|
+
items: AliasItemV2[];
|
|
7
|
+
updateTime?: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
export declare const getAliasListV2Factory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (page?: number, count?: number) => Promise<GetAliasListV2Response>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ZaloApiError } from "../Errors/ZaloApiError.js";
|
|
2
|
+
import { apiFactory } from "../utils.js";
|
|
3
|
+
export const getAliasListV2Factory = apiFactory()((api, ctx, utils) => {
|
|
4
|
+
const serviceURL = utils.makeURL(`${api.zpwServiceMap.alias[0]}/api/alias/list/v2`);
|
|
5
|
+
/**
|
|
6
|
+
* Lấy danh sách tên gợi nhớ (Alias) của bạn bè chuẩn V2 có hỗ trợ phân trang (command 12205)
|
|
7
|
+
*
|
|
8
|
+
* @param page Trang cần lấy (mặc định: 1)
|
|
9
|
+
* @param count Số lượng mục mỗi trang (mặc định: 100)
|
|
10
|
+
* @throws {ZaloApiError}
|
|
11
|
+
*/
|
|
12
|
+
return async function getAliasListV2(page = 1, count = 100) {
|
|
13
|
+
const params = {
|
|
14
|
+
page,
|
|
15
|
+
count,
|
|
16
|
+
src: -1,
|
|
17
|
+
imei: ctx.imei,
|
|
18
|
+
};
|
|
19
|
+
const encryptedParams = utils.encodeAES(JSON.stringify(params));
|
|
20
|
+
if (!encryptedParams) {
|
|
21
|
+
throw new ZaloApiError("Failed to encrypt params");
|
|
22
|
+
}
|
|
23
|
+
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
|
|
24
|
+
method: "GET",
|
|
25
|
+
});
|
|
26
|
+
return utils.resolve(response);
|
|
27
|
+
};
|
|
28
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type GetBlockFriendsResponse = {
|
|
2
|
+
profiles: Record<string, unknown>[];
|
|
3
|
+
version: number;
|
|
4
|
+
hasMore: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const getBlockFriendsFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (page?: number, count?: number, avatarSize?: number) => Promise<GetBlockFriendsResponse>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ZaloApiError } from "../Errors/ZaloApiError.js";
|
|
2
|
+
import { apiFactory } from "../utils.js";
|
|
3
|
+
export const getBlockFriendsFactory = apiFactory()((api, _ctx, utils) => {
|
|
4
|
+
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/blocklistv2`);
|
|
5
|
+
/**
|
|
6
|
+
* Lấy danh sách người dùng đang bị chặn chuẩn V2 (command 11429)
|
|
7
|
+
*
|
|
8
|
+
* @param page Trang cần lấy (mặc định: 1)
|
|
9
|
+
* @param count Số lượng mỗi trang (mặc định: 50)
|
|
10
|
+
* @param avatarSize Kích thước ảnh đại diện (mặc định: 120)
|
|
11
|
+
* @throws {ZaloApiError}
|
|
12
|
+
*/
|
|
13
|
+
return async function getBlockFriends(page = 1, count = 50, avatarSize = 120) {
|
|
14
|
+
const params = {
|
|
15
|
+
page,
|
|
16
|
+
count,
|
|
17
|
+
avatar: avatarSize,
|
|
18
|
+
};
|
|
19
|
+
const encryptedParams = utils.encodeAES(JSON.stringify(params));
|
|
20
|
+
if (!encryptedParams) {
|
|
21
|
+
throw new ZaloApiError("Failed to encrypt params");
|
|
22
|
+
}
|
|
23
|
+
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
|
|
24
|
+
method: "GET",
|
|
25
|
+
});
|
|
26
|
+
return utils.resolve(response);
|
|
27
|
+
};
|
|
28
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { GetCloudViewerKeyResponse } from "./getCloudViewerKey.js";
|
|
2
|
+
export type GetCloudInfoResponse = Record<string, unknown>;
|
|
3
|
+
export declare const getCloudInfoFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (viewerKeyInfo?: GetCloudViewerKeyResponse) => Promise<GetCloudInfoResponse>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ZaloApiError } from "../Errors/ZaloApiError.js";
|
|
2
|
+
import { apiFactory, decryptZCloudAES } from "../utils.js";
|
|
3
|
+
export const getCloudInfoFactory = apiFactory()((api, _ctx, utils) => {
|
|
4
|
+
var _a;
|
|
5
|
+
const baseDomain = ((_a = api.zpwServiceMap.zcloud) === null || _a === void 0 ? void 0 : _a[0]) || "https://zcld.chat.zalo.me";
|
|
6
|
+
const serviceURL = utils.makeURL(`${baseDomain}/zalocloud/cloudinfopcweb/v1/info`);
|
|
7
|
+
/**
|
|
8
|
+
* Lấy thông tin gói thuê bao Zalo Cloud (command 12754)
|
|
9
|
+
*
|
|
10
|
+
* @param viewerKeyInfo (Tùy chọn) Cặp `{ viewer_key, enk }` từ `api.getCloudViewerKey()`.
|
|
11
|
+
* @throws {ZaloApiError}
|
|
12
|
+
*/
|
|
13
|
+
return async function getCloudInfo(viewerKeyInfo) {
|
|
14
|
+
const keyInfo = viewerKeyInfo !== null && viewerKeyInfo !== void 0 ? viewerKeyInfo : (await api.getCloudViewerKey());
|
|
15
|
+
if (!(keyInfo === null || keyInfo === void 0 ? void 0 : keyInfo.viewer_key) || !(keyInfo === null || keyInfo === void 0 ? void 0 : keyInfo.enk)) {
|
|
16
|
+
throw new ZaloApiError("Invalid CloudViewerKey");
|
|
17
|
+
}
|
|
18
|
+
const response = await utils.request(serviceURL, {
|
|
19
|
+
method: "GET",
|
|
20
|
+
headers: {
|
|
21
|
+
"cloud-viewer-key": keyInfo.viewer_key,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const json = (await response.json());
|
|
25
|
+
if (json.error_code !== 0 && json.error_code !== -904) {
|
|
26
|
+
throw new ZaloApiError(json.error_message || "getCloudInfo failed", json.error_code);
|
|
27
|
+
}
|
|
28
|
+
if (!json.data) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
const decrypted = decryptZCloudAES(json.data, keyInfo.enk);
|
|
32
|
+
return JSON.parse(decrypted);
|
|
33
|
+
};
|
|
34
|
+
});
|