wechat-protocol
Blocking native protocol library for the Linux 4.1.13.26 profile. This is Rust protocol code using OpenSSL primitives; it does not execute Node or load an official WeChat executable/library. Async callers must use a blocking worker.
Start with NativeClient
Most server operations are methods on
NativeClient.
The crate-level Functions list mainly contains helper functions.
| Task | API |
|---|---|
| Login | start_qr_login, poll_login, complete_login |
| Receive | sync, sync_scene, heartbeat, push_connection |
| Send | send_text, send_share, send_quote, send_file, send_image, send_video, send_voice |
| Contacts | lookup_contacts, lookup_room, init_contacts |
| Lower-level operations | wire, media, group request builders and response decoders |
AccountState holds the accepted credentials and is passed mutably because
responses can update credentials and routing. The daemon's native upstream
adapter calls these APIs; it adds account coordination, recovery and profile
writeback above them. Some operations use a request builder, a client RPC method
and a decoder instead of one convenience method.
From a repository checkout, run one of these examples:
Each requests a fresh QR login for a test account, prints a private temporary
PNG path to open and waits for phone approval. The QR is removed after login;
credentials stay in memory. send_text submits once and prints the receipt;
sync_once summarizes one page without saving history or a cursor. These are
standalone examples, not consumers of an existing daemon session. A fresh login
may replace another active desktop login. --help makes no network requests.
The sender requires an exact username rather than a contact's display name. A task ID is not a server idempotency guarantee: investigate an uncertain send before running it again. Production applications must save the operation and its timestamp before submitting and keep secret account state encrypted.
See the Rust libraries guide for a short text-send example using an already authenticated account.
Transport and supported operations
The transport authenticates the configured public server pins, handshake Finished values, every GCM record, business signatures (credential 1), and business GCM envelopes before decoding service messages. No insecure peer or signature-bypass setting exists. Routing redirects are accepted only from authenticated responses and are restricted to supported official domain suffixes.
The conditional LAN login challenge is experimental. Notification field17 is an
SKBuffer containing a non-store risk extension; state11 starts CGI22312 with
local IPv4 address/port entries, the current login identifier and a fresh
16-byte SKBuffer. A temporary TCP listener replies with a big-endian u32 total
length followed by JSON containing the returned opaque token and string
scene: "xwechat". It never grants authorization; normal polling and final
authentication still apply. Listener/token state is never serialized and is
bounded by cancellation and the attempt deadline. Upload submission is attempted
once for an issued login identifier; an uncertain upload is not retried by the
repeatable polling path. poll_login_guarded lets an owner supply an earlier
deadline and nonblocking cancellation callback. This path has offline fixtures
and simulated-phone coverage; live phone/server acceptance remains unverified.
The crate includes QR login, QR polling/approval exchange, saved-device phone approval, trusted AutoAuth renewal, NewSync cursor merging, heartbeat, text send, known contact and group lookups, contact bootstrap pages, avatar bytes and voice download chunks. The CDN module implements authenticated routing bootstrap, encrypted range downloads, ordinary-file uploads with an initial 32 MiB plaintext ceiling, supplied JPEG image variants and MP4/thumbnail uploads. Metadata finalizers cover files, images, videos and bounded SILK voice notes. The bundled portable SILK SDK encodes fresh mono 16 kHz audio and decodes incoming voice bytes without loading an official client codec. A separate core layer owns resizing, input conversion, durable jobs, upload readback and uncertain-send handling. Sticker retrieval is restricted to the verified original-byte CDN host, with pinned public DNS, redirect refusal, MD5 validation and bounded full image decoding.
The native ordinary-file implementation selects the four-phase
apply/uploadblock/fin/complete carrier when PKCS#7 ciphertext reaches 25 MiB.
This uses the reference's supported multiphase policy for the 16-byte padding
band below 25 MiB plaintext; the reference's default binary-stream uploadbig
carrier is not implemented. Plaintext above 25 MiB selects filetype 7 and final
app-message field 6=7. Upload and download independently select the authenticated
safe C2C routing table with their respective operation selectors; upload routing
type 7 is separate from the request's actual filetype 5 or 7. Filetype7 readback uses
downloadbig, exact encrypted and plaintext sizes, source MD5 and caller-owned
SHA-256 verification before final submission. Ordinary image/video/voice upload
limits remain 26,214,383 bytes.
NativeClient::reserve_file_upload submits CGI6691 once using a separate,
caller-persisted progress ID. Its FileUploadReservation contains secret token
material with redacted Debug and zeroization; protect it with the upload key,
source and final client ID. send_file_with_reservation emits the reservation
metadata and correlates the final CGI222 receipt. A response failure must not
cause a new reservation or final send. Existing no-reservation APIs retain their
previous wire form. Large-file cache hits and server retry/routing controls are
rejected rather than guessed. The path has synthetic schema/transfer tests and
an isolated native 32 MiB File Transfer PDF accepted with exact readback,
recipient opening and complete local writeback. Cold CLI/SDK byte and range
checks passed; recipient-exported SHA-256 remains unavailable.
See FEATURES.md for the current validation record.
Call codecs
The calls module includes offline signaling and
incoming notification envelopes, personal Invite/Cancel/LiveSync codecs, selected
app-session negotiation and relay packet codecs under calls. These prepare and
validate owned bytes with account-generation bindings. The module alone does
not establish voice or video calls.
There is no call transport, codec negotiation, microphone/camera access or
NativeClient call method. Keys, media framing and session lifetimes must be
verified before connecting these building blocks to a live transport. Existing
voice-note and video-file methods remain attachment operations.
Results preserve unsigned 64-bit message IDs as decimal strings. Unknown command payloads and contact fields remain available as original bytes. All write/send methods submit once. A response failure after submission is an uncertain outcome; the service owns durable intents and must not resend blindly.
AccountState and LoginAttempt are serializable secret state, with redacted
Debug implementations and zeroization on drop. Store them only in the encrypted
service vault. Do not return their serialized representation from public APIs.
The optional 32-byte official profile password and raw auth/account/network/AX
sections stay in that protected state. AuthSect field 9 changes the password only
when the native authentication update gate is set and the field is present.
AccountState::from_baseline_json converts an explicitly selected private
standalone checkpoint; it does not discover official profiles or read their files.
Tests include offline synthetic and known-answer checks. A separately authorized isolated AMD64 validation also accepted one trusted AutoAuth renewal after an authenticated session-expired response, a heartbeat and one NewSync page (125 commands, including 117 AddMsg records), using this Rust implementation with zero QR requests, phone prompts or sends. Original account/checkpoint files were unchanged. This is one test account/build result, not universal server acceptance.
The media network methods follow previously verified native recipes. Expanded
multi-range MP4 uploads still require isolated live validation. Group sends,
group creation, sticker sends, active push association and a long-lived longlink
reconnect supervisor remain outside the verified scope. Avatar bytes
still need full bounded image decoding in the caller. QR images receive bounded
PNG-header checks only; supplied JPEG upload variants are fully decoded with
pixel/allocation limits. MP4 preparation validates container signature, not full
audio/video decoding. Voice finalization accepts format-4 SILK notes of up to 60
seconds and 186,010 encoded bytes, a bound derived from the bundled 16 kbit/s,
20 ms profile with 1.5x rate headroom; the bundled encoder can produce those from
fresh PCM. A short-link request travels in one MMTLS record, so a note above
32 KiB is submitted as consecutive uploadvoice offset/length ranges of one client
message ID, with the end flag on the last range and the server message ID from an
earlier range carried forward. That multi-range path has offline fixtures only and
still requires live validation. It does not record a microphone.
NewSync continuation follows raw returned versus sent cursor bytes; committed
cursors use the unsigned per-key maximum merge (or special -2006 replacement).
wire::decode_add_message retains fields 6/7 as numbered values. Present field 13
is also exposed as server_sequence after 319 exact retained-message joins all
matched the independently saved official server_seq value. Missing field 13
remains None, not zero, and this correlation does not validate arbitrary message
classes for official database writes. A group's actual member sender remains
unresolved until separate envelope/member validation. The supported incoming
path is bounded heartbeat selector hints (selector & 7) followed by NewSync
scene 7; a transport-ready longlink alone does not prove account push association.
The HTTP carrier is port 80 with authenticated MMTLS data. System DNS resolution is outside a strict end-to-end deadline; subsequent connect/read/write and HTTP requests are bounded. A caller cancellation does not stop an in-progress blocking send, so ownership and completion must remain with the service actor.
Run cargo test -p wechat-protocol from the native Rust workspace. See NOTICE
for the public fixture license and pin provenance.