Pabal API
Pabal API (MTProto)
Khi xây dựng client kết nối đến máy chủ theo cùng cách với ứng dụng: thông tin kết nối, khóa công khai của máy chủ, luồng xác thực, update và phạm vi hỗ trợ.
Ứng dụng Pabal giao tiếp với máy chủ bằng MTProto 2.0. Hãy đọc tài liệu này khi bạn xây dựng chương trình kết nối theo cùng cách đó — một ứng dụng khác, công cụ tự động hóa chạy bằng tài khoản người dùng, hay client phục vụ nghiên cứu. Nếu bạn tạo bot, Bot API đơn giản hơn là đủ dùng.
Pabal tuân theo giao thức công khai của Telegram, nên định nghĩa chi tiết của giao thức và các phương thức lấy tài liệu MTProto và phương thức API làm chuẩn. Tài liệu này ghi lại những điểm khác biệt và phạm vi hỗ trợ khi kết nối đến máy chủ Pabal.
Thông tin kết nối
| Mục | Giá trị |
|---|---|
| Địa chỉ | 122.34.175.215 |
| Cổng | 8443 (TCP) |
| DC | Cả DC 1–5 đều cùng một địa chỉ. Kết nối vào DC nào cũng được, thường dùng DC 2 |
| Giao thức | MTProto 2.0, API layer 216 |
| Kiểu truyền tải | Abridged, Intermediate, Padded Intermediate, Full — mỗi kiểu đều có bản làm rối (obfuscated2) |
| Khóa công khai máy chủ | server-key.pem · fingerprint 8724853375441383205 |
| api_id · api_hash | Không được kiểm tra. Điền giá trị nào cũng được |
Hiện chưa có truyền tải qua HTTP, WebSocket, cũng như MTProxy. Đồng hồ trên thiết bị client phải chính xác — số hiệu tin nhắn MTProto được tạo từ thời gian, nên nếu đồng hồ lệch nhiều, máy chủ sẽ bỏ các tin nhắn đó.
Khóa công khai của máy chủ
Khi kết nối lần đầu, client MTProto dùng khóa công khai RSA của máy chủ để mã hóa quá trình trao đổi khóa xác thực. Client Telegram có sẵn khóa công khai của Telegram bên trong, nên muốn kết nối đến Pabal thì phải nhúng khóa này thay vào (hoặc thêm vào). Chính khóa này ngăn máy chủ khác giả làm máy chủ Pabal.
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA4hH74xPQsUwr/pyXPdF4tVicYr6QbfeDrKC7mUOVrPLSL4FtmgGn
w+O4u6lVvOf3Udd1KY6+OL4fUZdMBlLzwsoGLoniiVR09dnvyXHE8LhQSS+i1LmI
oJbhQwXplLnUJf272fLXkD23e7ppKLkjYk+jeYObueCy5HYMSThklVeXEzbZVGZv
47o/mjU2vyFoRpa6wCIE4rpj1UIPtOMpekMI/TocIlGVJ+ch6cAVNxIDro53a1eG
/1oZRLQH4oViEGxeMMjBMY5gk5HPkZvjbqy4h8TjXEz7O5o0BRsSqG/OPtP/dRQV
X4ewPhj2WCU4e6l5X59ZKIcv4sQLOwClqQIDAQAB
-----END RSA PUBLIC KEY-----
curl -s -o server-key.pem https://pabal.me/docs/server-key.pem
Khóa này được tạo một lần khi máy chủ chạy lần đầu và không thay đổi. Hãy kiểm tra giá trị Loaded RSA key … (fingerprint …) trong log máy chủ có khớp với fingerprint ở trên không.
Kết nối bằng Telethon
Ví dụ dùng Telethon của Python để đăng nhập bằng tài khoản người dùng và nhắn tin qua lại. Hãy đăng ký tài khoản trong ứng dụng trước (xem bên dưới).
# pabal_client.py — pip install telethon==1.42.0
# Đặt server-key.pem (khóa công khai máy chủ đã tải ở trên) trong cùng thư mục
import asyncio
from telethon import TelegramClient, events
from telethon.crypto import rsa
rsa.add_key(open("server-key.pem").read(), old=False) # khóa công khai của máy chủ Pabal
client = TelegramClient("pabal", api_id=1, api_hash="0" * 32) # lưu trạng thái đăng nhập vào pabal.session
client.session.set_dc(2, "122.34.175.215", 8443)
@client.on(events.NewMessage(incoming=True))
async def show(event):
sender = await event.get_sender()
print(f"{sender.first_name}: {event.raw_text}")
async def main():
await client.start(phone=lambda: input("Số điện thoại (+849…): ")) # nhập mã một lần đầu tiên
me = await client.get_me()
print(f"Đã đăng nhập: {me.first_name} (id {me.id})")
await client.send_message("BotFather", "/help")
await client.run_until_disconnected()
asyncio.run(main())
- Hãy dùng Telethon 1.42. Đây là bản dùng layer 216. Các bản mới hơn cố đọc phản hồi theo layer cao hơn nên thất bại với
TypeNotFoundError. - Telethon đã chặn việc đăng ký tài khoản mới (
sign_up()). Hãy đăng ký trong ứng dụng, hoặc tự gọiauth.signUp. - Trạng thái đăng nhập được lưu vào tệp
pabal.session, nên từ lần sau sẽ không hỏi mã nữa. Tệp này là chìa khóa của tài khoản, hãy giữ nó cẩn thận.
Luồng đăng nhập
Giải thích sơ đồ
- Hai giai đoạn: phía trên là giai đoạn tạo khóa xác thực dùng để mã hóa (giao thức), phía dưới là giai đoạn đăng nhập gắn tài khoản vào khóa đó (API). Thư viện sẽ tự lo giai đoạn phía trên.
- Trạng thái đăng nhập gắn với khóa xác thực: dù mở nhiều phiên bằng khóa đã đăng nhập, tất cả đều ở trạng thái đăng nhập. Nếu mất khóa (xóa tệp phiên) thì phải đăng nhập lại.
- Mã được gửi theo đường nào là do người vận hành máy chủ quyết định: nếu là SMS hoặc quản trị viên chuyển thì nhận
sentCodeTypeSms; nếu là email thì nhậnsentCodeTypeSetUpEmailRequired, khi đó client hỏi địa chỉ email rồi gọiaccount.sendVerifyEmailCode(hàng giữa). - Nét đứt màu đỏ là đường của số mới: nếu mã đúng nhưng chưa có tài khoản, bạn nhận
authorizationSignUpRequired; nhập tên và gọiauth.signUplà hoàn tất đăng ký. Chỉ đăng ký được sau khi đã nhập đúng mã. - Bot không đi qua giai đoạn phía dưới mà đăng nhập bằng một lần gọi
auth.importBotAuthorization(token bot).
| Lỗi | Khi nào |
|---|---|
PHONE_NUMBER_INVALID | Số sai, hoặc là số mới trong lúc máy chủ đang đóng đăng ký mới |
PHONE_NUMBER_BANNED | Số đã bị người vận hành chặn, hoặc số của tài khoản bị tạm khóa (nếu bị xóa khi đang tạm khóa thì mặc định 1 năm — người vận hành có thể kéo dài hoặc đặt vô thời hạn) |
FLOOD_WAIT_n (420) | Yêu cầu mã quá thường xuyên. Thử lại sau n giây |
PHONE_CODE_INVALID | Mã sai (vượt quá số lần cho phép thì bị khóa) |
PHONE_CODE_EXPIRED | Mã đã hết hạn hoặc bị khóa, hoặc phone_code_hash không xác định — bắt đầu lại từ sendCode |
EMAIL_INVALID, EMAIL_NOT_ALLOWED | Địa chỉ email sai / tài khoản đã tồn tại nhưng đây không phải email đăng nhập đã đăng ký |
AUTH_KEY_UNREGISTERED (401) | Gọi phương thức cần đăng nhập bằng khóa chưa đăng nhập |
Trên máy chủ mà người vận hành bật số thử nghiệm, các số có dạng +99966XYYYY đăng nhập được bằng mã XXXXX (lặp X năm lần) mà không cần gửi mã thật. Tính năng này chỉ dùng cho máy chủ phát triển và bị tắt trên máy chủ vận hành thật.
Nhận update
- Thời gian thực: khi kết nối đang mở, máy chủ gửi ngay tin nhắn mới, sửa, xóa dưới dạng
updateShortMessage,updates. Phiên đã gửi yêu cầu nhận kết quả qua phản hồi RPC, nên cùng nội dung đó sẽ không được đẩy tới phiên ấy thêm lần nữa. - pts: mỗi thay đổi của từng người dùng được gắn một số thứ tự (pts). Nếu pts nhận được có khoảng trống thì client đã bỏ lỡ điều gì đó.
- Bắt kịp: ghi nhớ pts hiện tại bằng
updates.getState, và khi kết nối lại thì dùngupdates.getDifference(pts, date, qts)để nhận tin nhắn mới, lượt xóa trong khoảng đó cùng người dùng và nhóm liên quan. Nếu pts mà client đang giữ vượt trước máy chủ (ví dụ khi dữ liệu máy chủ đã bị khởi tạo lại), bạn sẽ nhậndifferenceTooLong, khi đó hãy tải lại danh sách trò chuyện. - Thông báo đẩy — Android: ứng dụng Android không có kết nối được đánh thức bằng push của Firebase. Khi ứng dụng đăng ký bằng
account.registerDevice(token_type2 = token FCM,secret= khóa thiết bị 256 byte), máy chủ mã hóa tin nhắn và cuộc gọi mới bằng khóa thiết bị đó rồi gửi qua FCM, còn ứng dụng khi thức dậy sẽ bắt kịp bằngupdates.getDifference. Thông báo đẩy chỉ đến được những ứng dụng build bằng dự án Firebase của người vận hành máy chủ. - Thông báo đẩy — iPhone: ứng dụng iPhone đăng ký hai thứ bằng cùng yêu cầu đó —
token_type1 (token thông báo APNs) và 9 (token VoIP của PushKit);secretcủa cả hai đều là khóa thiết bị 256 byte của tài khoản đó. Tin nhắn mới được gửi thành thông báo APNs: phần chữ bên ngoài mà Apple thấy được chỉ là tên ứng dụng và một câu không có nội dung như "Bạn có thông báo mới", còn tin nhắn được mã hóa bằng khóa thiết bị và đặt trongp, rồi phần mở rộng thông báo (Notification Service Extension) của ứng dụng giải mã và hiển thị. Cuộc gọi được gửi bằng push VoIP để hiện màn hình cuộc gọi CallKit (từ bản build mà người vận hành đã bật VoIP; trước đó thì gửi thành thông báo), còn những gì đã đọc hoặc đã xóa trên thiết bị khác được báo bằng push chạy nền. Thông báo đẩy chỉ đến được những ứng dụng được ký bởi cùng nhóm (team) với khóa APNs của người vận hành máy chủ và có cùng bundle ID. Cáctoken_typekhác chỉ được trả lờiboolTruevà không được gửi gì. - Các thư viện như Telethon tự lo toàn bộ quá trình này.
ID và peer
| Đối tượng | ID | Ghi chú |
|---|---|---|
| Người | Từ 100001 | peerUser. @BotFather là 100000 |
| Bot | Cùng hệ thống số với người | user.bot = true. Dãy số ở đầu token là ID của bot |
| Nhóm cơ bản | Từ 1000001 | peerChat. Trong Bot API hiển thị là số âm (-chat_id) |
| Tin nhắn | Một dãy số chung cho toàn máy chủ | Trong trò chuyện 1:1, hai bản sao mang cùng một số, nên các yêu cầu chỉ nhận số tin nhắn mà không có peer (messages.getMessages, messages.deleteMessages) đều chỉ đến cùng một tin nhắn đối với cả hai người. Chỉ kênh là đếm riêng từ 1 |
Hãy lưu nguyên giá trị access_hash mà máy chủ cấp để dùng về sau (nó đi kèm khi tra cứu tên người dùng, trong danh sách trò chuyện và trong update).
Tệp
- Tải lên: tải từng phần bằng
upload.saveFilePart(mỗi phần tối đa 512KB, tối đa 4.000 phần) và tham chiếu bằnginputFileUploaded…. Tệp lớn hơn 10MB được tải lên bằngupload.saveBigFilePart— vì bạn báo trước số phần nên nếu máy chủ không nhận kích thước đó, nó từ chối ngay bằngFILE_TOO_BIGtrước khi bạn gửi hết. Các phần được ghi xuống đĩa ngay khi đến và chỉ được ghép lại thành một tệp khi có tin nhắn trỏ tới tệp đó. - Gửi: dùng
messages.sendMediavớiinputMediaUploadedPhoto(ảnh mới),inputMediaPhoto(ảnh đã có trên máy chủ),inputMediaUploadedDocument(tệp mới),inputMediaDocument(tệp đã có trên máy chủ). Các phương tiện khác trả vềMEDIA_INVALID. Bạn cũng có thể tải lên trước mà chưa gửi bằngmessages.uploadMedia(media nó trả về sẽ được gửi nguyên như vậy về sau), cònmessages.sendMultiMediathì được chấp nhận nhưng các mục đi từng cái một, không gộp thành nhóm (không có grouped_id). - Nhận: dùng
upload.getFilevớiinputPhotoFileLocation(ảnh trong tin nhắn),inputDocumentFileLocation(tệp trong tin nhắn),inputPeerPhotoFileLocation(ảnh đại diện). Tối đa 1MB mỗi lần. Bên nhận cũng chỉ đọc đúng đoạn được yêu cầu chứ không nạp cả tệp vào bộ nhớ. - Ảnh đại diện:
photos.uploadProfilePhoto,photos.updateProfilePhoto,photos.getUserPhotos,photos.deletePhotos. - Ảnh chỉ được lưu ở một kích thước gốc (không tạo ảnh thu nhỏ riêng). Tệp thì được giữ nguyên vẹn, và các
documentAttribute*do bên gửi đính kèm được chuyển nguyên byte tới bên nhận — máy chủ không cần hiểu độ dài video hay dạng sóng của âm thanh mà vẫn chuyển đi y nguyên.
Phạm vi hỗ trợ
Máy chủ có bộ xử lý cho 469 phương thức của layer 216 và tất cả đều đọc được yêu cầu, nhưng những phương thức đã được kiểm chứng trọn vẹn bằng client thật là các phương thức dưới đây. Các phương thức còn lại trả lời đúng định dạng nhưng nội dung có thể rỗng hoặc không được ghi lại.
| Lĩnh vực | Phương thức đã kiểm chứng |
|---|---|
| Kết nối | initConnection, invokeWithLayer, help.getConfig, auth.bindTempAuthKey (khóa tạm thời PFS), auth.exportAuthorization/importAuthorization |
| Đăng nhập | auth.sendCode, auth.signIn, auth.signUp, auth.logOut, auth.importBotAuthorization, account.sendVerifyEmailCode |
| Người dùng, danh bạ | users.getUsers, users.getFullUser, contacts.resolveUsername, contacts.importContacts, contacts.search |
| Tin nhắn | messages.sendMessage, messages.sendMedia (ảnh, tệp), messages.getHistory, messages.getDialogs, messages.getMessages, messages.editMessage, messages.deleteMessages |
| Nhóm | messages.createChat, messages.deleteChatUser, messages.editChatTitle (messages.addChatUser chỉ mới kiểm chứng bằng ứng dụng chính thức) |
| Bot | messages.getBotCallbackAnswer, messages.setBotCallbackAnswer, tin nhắn có gắn nút (reply_markup) |
| Update | updates.getState, updates.getDifference, đẩy (push) thời gian thực |
| Tệp, ảnh | upload.saveFilePart, upload.saveBigFilePart (trên 10MB), upload.getFile, photos.* (ở trên) |
Chúng tôi cũng đã kiểm chứng Telegram Desktop chính thức 6.2.6 hoạt động không cần sửa đổi, từ đăng ký, đăng nhập, trò chuyện, ảnh, nhóm cho đến kết nối lại. Khoảng 60 phương thức mà ứng dụng gọi khi khởi động được kiểm tra định dạng phản hồi riêng.
Những gì thêm sau đó — danh sách thiết bị và đăng xuất thiết bị (account.getAuthorizations, account.resetAuthorization, auth.resetAuthorizations), xuất dữ liệu của ứng dụng máy tính (account.initTakeoutSession, invokeWithTakeout, invokeWithMessagesRange, account.finishTakeoutSession — mỗi tài khoản ba lần bắt đầu mỗi ngày, vượt quá thì 420 TAKEOUT_INIT_DELAY_n), đổi số (account.sendChangePhoneCode, account.changePhone — 400 PHONE_CHANGE_DISABLED khi người vận hành chưa bật, BOT_METHOD_INVALID với bot) — đã được kiểm chứng bằng các bài thử của máy chủ; chưa kiểm tra trọn vẹn bằng ứng dụng thật.
Lỗi
Lỗi được trả về dưới dạng rpc_error chuẩn (error_code + error_message). error_message luôn có dạng chữ hoa, chữ số và dấu gạch dưới (PEER_ID_INVALID), và khi cần sẽ có thêm : mô tả phía sau.
| Mã | Ý nghĩa |
|---|---|
400 | Yêu cầu sai — PEER_ID_INVALID, MESSAGE_ID_INVALID, MEDIA_INVALID, USERNAME_NOT_OCCUPIED … |
401 | Cần đăng nhập — AUTH_KEY_UNREGISTERED |
403 | Không có quyền — ví dụ nhóm mà bạn không phải thành viên |
406 | Chưa được phép lúc này — thiết bị mới đăng nhập chưa đủ 24 giờ cố đăng xuất thiết bị khác: FRESH_RESET_AUTHORISATION_FORBIDDEN |
420 | FLOOD_WAIT_n — chờ n giây |
500 | Lỗi nội bộ máy chủ |
Lỗi truyền tải -404 | Máy chủ không biết khóa xác thực này — tạo khóa mới rồi đăng nhập lại (khóa vĩnh viễn) hoặc gắn lại (khóa tạm thời) |
API đồng hồ
/api/watch/v1/ của máy chủ là điểm vào HTTPS JSON chỉ dành cho ứng dụng Apple Watch của Pabal. Nó tồn tại riêng vì đồng hồ không dùng được MTProto; đây không phải đặc tả công khai và đang được chuẩn bị, nên có thể thay đổi mà không báo trước. Nếu muốn viết chương trình kết nối tới Pabal, hãy dùng MTProto ở trang này. Người vận hành máy chủ xem Cài đặt máy chủ — Điểm vào của Apple Watch.
Những gì chưa có
- Kênh và siêu nhóm (
channels.*có trả lời nhưng không hiển thị đúng trong ứng dụng), trò chuyện bí mật, gọi nhóm - Tin nhắn video và tin nhắn thoại phát ngay trong ứng dụng, album hiện ra thành một nhóm (grouped_id), sticker, ảnh thu nhỏ (tệp chỉ có bản gốc)
- Xác minh hai bước (SRP) — không thể thiết lập, và các thao tác cần xác minh hai bước đều bị từ chối
- Truyền tải qua HTTP và WebSocket, MTProxy, gửi
msgs_ack, xoay vòng định kỳ salt của máy chủ (salt sai được trả lời bằngbad_server_salt) - Chia ra nhiều máy chủ — một máy chủ đảm nhận cả DC 1–5
Để kết nối ứng dụng Telegram chính thức với Pabal
Ứng dụng Telegram nhúng địa chỉ máy chủ và khóa công khai vào bên trong lúc build. Vì vậy không đổi được trong màn hình cài đặt mà phải sửa mã nguồn rồi build lại. Ứng dụng Pabal (Pabal.app) chính là được làm như vậy. Nếu bạn là người vận hành máy chủ, hãy xem Cài đặt máy chủ — kết nối ứng dụng.