Tích hợp client AeroNyx Chat Relay

AeroNyx19 tháng 6, 20264 phút đọc34 lượt xem

Client contract cho blind relay, presence giữa mutual contacts, reciprocal read receipts, encrypted reactions, offline queue và resumable media.

Contract chính thức về frame và media API cho đội App, frontend, backend và coding agent xây client AeroNyx. Relay chỉ route ciphertext và không hiểu nội dung.

Nguyên tắc riêng tư không thể thay đổi

Relay không được phân tích, lưu hay suy ra chat/reaction plaintext, voice/media, key, nonce, waveform, filename, transcript, MemChain, packet payload, DNS, destination, URL, history, wallet traffic hoặc private seed. Client mã hóa E2E trước transport.

E2E content nằm trong payload_b64payload_sig. Visible metadata chỉ gồm type, IDs, receiver/group, timestamps, delivery state, blob size/expiry, access mode và counters.

Nguyên tắc riêng tư của trạng thái trực tuyến

Online và last seen chỉ hiện khi P2PContact hoạt động theo cả hai chiều. Backend kiểm tra hai phía để ngăn public key scan. Presence và exact last seen có thể tắt riêng.

Hidden result không có online hay last_seen_ts; trả reason=not_mutual_contact hoặc reason=presence_hidden.

API quyền riêng tư hồ sơ

Client đọc profile privacy flags khi kết nối và giữ UI phù hợp backend enforcement. PATCH nhận nested privacy và top-level fields cũ.

http
GET /api/relay/profile/
PATCH /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
json
{
  "privacy": {
    "presence_enabled": true,
    "last_seen_enabled": false,
    "read_receipts_enabled": false
  }
}

Khung trạng thái trực tuyến

Chỉ gửi presence_subscribe cho contacts. Khi last_seen_enabled=false, hiển thị trạng thái gần đúng hoặc ẩn thời gian; không suy ra exact status từ tín hiệu khác.

json
{
  "type": "presence_subscribe",
  "pubkeys": ["contact-pubkey-a", "contact-pubkey-b"]
}
json
{
  "type": "presence_subscribe_ack",
  "updates": [{
    "pubkey": "contact-pubkey-a",
    "visible": true,
    "presence_visible": true,
    "last_seen_visible": true,
    "online": true,
    "last_seen_ts": 1780000000,
    "reason": "allowed"
  }],
  "server_ts": 1780000001
}

Quy tắc biên nhận đã đọc đối ứng

Read receipts là reciprocal: người tắt không gửi message_read và không hiển thị peer read. Nếu một bên tắt hoặc không phải mutual contact, backend suppress frame. Chỉ có metadata.

json
{
  "type": "message_read",
  "msg_id": "message-id",
  "receiver_pubkey": "original-sender-pubkey",
  "timestamp": 1780000200
}
json
{
  "type": "message_read_ack",
  "msg_id": "message-id",
  "delivered": false,
  "suppressed": true,
  "reason": "receiver_read_receipts_disabled"
}

Reasons: client_disabled, not_mutual_contact, reader_read_receipts_disabled, receiver_read_receipts_disabled; offline pull dùng cùng gate.

Phản ứng biểu tượng cảm xúc

Reaction cũng là E2E ciphertext. Relay route theo receiver/membership, deduplicate bằng reaction_id, dùng store-and-forward khi offline. Aggregate state thuộc client.

json
{
  "type": "message_reaction",
  "msg_id": "target-message-id",
  "receiver_pubkey": "peer-pubkey",
  "reaction_id": "unique-reaction-event-id",
  "timestamp": 1780000300,
  "payload_b64": "e2e-ciphertext",
  "payload_sig": "ed25519-signature"
}

Discriminant 12; reaction_id là idempotency/offline ACK key. ACK message_reaction_ack; group dùng group_message_reaction, group_id, key_version.

Mô hình đối tượng phương tiện mã hóa

Voice, image, video, file được mã hóa trước upload. blob_id, key, nonce, duration, waveform, display filename, preview metadata nằm trong relay_send.payload_b64, không ở blob API plaintext fields.

json
{
  "kind": "voice",
  "blob_id": "blob-uuid",
  "key_b64": "inside-e2e-envelope",
  "nonce_b64": "inside-e2e-envelope",
  "duration_ms": 43000,
  "waveform": [0, 3, 8, 6, 2],
  "media_type": "audio/ogg; codecs=opus",
  "file_size": 7340032
}

Tải lên đơn giản đối tượng mã hóa

Dùng multipart cho short voice và small image. Server chỉ nhận encrypted bytes; TTL mặc định 7 ngày, policy 1–30. Download bằng unguessable capability hoặc authenticated P2P key.

http
POST /api/relay/blob/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: multipart/form-data
fieldrequiredvalue
filetrueciphertext
media_kindfalsevoice, image, video, file, avatar, other
media_typefalseMIME
ttl_daysfalse1..30
access_modefalsecapability, authenticated
allowed_downloadersfalseJSON P2P pubkey array

Simple limit 10 MB; quá giới hạn trả HTTP 413, error_code=blob_too_large, chunked_max_bytes=104857600.

Tải lên có thể tiếp tục đối tượng mã hóa

Trên simple limit dùng chunk session. Ciphertext total tối đa 100 MB; retry cùng chunk index là an toàn. Lưu local upload_id, chunk_size, completed indexes.

1. Tạo phiên tải lên

http
POST /api/relay/blob/session/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
json
{
  "total_size": 7340032,
  "chunk_size": 1048576,
  "media_type": "audio/ogg",
  "media_kind": "voice",
  "ttl_days": 7,
  "access_mode": "authenticated",
  "allowed_downloaders": ["receiver-pubkey"]
}

2. Tải các phần dữ liệu

http
PUT /api/relay/blob/session/{upload_id}/chunk/{chunk_index}/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/octet-stream

Default chunk 1 MB, maximum 4 MB; retry cùng index thay chunk cũ và idempotent.

3. Tiếp tục sau gián đoạn mạng

http
GET /api/relay/blob/session/{upload_id}/
Authorization: Relay <pubkey>:<timestamp>:<signature>

Đọc missing_chunks, chỉ gửi index thiếu. Session hiệu lực 24 giờ.

4. Hoàn tất tải lên

http
POST /api/relay/blob/session/{upload_id}/complete/
Authorization: Relay <pubkey>:<timestamp>:<signature>

Complete kiểm tra chunks và total bytes; safe retry trả final blob cũ, không tạo duplicate.

5. Hủy tải lên

http
DELETE /api/relay/blob/session/{upload_id}/
Authorization: Relay <pubkey>:<timestamp>:<signature>

Tải xuống đối tượng mã hóa

Capability không cần RelayAuth vì UUID là bearer capability. Authenticated cần chữ ký và chỉ uploader hoặc allowed_downloaders được truy cập. Expired blob được xóa khi access.

http
GET /api/relay/blob/{blob_id}/
HTTPerror_code
400blob_id_invalid
401auth_required
403download_forbidden
404blob_not_found
410blob_expired
413blob_too_large, blob_total_size_too_large, chunk_too_large
409upload_incomplete

Hướng dẫn UX cho client

Small file dùng simple upload, trên max_bytes mới dùng chunks. Sau App restart đọc missing_chunks. Giữ secrets trong E2E; biến 410 blob_expired thành resend action.

Thứ tự tích hợp AI agent

Agent triển khai RelayAuth, profile privacy, presence UI, reciprocal reads, reaction idempotency, simple blob, chunk resume, rồi relay_send reference. Không tạo server-side chat search.

Phân phối hai bước nhảy đã xác minh

Eligible ChatRelay có thể chọn network-diverse two-hop path. Source chỉ tính delivery sau khi xác minh signed receipt của expected terminal; middle node chỉ route ciphertext.

Node discovery và encrypted delivery có thể kiểm chứng