Skip to content

zca-js ​

zca-js giả lập Zalo Web để một chương trình Node.js đăng nhập và nhắn tin bằng tài khoản cá nhân.

Bản được khảo sát: zca-js@2.2.0. Đây là thư viện mã nguồn mở của cộng đồng, viết bằng TypeScript, và không liên quan gì tới công ty Zalo/VNG.

loginQR / login(cookie, imei, userAgent)
    ↓  HTTP tới các service zpw (tham số mã hoá AES, ký MD5)
Context  (cookie jar, secretKey, uid, danh sách service)
    ↓
listener.start()  →  WebSocket  →  nhận cipher_key  →  ping định kỳ
    ↓
khung nhị phân: 4 byte header (version, cmd, subCmd) + JSON
    ↓  cmd 501 = tin 1-1 · 521 = tin group · 601 = sự kiện điều khiển
giải mã (AES + pako) → UserMessage / GroupMessage → emit("message")

Cơ chế ​

Thuộc tínhGhi chú
Đăng nhậploginQR() lấy mã QR từ Zalo. Quét xong, callback GotLoginInfo trả cookie, imei, userAgent. Lần sau gọi login(credentials) với bộ này, khỏi quét lại
Gọi APIMỗi hàm (sendMessage, getAllFriends, getGroupInfo…) là một factory tạo request HTTP. Tham số được mã hoá AES bằng secretKey của phiên, URL được ký, kết quả trả về được giải mã
Nhận tinlistener mở WebSocket. Gói đầu tiên mang key để giải mã; sau đó listener ping theo ping_interval do server cấp. Mỗi khung được tách header, parse JSON, giải mã payload rồi phát sự kiện message, reaction, undo, group_event, typing, seen_messages…
Tự nối lạistart({ retryOnClose: true }) thử lại theo bảng mã đóng và thời gian chờ do server cấu hình
Tin của chính mìnhselfListen: true thì tin bạn gửi từ máy khác cũng được phát ra, có isSelf = true

Đánh giá code ​

ĐiểmNhận xét
TốtCó type đầy đủ. Mỗi API một file, dễ tìm. Lưu được phiên đăng nhập. Có retry cho WebSocket. Phụ thuộc ít và phổ biến
Chưa tối ưuGiải mã và parse JSON chạy trên luồng chính; group đông tin có thể làm event loop bị nghẽn. encodeAES/decodeAES nuốt lỗi rồi thử lại tới 3 lần, nên lỗi thật bị che. Logging tắt/bật kiểu toàn cục. getGroupInfo mỗi lần là một request; thư viện không cache tên group hay thành viên
Rủi roPhụ thuộc hoàn toàn vào giao thức nội bộ của Zalo: Zalo đổi là thư viện hỏng cho tới khi có bản vá. Mỗi tài khoản chỉ có một kết nối WebSocket; mở Zalo Web ở nơi khác sẽ đá kết nối (mã 3000)

Có thể cải tiến ​

  • Cache tên group và thành viên (Ran đã tự cache tên group trong bộ nhớ).
  • Tách giải mã sang worker_threads khi lưu lượng lớn.
  • Phát sự kiện lỗi có cấu trúc thay vì nuốt lỗi khi giải mã.
  • Bù tin lúc mất kết nối: gọi requestOldMessages sau khi nối lại. Ran chưa làm việc này.
  • Hàng đợi gửi có giới hạn tốc độ để tránh bị Zalo đánh dấu spam.

Làm được và không làm được ​

Làm đượcKhông làm được
Nhận và gửi tin 1-1 và group theo thời gian thựcChạy song song với một tab Zalo Web khác của cùng tài khoản
Gửi ảnh, file, sticker, reaction, @mention, trích dẫn, thu hồiGọi thoại / video
Danh bạ, group, thông tin người dùng, quản trị group (thêm/xoá thành viên, đổi tên…)Đọc lại toàn bộ lịch sử cũ trên server (chỉ lấy được một phần qua requestOldMessages)
Lời mời kết bạn, nhãn, tin nhắn nhanh, trả lời tự động, bình chọnGiải mã nội dung bị Zalo mã hoá đầu-cuối (nếu bật)
Lưu và tái dùng phiên đăng nhậpBảo đảm tài khoản không bị khoá. Bảo đảm còn chạy khi Zalo đổi giao thức