AeroNyx Sohbet Aktarıcısı İstemci Entegrasyonu
AeroNyx Sohbet Aktarıcısı için entegrasyon başvuru kaynağı: WebSocket kimlik doğrulaması, mühürlü birebir ve grup mesajları, çevrimdışı teslim, teslim ve okundu bilgileri, tepkiler, çevrimiçi durumu, şifrelenmiş ekler, anlık bildirimler ve hız sınırları.
Entegrasyon istemi oluştur
İstemci teknolojisini ve görevi seçip kodlama yardımcınıza kopyalayın. İstem yerel olarak oluşturulur; yapay zekâ hizmetine gönderilmez.
Oluşturulan istem
Bu belge, AeroNyx Sohbet Aktarıcısı (Chat Relay) için entegrasyon başvuru kaynağıdır: api.aeronyx.network adresindeki bu WebSocket ve HTTPS hizmeti, AeroNyx kimlikleri arasında uçtan uca şifrelenmiş birebir (1:1) mesajları, grup mesajlarını, teslim ve okundu bilgilerini, tepkileri, çevrimiçi durumunu ve şifrelenmiş ekleri taşır.
Belge, AeroNyx uyumlu istemciler, botlar ve hizmetler geliştiren mühendisler ile bunları uygulayan yapay zekâ kodlama ajanları için yazılmıştır. Bu sayfadaki her çerçeve, alan ve sınır, Ekim 2026 itibarıyla üretimdeki aktarıcıyı ve AeroNyx App'i yansıtır.
Sohbet Aktarıcısı merkezî teslim yoludur. Merkeziyetsiz düğüm yoluyla (onion yönlendirme ve anonim posta kutuları; bkz. "Doğrulanmış iki atlamalı teslim") birlikte çalışır; bir istemci her ikisini de kullanabilir. WebSocket kullanmayan, istek/yanıt tabanlı bir HTTPS entegrasyonu için Merkezî Sohbet HTTPS API v1 sayfasına bakın.
Güven modeli
Aktarıcı içeriğe kördür. İstemciler her şeyi aktarıcıya ulaşmadan önce şifreler ve imzalar; aktarıcı ise yalnızca opak şifreli metni yönlendirir, kuyruğa alır ve hız sınırı uygular.
Aktarıcı şunları hiçbir zaman almaz:
- açık metin hâlinde mesaj metni, tepki emojisi, düzenlemeler veya grup yükleri
- sohbet anahtarları, grup anahtarları, ek anahtarları veya nonce değerleri
- ek içerikleri, dosya adları, küçük resimler, dalga formları veya dökümler
- özel kimlik anahtarları
Aktarıcı ise teslim meta verilerini görür; entegrasyonu yapanlar bu verileri operatör tarafından görülebilir kabul etmelidir:
- gönderici ve alıcı açık anahtarları, grup kimlikleri ve mesaj kimlikleri
- zaman damgaları, yük boyutları ve teslim, alındı ve okundu durumu
- çevrimiçi durumu, ön plan durumu ve yazıyor göstergeleri (açık metin çerçeveler olarak gönderilir)
- arama sinyalleşmesi meta verileri (oda adı, arama kimliği, video bayrağı)
- ekin şifreli metin boyutu, bildirilen medya türü ve sona erme zamanı
contact_requestbayrağı ve IP düzeyindeki bağlantı meta verileri
İçeriğin gizliliği, aktarıcıdaki erişim denetiminden değil uçtan uca şifrelemeden gelir. Tasarımınızı buna göre yapın: depolanmış bir şifreli metni ele geçiren saldırgan yine de onu okuyamamalıdır.
Kimlikler ve anahtarlar
Bir AeroNyx sohbet kimliği, bir Ed25519 anahtar çiftidir. 64 küçük harfli onaltılık karakter olarak yazılan 32 baytlık açık anahtar, adrestir. Anahtarları cihazda üretin ve özel anahtarı hiçbir yere göndermeyin.
Bir kimlik çiftinden iki anahtar türetilir:
- Sohbet anahtarı (1:1).
HKDF-SHA256(salt = empty, ikm = X25519(my_secret, peer_public), info = "AERONYX-P2P-KEY", length = 32); burada her iki Ed25519 anahtarı da X25519'a dönüştürülür (gizli anahtar içinSHA-512(seed)[0..32]kırpılarak (clamping), açık anahtar için Edwards'tan Montgomery'ye dönüşümle). İki taraf da aynı anahtarı türetir. - Mesaj imzaları. Bu sayfada tanımlanan bayt dizilerinin tam hâli üzerinde, kimlik anahtarıyla Ed25519.
Çerçevelerdeki açık anahtarlar için her zaman küçük harfli onaltılık gösterim kullanın. Aktarıcı her kuyruk anahtarında büyük/küçük harf normalleştirmesi yapmaz.
Kimlik doğrulama
RelayAuth imzası
WebSocket oturum açma işlemi ve kimlik doğrulaması gerektiren her HTTPS uç noktası aynı imzayı kullanır:
digest = SHA256("AeroNyx-RelayAuth-v1" || pubkey[32] || timestamp as u64 little-endian)
signature = Ed25519(identity_key, digest)
"AeroNyx-RelayAuth-v1", sonlandırıcı içermeyen 20 ASCII bayttır. timestamp Unix saniyesi cinsindendir ve sunucu saatinden en fazla 300 saniye sapabilir.
İmza yalnızca kimliği ve zamanı bağlar. Yöntemi, yolu, gövdeyi veya bağlantıyı bağlamaz ve nonce içermez. Her istek için yeni bir zaman damgası üretin, imzayı yalnızca TLS üzerinden gönderin ve asla günlüğe kaydetmeyin.
HTTPS başlığı
Authorization: Relay <pubkey-hex>:<timestamp>:<signature-hex>
Başarısız bir denetim, {"success": false, "error": "<reason>"} ile birlikte HTTP 401 döndürür. Nedenler arasında missing_auth_header, malformed_auth_header, invalid_timestamp, timestamp_expired, invalid_pubkey ve invalid_signature bulunur.
WebSocket bağlantısı
Uç nokta
wss://api.aeronyx.network/ws/relay/
Yerel istemciler Origin başlığı olmadan bağlanır. Tarayıcılar izin verilen bir kaynaktan bağlanmalıdır; başka herhangi bir kaynak veya bilinmeyen bir Host söz konusu olduğunda bağlantı 1008 koduyla kapatılır.
Oturum açma
Sunucu soketi kabul eder, ardından 30 saniye içinde bir auth çerçevesi bekler:
{
"type": "auth",
"pubkey": "<64 hex>",
"timestamp": 1780000000,
"signature": "<128 hex>"
}
Başarılı yanıt:
{ "type": "auth_ack", "session_id": "<uuid>", "server_ts": 1780000001 }
Saat farkını tahmin etmek için server_ts değerini kullanın; mesaj zaman damgaları da aynı ±300 saniyelik pencereye göre denetlenir.
auth_ack sonrasında sunucu kalp atışını başlatır, bağlantıyı kanallarına abone eder ve çevrimdışı kuyruğu hemen yeniden oynatır (bkz. "Çevrimdışı teslim").
Başarısızlık durumunda {"type": "auth_error", "reason": "<reason>"} gönderilir ve soket 4001 koduyla kapatılır. Nedenler: missing_fields, timestamp_expired, invalid_pubkey, invalid_signature_length, invalid_signature_encoding, invalid_signature, internal_error. Oturum açma zaman aşımında timeout nedeni gönderilir ve bağlantı 4002 koduyla kapatılır.
Oturum açmadan önce gelen diğer tüm çerçevelere authentication_required nedeniyle auth_error yanıtı verilir; soket açık kalır.
Kalp atışı ve ön plan durumu
| Yön | Çerçeve | Davranış |
|---|---|---|
| sunucu → istemci | 30 sn'de bir {"type":"ping"} | {"type":"pong"} ile yanıtlayın. |
| istemci → sunucu | {"type":"ping"} | Sunucu {"type":"pong"} ile yanıtlar. |
| istemci → sunucu | {"type":"presence_state","foreground":true} | Bu bağlantıyı etkin olarak işaretler. |
| istemci → sunucu | {"type":"presence_state","foreground":false} | Bağlantıyı arka planda olarak işaretler; böylece aktarıcı yeni mesajlar için anlık bildirim gönderebilir. |
Aktarıcı bir kimliği yalnızca bağlantısı en az 90 saniyede bir ping, pong veya foreground: true içeren presence_state gönderdiği sürece çevrimiçi kabul eder. AeroNyx App ön plandayken 15 saniyede bir ping gönderir ve üçten fazla pong yanıtı kaçırılırsa bağlantıyı kopmuş sayar.
Uzun ömürlü bağlantılar en az 24 saatte bir yeniden bağlanmalıdır. Bir bağlantı canlı çerçeveleri sessizce almayı bıraktığında mesajlar asla kaybolmaz, çünkü her mesaj ayrıca kuyruğa alınır ve oturum açıldığında yeniden oynatılır; ancak canlı teslim yalnızca yeniden bağlandıktan sonra sürer.
Çerçeve kuralları
- Yalnızca metin çerçeveleri; her çerçevede tek bir JSON nesnesi. İkili çerçeveler yok sayılır.
- Azami çerçeve boyutu 1.048.576 karakterdir. Daha büyük çerçeveler
{"type":"error","reason":"message_too_large"}ile reddedilir. Çerçevenin geri kalanına yer bırakmak içinpayload_b64boyutunu yaklaşık 800 KiB'ın altında tutun. - Hatalı biçimlendirilmiş çerçeveler
invalid_json,invalid_json_typeveyaunknown_typenedeniyleerrordöndürür.
Genel hata çerçevesi:
{ "type": "error", "reason": "<reason>", "retry_after": 0 }
Hız sınırı hataları ayrıca scope alanını da taşır.
Kapatma kodları
| Kod | Anlamı |
|---|---|
1008 | Host veya Origin'e izin verilmiyor. |
4000 | Sunucu kalp atışını iletemedi. |
4001 | Oturum açma başarısız oldu. |
4002 | Oturum açma zaman aşımına uğradı. |
Rastgele sapmalı (jitter) üstel geri çekilmeyle yeniden bağlanın. AeroNyx App, 1–60 saniye aralığına sınırlanmış ve 0,8 ile 1,2 arasında rastgele bir katsayıyla çarpılmış 2^(attempt-1) saniye bekler.
Birebir (1:1) mesaj gönderme
1. Mühürlü zarfı oluşturun
Birebir mesajın yükü, imzalanmış ve şifrelenmiş bir ChatEnvelope nesnesidir. Tam oluşturma yöntemi, Python referans uygulaması ve altın test vektörü Merkezî Sohbet HTTPS API v1: Mühürlü zarf biçimi bölümündedir. Aynı zarf her iki API'de de kullanılır.
Özetle: sohbet anahtarıyla XChaCha20-Poly1305, 121 baytlık bir döküm (transcript) üzerinde Ed25519 imzası ve sabit bir ikili düzen. Ek içeren mesajlar dahil her mesaj için content_type değeri 0'dır.
Açık metin, düz bir mesaj için UTF-8 metindir; ek, yanıt, iletme veya bağlantı önizlemesi içeren mesajlar için ise bir JSON nesnesidir:
{
"type": "aeronyx_message",
"text": "See the attached file",
"attachments": [ { "blob_id": "...", "file_key": "...", "media_type": "image/jpeg", "file_name": "photo.jpg", "file_size": 482113 } ],
"reply": { "msg_id": "...", "sender_pubkey": "...", "text": "..." },
"forwarded": true,
"forwarded_from_name": "...",
"forwarded_from_pubkey": "...",
"link_preview": { "url": "https://...", "title": "...", "description": "...", "site_name": "..." }
}
type ve text dışındaki tüm alanlar isteğe bağlıdır. Alıcılar, "type": "aeronyx_message" içeren bir JSON nesnesi olmayan her açık metni düz metin olarak göstermelidir. Ek nesnesi "Şifrelenmiş ekler" bölümünde tanımlanmıştır.
2. Çerçeveyi imzalayın
Her mesaj çerçevesi, aktarıcının kabul etmeden önce doğruladığı ikinci bir imza olan payload_sig alanını taşır:
payload_sig = Ed25519(identity_key,
SHA256(receiver_pubkey[32] || sender_pubkey[32] || discriminant as 1 byte
|| timestamp as u64 little-endian || envelope_bytes))
envelope_bytes, payload_b64 değerinin kodu çözülmüş hâlidir. Mesajlar ve düzenlemeler için 11, tepkiler için 12 ayırt edicisini kullanın. payload_sig onaltılık olarak kodlanır.
3. Gönderin
{
"type": "relay_send",
"msg_id": "9e762ae0f5da43e6bec5eb8143f1f834",
"receiver_pubkey": "<64 hex>",
"discriminant": 11,
"payload_b64": "<base64 envelope>",
"timestamp": 1780000000,
"payload_sig": "<128 hex>"
}
| Alan | Kurallar |
|---|---|
msg_id | 32 küçük harfli onaltılık karakter: zarfın 16 baytlık message_id değeri. Alıcı taraftaki uygulama mesajı bu kimlikle saklar; bu nedenle zarfla eşleşmelidir. |
receiver_pubkey | Alıcının açık anahtarı. |
discriminant | 11. |
timestamp | Unix saniyesi; sunucu saatinden en fazla ±300 sn sapma. |
suppress_push | İsteğe bağlı. true olduğunda anlık bildirim gönderilmez. |
contact_request | İsteğe bağlı. Kişi doğrulaması gerektiren birine gönderilen ilk mesajı işaretler (bkz. "Kişi doğrulaması"). |
4. Onay
{ "type": "relay_delivered", "msg_id": "...", "delivered": true, "queued": true, "durable": true }
durable(vequeued), mesaj alıcının çevrimdışı kuyruğunda saklandığı andatrueolur.durable: truedeğerini "gönderildi" olarak değerlendirin.delivered, alıcının etkin bir ön plan bağlantısı olduğu anlamına gelir. Alındığının kanıtı değildir; bunun için teslim bilgilerini kullanın.
Denemeyi başarısız saymadan önce onay için en fazla 15 saniye bekleyin.
Retler ve hatalar
{ "type": "send_rejected", "msg_id": "...", "reason": "verification_required" }
| Yanıt | Neden | Eylem |
|---|---|---|
send_rejected | verification_required | Alıcı yalnızca kişilerinden mesaj kabul ediyor. Yeniden denemeyin. |
send_rejected | contact_request_rate_limited | Bu alıcı için kişi isteği sınırına ulaşıldı. Yeniden denemeyin. |
error | missing_fields | Zorunlu bir alan eksik veya boş. |
error | invalid_timestamp, timestamp_expired | Saati düzeltin ve zaman damgasını yenileyin. |
error | invalid_payload_sig | payload_sig doğrulanamıyor. |
error | rate_limited | retry_after saniye sonra yeniden deneyin. |
Yeniden denemeler
Onaylanmamış bir mesajı aynı msg_id ve aynı zarf baytlarıyla yeniden deneyin. Aktarıcı 300 saniyeden eski çerçeveleri reddettiği için her yeniden denemede çerçevenin timestamp ve payload_sig değerlerini yeniden hesaplayın; zarf ise özgün zaman damgasını korur. Aktarıcı ve alıcılar yinelenenleri msg_id üzerinden ayıklar.
HTTPS yedek yolu
WebSocket kullanılamadığında aynı mesaj HTTPS üzerinden gönderilebilir:
POST /api/relay/push/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
{
"receiver_pubkey": "<64 hex>",
"discriminant": 11,
"payload_b64": "<base64 envelope>",
"timestamp": 1780000000,
"payload_sig": "<128 hex>"
}
Başarı, {"success": true} ile birlikte HTTP 200 döndürür. Kişi doğrulaması hataları verification_required veya contact_request_rate_limited ile 400, hız sınırı ise Retry-After ile 429 döndürür. Bu yolla gönderilen mesajlar alıcı için kuyruğa alınır ancak anlık bildirim tetiklemez; bu nedenle WebSocket yeniden bağlandığında mesajı onun üzerinden yeniden gönderin.
Mesajları alma
Gelen mesajlar relay_envelope olarak ulaşır:
{
"type": "relay_envelope",
"sender_pubkey": "<64 hex>",
"discriminant": 11,
"payload_b64": "<base64 envelope>",
"timestamp": 1780000000,
"msg_id": "9e762ae0f5da43e6bec5eb8143f1f834",
"from_offline": false
}
discriminant: 11 için:
- Yinelenenleri
msg_idüzerinden ayıklayın. Aynı mesaj hem canlı olarak hem de çevrimdışı kuyruktan yeniden gelebilir. - Zarfı ayrıştırın ve zarftaki
receiver_pubkeydeğerinin sizin kimliğiniz olduğunu denetleyin. - Canlı çerçevelerde (
from_offline: false), zarfın zaman damgası saatinizden 300 saniyeden fazla sapıyorsa mesajı atın. - Zarf imzasını zarfın
sender_pubkeydeğerine göre doğrulayın. Kimliği doğrulanmış gönderici, çerçeveninsender_pubkeydeğeri değil, bu anahtardır. - O göndericiden türetilen sohbet anahtarıyla şifreyi çözün. Çok eski uygulama sürümleri ham X25519 çıktısıyla şifreliyordu; HKDF anahtarı başarısız olursa bunu deneyin.
- Mesajı kalıcı olarak saklayın, ardından bir teslim bilgisi ve
from_offline: truedurumunda ayrıca bir çevrimdışı onay gönderin.
Birebir zarflar payload_sig olmadan teslim edilir; özgünlük denetimi zarf imzasıdır. Çerçeveler ayrıca contact_request: true da taşıyabilir.
Bir mesaj size gönderilmemişse, doğrulamadan geçemiyorsa veya şifresi çözülemiyorsa, hiçbir şey göstermeden atın.
Çevrimdışı teslim
Her mesaj, düzenleme, geri çekme, tepki, teslim bilgisi ve okundu bilgisi, canlı teslimden önce alıcının çevrimdışı kuyruğuna yazılır. Kuyruk her oturum açmadan sonra ve istek üzerine otomatik olarak yeniden oynatılır:
{ "type": "relay_pull" }
Aktarıcı kuyruktaki tüm öğeleri, from_offline: true ile ve zaman damgasına göre sıralı olarak normal çerçeve türleriyle yeniden oynatır; ardından şunu gönderir:
{ "type": "relay_pull_done", "count": 12, "has_more": false }
Teslim en az bir kez garantisiyle yapılır. Öğeler onaylanana kadar kuyrukta kalır:
{ "type": "relay_offline_ack", "msg_id": "9e762ae0f5da43e6bec5eb8143f1f834" }
Tepkileri "msg_id" yerine "reaction_id" ile onaylayın. Yalnızca öğe cihazda kalıcı olarak saklandıktan sonra onaylayın. Aktarıcı {"type":"relay_offline_ack","msg_id":"...","success":true} ile yanıt verir.
Kuyruk sınırları:
| Sınır | Değer |
|---|---|
| Alıcı başına öğe | 1.000. Kuyruk dolduğunda yeni öğeler reddedilir ve gönderici durable: false görür. |
| Saklama süresi | En son öğenin eklenmesinden sonra 72 saat. |
| Yük boyutu | Kodu çözülmüş 1 MiB; 1 MiB'lık çerçeve sınırı içinde. |
Aktarıcı bir teslim arabelleğidir, mesaj geçmişi değildir. Geçmişi cihazda tutun.
Teslim ve okundu bilgileri
Teslim bilgisi
Bir mesajı sakladıktan sonra gönderin:
{ "type": "message_receipt", "receiver_pubkey": "<original sender>", "msg_id": "...", "timestamp": 1780000010 }
Aktarıcı message_receipt_ack ile yanıt verir ve özgün göndericiye {"type":"message_receipt","sender_pubkey":"...","msg_id":"...","timestamp":...} iletir.
Okundu bilgisi
{ "type": "message_read", "receiver_pubkey": "<original sender>", "msg_id": "<latest read message>", "timestamp": 1780000200, "enabled": true }
Okundu bilgileri birer eşik işaretidir (watermark): uygulama belirtilen mesajı ve sohbetteki ondan önceki tüm giden mesajları okundu olarak işaretler. Yalnızca kullanıcının okundu bilgileri etkinse gönderin.
Aktarıcı gönderimde, canlı teslimde ve yeniden oynatmada karşılıklılık kuralı uygular. Okundu bilgisi yalnızca iki kullanıcı karşılıklı olarak birbirinin kişisiyse ve her ikisinde de read_receipts_enabled etkinse teslim edilir. Aksi hâlde gönderici şunu alır:
{ "type": "message_read_ack", "msg_id": "...", "delivered": false, "suppressed": true, "reason": "receiver_read_receipts_disabled" }
| Neden | Anlamı |
|---|---|
client_disabled | Çerçeve enabled: false veya read_receipts_enabled: false taşıyordu. |
not_mutual_contact | Kullanıcılar karşılıklı kişi değil. |
reader_read_receipts_disabled | Okuyan taraf okundu bilgilerini kapatmış. |
receiver_read_receipts_disabled | Özgün gönderici okundu bilgilerini kapatmış. |
invalid_pubkey | Açık anahtarlardan biri hatalı biçimlendirilmiş. |
Teslim edilen bir okundu bilgisi {"type":"message_read_ack","msg_id":"...","delivered":true} ile onaylanır.
Düzenlemeler ve geri çekmeler
Düzenleme
Düzenleme, yerine geçecek içeriğin tamamını barındıran ve özgün mesaj kimliğine karşı gönderilen yeni bir mühürlü zarftır (kendine ait rastgele bir message_id ile):
{
"type": "message_edit",
"receiver_pubkey": "<64 hex>",
"msg_id": "<original msg_id>",
"target_msg_id": "<original msg_id>",
"payload_b64": "<base64 envelope>",
"payload_sig": "<128 hex>",
"timestamp": 1780000400
}
payload_sig, "Çerçeveyi imzalayın" bölümündeki formülü 11 ayırt edicisiyle kullanır. Tüm ekleri kaldıran bir düzenleme, açık metin JSON'unda "attachments_edited": true değerini ayarlar. Aktarıcı message_edit_ack ile yanıt verir. Alıcılar zarfı bir mesaj gibi doğrular ve şifresini çözer; düzenlemeyi yalnızca göndericisi özgün mesajın yazarıysa uygulamalıdır.
Geri çekme
{
"type": "message_revoke",
"receiver_pubkey": "<64 hex>",
"sender_pubkey": "<64 hex>",
"msg_id": "<original msg_id>",
"timestamp": 1780000500,
"payload_sig": "<128 hex>"
}
Geri çekme imzası, karma uygulanmadan ham baytlar üzerinde hesaplanır:
payload_sig = Ed25519(identity_key,
"aeronyx-message-revoke-v1" || sender_pubkey[32] || receiver_pubkey[32]
|| UTF-8(msg_id) || timestamp as u64 little-endian)
Aktarıcı message_revoke_ack ile yanıt verir. Aktarıcı yazarlığı denetlemez: alıcılar imzayı doğrulamalı ve geri çekmeyi yalnızca göndericisi özgün mesajın yazarıysa uygulamalıdır. Geri çekilen bir mesajın eklerini silmek için POST /api/relay/blob/{blob_id}/delete/ çağrısını yapın.
Tepkiler
Birebir tepki, message_id değeri tepki kimliği olan, content_type değeri 2 olan ve açık metni {"emoji": "❤️", "op": "add"} (veya "remove") olan bir mühürlü zarftır:
{
"type": "message_reaction",
"receiver_pubkey": "<64 hex>",
"msg_id": "<message being reacted to>",
"reaction_id": "<32 hex>",
"payload_b64": "<base64 envelope>",
"payload_sig": "<128 hex>",
"timestamp": 1780000300
}
payload_sig,12ayırt edicisini kullanır.reaction_id, eş güçlülük (idempotency) anahtarıdır. 72 saat içinde yinelenen birreaction_id,"duplicate": trueile onaylanır ve yeniden teslim edilmez.- Aktarıcı
{"type":"message_reaction_ack","msg_id":"...","reaction_id":"...","delivered":...,"queued":...}ile yanıt verir. - Tepkiler, hız penceresi içinde gönderici ve sohbet başına 20 ile sınırlıdır.
Grup tepkileri "Gruplar" bölümünde açıklanmıştır.
Çevrimiçi durumu ve yazıyor göstergesi
Çevrimiçi durumu ve yazıyor çerçeveleri açık metin meta verilerdir ve aktarıcı tarafından görülebilir.
Çevrimiçi durumu
Kişilere abone olun:
{ "type": "presence_subscribe", "pubkeys": ["<64 hex>", "<64 hex>"] }
Çerçeve başına en fazla 200 anahtar dikkate alınır; hatalı biçimlendirilmiş ve yinelenen anahtarlar yok sayılır. Abonelikler bağlantının ömrü boyunca birikir. Yalnızca kendi kişilerinize abone olun.
{
"type": "presence_subscribe_ack",
"count": 2,
"updates": [
{ "pubkey": "<a>", "visible": true, "presence_visible": true, "last_seen_visible": true, "online": false, "last_seen_ts": 1780000000, "reason": "allowed" },
{ "pubkey": "<b>", "visible": false, "presence_visible": false, "last_seen_visible": false, "reason": "not_mutual_contact" }
],
"server_ts": 1780000001
}
Çevrimiçi durumu yalnızca karşılıklı kişiler arasında ve yalnızca hedefte presence_enabled etkinse görülebilir. Gizli girdiler (reason değeri not_mutual_contact veya presence_hidden olanlar) online veya last_seen_ts içermez. last_seen_ts yalnızca last_seen_visible değeri true olduğunda bulunur; aksi hâlde "yakın zamanda görüldü" gibi genel bir durum gösterin.
Canlı değişiklikler şu şekilde gelir:
{ "type": "presence_update", "pubkey": "<a>", "online": true, "presence_visible": true, "last_seen_visible": true, "last_seen_ts": 1780000100 }
Yazıyor göstergesi
{ "type": "typing", "receiver_pubkey": "<64 hex>", "is_typing": true }
{ "type": "group_typing", "group_id": "<uuid>", "is_typing": true }
Yazıyor göstergesi yalnızca göndericinin çevrimiçi durumu alıcıya görünür olacaksa (karşılıklı kişiler ve presence_enabled) ya da göndericinin üyesi olduğu bir grubun diğer üyelerine iletilir. Hiçbir zaman saklanmaz, kuyruğa alınmaz veya anlık bildirim olarak gönderilmez.
Profil ve gizlilik ayarları
GET /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
{
"success": true,
"profile": {
"pubkey_hex": "<64 hex>",
"display_name": "AeroNyx User",
"bio": "",
"handle": "",
"avatar_url": "",
"status_text": "",
"privacy": { "presence_enabled": true, "last_seen_enabled": true, "read_receipts_enabled": true },
"updated_at": "2026-10-09T10:00:00Z"
}
}
Profili olmayan bir kimlik boş alanlar alır ve üç gizlilik bayrağının tümü true olur.
PATCH /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
{ "display_name": "Alice", "privacy": { "presence_enabled": true, "last_seen_enabled": false, "read_receipts_enabled": false } }
| Alan | Kurallar |
|---|---|
display_name | En fazla 50 karakter. |
bio | En fazla 200 karakter. |
avatar_url | https:// URL'si veya boş. |
handle | a-z ve 0-9, 5–24 karakter. Kullanıcı adları üyelik kurallarına ve değişiklik bekleme sürelerine tabidir. |
privacy.* | Mantıksal değerler. Üç bayrak üst düzeyde de gönderilebilir. |
Hatalar arasında no_valid_fields, <flag>_invalid_boolean, handle_taken ve handle_change_cooldown:<date> bulunur.
İstemciyi bu ayarlarla tutarlı tutun: okundu bilgileri kapalıyken okundu bilgisi göndermeyin ve kendi okundu bilgileriniz kapalıyken karşı tarafın okundu durumunu göstermeyin.
Kişi doğrulaması
Bir kullanıcı, yabancıların kendisine mesaj göndermeden önce doğrulanmasını şart koşabilir. Alıcı bu özelliği açmışsa ve göndericiyi kişi olarak eklememişse relay_send, verification_required ile reddedilir.
Bir sohbet başlatmak için "contact_request": true içeren tek bir mesaj gönderin. Kişi istekleri bu denetimi atlar ve kayan 24 saatlik bir pencere içinde gönderici ve alıcı başına 3 ile sınırlıdır; sonraki istekler contact_request_rate_limited ile reddedilir. Uygulamanın mesajı bir istek olarak sunabilmesi için contact_request bayrağı alıcıya iletilir.
Kişi doğrulaması relay_send ve HTTPS yedek yolu için geçerlidir.
Gruplar
Grup mesajları
Grup içeriği, AES-256-GCM kullanılarak 32 baytlık paylaşılan bir grup anahtarıyla şifrelenir:
payload_b64 = base64(nonce[12] || AES-256-GCM(group_key, plaintext_json) || tag[16])
Açık metin JSON; text, type (text, media, system veya reaction), sender_pubkey, created_at ve isteğe bağlı olarak attachments, mentions, reply, forwarded, forwarded_from_name, forwarded_from_pubkey ve link_preview alanlarını içerir.
{
"type": "group_send",
"msg_id": "<32 hex>",
"group_id": "<uuid>",
"payload_b64": "<base64>",
"timestamp": 1780000000,
"payload_sig": "<128 hex>",
"key_version": 3
}
payload_sig = Ed25519(identity_key,
SHA256(UTF-8(group_id) || sender_pubkey[32] || 0x19 || timestamp as u64 little-endian
|| decoded payload))
Aktarıcı imzayı ve göndericinin etkin bir üye olduğunu denetler, mesajı diğer tüm etkin üyeler için saklar ve ardından canlı olarak teslim eder. Grup yükleri birebir zarfı kullanmaz; grup zarfları, alıcıların şifreyi çözmeden önce göndericiyi doğrulayabilmesi için group_id, key_version ve payload_sig ile teslim edilir.
{
"type": "group_delivered",
"msg_id": "...",
"group_id": "...",
"accepted": true,
"accepted_count": 5,
"delivered_count": 2,
"queued_count": 5,
"failed_count": 0,
"member_count": 6
}
Üye olmayan bir gönderici not_a_member nedeniyle error alır.
Grup düzenlemeleri, geri çekmeleri ve tepkileri
| Çerçeve | İmza |
|---|---|
group_message_edit (group_id, msg_id, target_msg_id, payload_b64, payload_sig, key_version, timestamp) | Yukarıdaki grup formülü. |
group_message_reaction (group_id, msg_id, reaction_id, payload_b64, payload_sig, key_version, timestamp) | Yukarıdaki grup formülü. Yük, type: "reaction" içeren bir grup yüküdür. |
group_message_revoke (group_id, sender_pubkey, msg_id, timestamp, payload_sig) | `"aeronyx-group-message-revoke-v1" |
Her biri, teslim sayılarını taşıyan karşılık gelen _ack çerçevesiyle onaylanır. Alıcılar düzenlemeleri ve geri çekmeleri yalnızca özgün yazardan geliyorsa uygular.
Grup anahtarları
Grup anahtarları, grup sahibi tarafından üye başına anahtar paketleri olarak dağıtılır: base64(nonce[12] || AES-256-GCM(chat_key(owner, member), group_key) || tag[16]). /api/relay/groups/ altındaki REST uç noktaları grup oluşturur, üyeleri ve davetleri yönetir, anahtar paketlerini yükler, anahtarları döndürür (keys/rotate/) ve çağıranın geçerli paketini getirir (keys/me/). Göndericiler sahip oldukları en son anahtar sürümüyle şifreler; bir anahtar sürümüne sahip olmayan alıcılar keys/me/ uç noktasından anahtarı getirmeli ve anahtar gelene kadar mesajı bekletmelidir.
Şifrelenmiş ekler
Ekler cihazda şifrelenir, opak şifreli metin olarak yüklenir ve şifrelenmiş mesajın içinden başvurulur.
Dosyayı şifreleyin
Her dosya için rastgele 32 baytlık bir anahtar ve rastgele 12 baytlık bir nonce üretin:
blob = nonce[12] || AES-256-GCM(file_key, file_bytes) || tag[16]
blob verisini yükleyin. file_key değerini ve tüm tanımlayıcı alanları yükleme isteğine asla koymayın, şifrelenmiş mesajın içine koyun.
Ek nesnesi
| Anahtar | Zorunlu | Anlamı |
|---|---|---|
blob_id | evet | Yüklemenin döndürdüğü kimlik. |
file_key | evet | 32 baytlık dosya anahtarının Base64 hâli. |
media_type | evet | Açık metin dosyanın MIME türü. |
file_name | evet | Görünen ad. |
file_size | evet | Bayt cinsinden açık metin boyutu. |
thumb_b64 | hayır | Base64 JPEG küçük resim, en fazla 64 KiB. |
duration_ms | hayır | Ses veya video süresi. |
waveform | hayır | Sesli mesajlar için [0, 1] aralığında en fazla 96 sayı. |
sticker, sticker_pack, sticker_pose | hayır | Çıkartma kimliği. |
live | hayır | Live Photo hareket bölümü: {blob_id, file_key, media_type, file_size, duration_ms?, width?, height?}. |
Alıcılar blob_id veya file_key içermeyen ekleri yok sayar. Uygulamadan gelen sesli mesajlar, MP4 kapsayıcısında AAC-LC biçimindedir (audio/mp4).
Yükleme: tek istek (en fazla 10 MiB)
POST /api/relay/blob/presign/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
{ "file_size": 482141, "media_type": "image/jpeg", "media_kind": "image", "ttl_days": 7 }
file_size, şifreli metin boyutudur. media_kind şunlardan biridir: voice, image, video, file, avatar, other. ttl_days 1–30 aralığına sınırlanır (varsayılan 7).
{
"blob_id": "<uuid>",
"upload_url": "https://...",
"upload_method": "PUT",
"storage": "r2",
"expires_at": "2026-10-16T10:00:00Z",
"media_type": "image/jpeg",
"media_kind": "image",
"access_mode": "capability",
"ttl_days": 7,
"max_bytes": 10485760
}
Ardından:
- Şifreli metni 15 dakika içinde, yalnızca bir
Content-Typebaşlığıylaupload_urladresinePUTile gönderin.Authorizationbaşlığını depolama hizmetine göndermeyin. - RelayAuth ile
POST /api/relay/blob/{blob_id}/complete/çağrısını yapın. Aktarıcı nesneyi doğrular ve{blob_id, file_size, expires_at, storage}döndürür.
Yükleme: çok parçalı (en fazla 100 MiB)
POST /api/relay/blob/multipart/create/
{ "total_size": 52428800, "media_type": "video/mp4", "media_kind": "video", "ttl_days": 7 }
{
"blob_id": "<uuid>",
"upload_id": "...",
"part_size": 8388608,
"total_parts": 7,
"part_urls": ["https://...", "..."],
"storage": "r2",
"expires_at": "...",
"max_bytes": 104857600
}
part_size varsayılan olarak 8 MiB'tır ve 5 ile 16 MiB arasında bir değer istenebilir. Parça URL'leri 60 dakika geçerlidir. Her parçayı kendi URL'sine PUT ile gönderin ve ETag yanıt başlığını kaydedin, ardından:
POST /api/relay/blob/multipart/complete/
{ "blob_id": "<uuid>", "upload_id": "...", "parts": [ { "part_number": 1, "etag": "\"...\"" } ] }
AeroNyx App, 8 MiB'a kadar şifreli metin için tek istekli yüklemeyi, bunun üzerinde ise çok parçalı yüklemeyi kullanır.
İndirme
GET /api/relay/blob/{blob_id}/
Aktarıcı, içerik dağıtım ağındaki bir Location ile ve X-AeroNyx-Blob-Size, X-AeroNyx-Blob-Media-Type ve X-AeroNyx-Blob-Storage başlıklarıyla 302 yanıtı verir. Yönlendirmeyi hiçbir Authorization başlığını iletmeden kendiniz izleyin, ardından blob'u file_key ile doğrulayın ve şifresini çözün. İndirmeyi beklenen boyutla sınırlayın.
Bir blob_id, taşıyıcı yetkisidir (bearer capability): ona sahip olan herkes şifreli metni getirebilir; anahtarın yalnızca şifrelenmiş mesajın içinde taşınmasının nedeni budur. access_mode ve sona erme süresi aktarıcının yönlendirmesinde uygulanır. Gizlilik için bunlara güvenmeyin.
Ekleri silme
POST /api/relay/blob/{blob_id}/delete/
Bir blob'u yalnızca onu yükleyen silebilir. Yanıt {"blob_id": "...", "deleted": true} şeklindedir.
Ek hataları
Hatalar {"success": false, "error": "<text>", "error_code": "<code>"} biçimini kullanır. Akışı error_code değerine göre dallandırın.
| HTTP | error_code | Anlamı |
|---|---|---|
| 400 | blob_id_invalid | Hatalı biçimlendirilmiş blob kimliği. |
| 400 | blob_missing_file_size, blob_missing_total_size, blob_missing_parts, blob_bad_parts, blob_bad_part_count | Geçersiz yükleme isteği. |
| 400 | blob_not_r2, blob_multipart_complete_failed | Tamamlama başarısız oldu; yeni bir yükleme başlatın. |
| 401 | auth_required | Blob, RelayAuth gerektiriyor. |
| 403 | blob_not_uploader, download_forbidden | Çağıranın izni yok. |
| 404 | blob_not_found, blob_not_uploaded | Bilinmeyen blob veya yükleme bitmeden yapılan tamamlama isteği. |
| 410 | blob_expired | Blob'un süresi doldu. Göndericiden yeniden göndermesini isteyin. |
| 413 | blob_too_large | Sınır aşıldı; yanıt max_bytes ve chunked_max_bytes içerir. |
| 503 | blob_r2_unavailable | Depolama geçici olarak kullanılamıyor; geri çekilmeyle yeniden deneyin. |
Eski yükleme uç noktaları
POST /api/relay/blob/ (çok parçalı form, en fazla 10 MiB) ve /api/relay/blob/session/ altındaki sürdürülebilir oturum API'si (en fazla 100 MiB, 64 KiB ile 4 MiB arası parçalar, 24 saat geçerli oturumlar) yedek olarak kullanılabilir durumdadır. Yeni istemciler yukarıdaki uç noktaları kullanmalıdır.
Anlık bildirimler
Aktarıcı, iOS ve macOS için Apple Push Notification service (APNs) bildirimleri gönderir. Android istemcileri mesajları yalnızca WebSocket üzerinden alır.
Alıcının etkin bir ön plan bağlantısı yoksa, gönderici suppress_push ayarlamamışsa ve alıcı sohbeti sessize almamışsa relay_send ve group_send için anlık bildirim gönderilir. Düzenlemeler, geri çekmeler, tepkiler ve teslim/okundu bilgileri anlık bildirim göndermez. Anlık bildirim yükleri hiçbir şifreli metin içermez:
{
"aps": { "alert": { "title": "AeroNyx", "body": "New encrypted message" }, "sound": "default", "badge": 1, "content-available": 1 },
"kind": "p2p_message",
"sender_pubkey": "<64 hex>",
"message_id": "..."
}
kind, p2p_message (sender_pubkey ile) veya group_message (group_id ile) değerini alır. Arama bildirimleri missed_call ve aramaya özel yükler kullanır. Anlık bildirim aldığınızda bağlanın ve relay_pull çalıştırın.
| Uç nokta | Gövde |
|---|---|
POST /api/relay/push/register/ | token (64 onaltılık karakter), platform (ios veya macos), bundle_id, environment (production veya sandbox), isteğe bağlı token_type (alert veya voip) ve provider (apns). |
POST /api/relay/push/unregister/ | token, isteğe bağlı platform, token_type, provider. |
POST /api/relay/push/mute/ | kind (p2p veya group), target (açık anahtar veya grup kimliği), muted (mantıksal değer). |
Üçü de RelayAuth gerektirir. Bir belirtecin kaydedilmesi, onu çağıran kimliğe taşır.
Aramalar
Sesli ve görüntülü arama sinyalleşmesi, aynı WebSocket üzerinden açık metin meta veri olarak iletilir; medya ayrı akar. Çerçeveler birebir aramalar için call_invite, call_answer, call_reject, call_hangup ve call_busy; gruplar için group_call_invite, group_call_invite_broadcast, group_call_answer ve group_call_hangup_broadcast'tır; barındırılan toplantılar için ayrıca toplantıya kabul çerçeveleri bulunur.
Aktarıcı room_name değerini katılımcılara göre doğrular: birebir aramalar için p2p_ ve ardından SHA256(lower_key + ":" + higher_key) değerinin ilk 16 onaltılık karakteri; gruplar için grp_<first 8 characters of group_id>_<first 8 hex of SHA256(group_id)>. Çevrimdışı bir alıcıya yönelik arama sinyalleri 120 saniye bekletilir.
Hız sınırları
| Kapsam | Sınır | Yanıt |
|---|---|---|
Kimlik başına relay_send, group_send ve HTTPS push | Kısa pencere başına 50; günde 100.000 | WebSocket: retry_after ile error rate_limited. HTTPS: Retry-After ile 429. |
Gönderici ve grup başına group_send | Kısa pencere başına 10 | error rate_limited, scope: "sender". |
Grup başına group_send | Kısa pencere başına 50 | error rate_limited, scope: "group". |
| Gönderici ve sohbet başına tepkiler | Kısa pencere başına 20 | error rate_limited, scope: "reaction". |
| Gönderici ve alıcı başına kişi istekleri | 24 saatte 3 | send_rejected contact_request_rate_limited. |
En az retry_after saniye geri çekilin. Sıkı bir döngü içinde yeniden göndermeyin: siz yeniden denerken sayaçlar işlemeye devam eder.
Uygulama kontrol listesi
- Bir Ed25519 kimliği üretin ve saklayın; her yerde küçük harfli onaltılık anahtarlar kullanın.
- RelayAuth'u ve WebSocket oturum açma, kalp atışı ve
presence_stateişlevlerini uygulayın. - Mühürlü zarfı uygulayın ve Merkezî Sohbet HTTPS API v1 içindeki altın vektöre göre doğrulayın.
relay_sendile gönderin,durable: truedeğerini gönderildi olarak değerlendirin, yeniden denemelerdetimestampvepayload_sigdeğerlerini yenileyin.relay_envelopealın: yinelenenleri ayıklayın, doğrulayın, şifreyi çözün, saklayın, ardındanmessage_receiptverelay_offline_ackgönderin.- Oturum açtıktan sonra ve anlık bildirimle uyandırıldığınızda
relay_pullçalıştırın; yalnızca kalıcı depolamadan sonra onaylayın. - Profil gizlilik bayraklarını okuyun ve çevrimiçi durumu ile okundu bilgilerinde bunlara uyun.
- Ekleri cihazda şifreleyin ve
presignveya çok parçalı yükleme ile yükleyin;file_keydeğerini şifrelenmiş mesajın içinde tutun. - Düzenlemeleri ve geri çekmeleri uygulamadan önce yazarlığı doğrulayın.
- Mesaj aramasını ve geçmişi cihazda tutun. Aktarıcıda içerik araması yoktur ve aktarıcı bir arşiv değildir.
Sıkça sorulan sorular
AeroNyx Sohbet Aktarıcısı mesajlarımı okuyabilir mi?
Hayır. Mesajlar, düzenlemeler, tepkiler, grup mesajları ve ekler aktarıcıya ulaşmadan önce göndericinin cihazında şifrelenir ve imzalanır; anahtarlar ise konuşmadaki kişilerin cihazlarından hiçbir zaman çıkmaz. Aktarıcı yalnızca şifreli metni saklar ve iletir.
AeroNyx Sohbet Aktarıcısı neleri görebilir?
Aktarıcı teslim meta verilerini görür: gönderici ve alıcı açık anahtarları, grup ve mesaj kimlikleri, zaman damgaları, yük boyutları, teslim ve okundu durumu, çevrimiçi durumu ve yazıyor sinyalleri, arama sinyalleşmesi meta verileri, ek boyutları ve bağlantı IP adresleri. Mesaj içeriğini, ek içeriğini veya anahtarları görmez. Tam liste, bu sayfanın başındaki güven modelinde yer alır.
AeroNyx sohbeti hangi şifrelemeyi kullanır?
Her kimlik bir Ed25519 anahtar çiftidir. İki kişi, X25519 ve HKDF-SHA256 ile ortak bir sohbet anahtarı türetir. Birebir (1:1) mesajlar XChaCha20-Poly1305 ile şifrelenir ve Ed25519 ile imzalanır. Grup mesajları ve ekler AES-256-GCM ile şifrelenir. Tam bayt biçimleri ve bir test vektörü, Merkezî Sohbet HTTPS API v1 belgelerinde yayımlanmıştır.
Fotoğraflar, videolar ve dosyalar nasıl korunur?
Her dosya, yüklenmeden önce cihazda kendine ait rastgele bir AES-256-GCM anahtarıyla şifrelenir. Depolama yalnızca şifreli metni alır. Dosya anahtarı uçtan uca şifrelenmiş mesajın içinde taşınır; bu nedenle dosyanın şifresini yalnızca alıcılar çözebilir.
Alıcı çevrimdışıysa ne olur?
Aktarıcı, şifrelenmiş mesajları alıcının çevrimdışı kuyruğunda en fazla 72 saat tutar ve alıcı yeniden bağlandığında teslim eder. iOS ve macOS'ta alıcı ayrıca mesaj içeriği barındırmayan bir anlık bildirim alır.
AeroNyx sohbet geçmişimi saklıyor mu?
Hayır. Aktarıcı bir teslim arabelleğidir: öğeler, alıcının cihazı bunları sakladığını onayladıktan sonra silinir. Sohbet geçmişi ve arama sizin cihazlarınızda bulunur.
Kendi AeroNyx istemcimi veya botumu geliştirebilir miyim?
Evet. Bir Ed25519 kimliğine sahip olan ve bu sayfadaki biçimleri uygulayan her yazılım, AeroNyx App kullanıcılarıyla mesaj alışverişi yapabilir. WebSocket kullanmayan, daha basit ve istek/yanıt tabanlı bir entegrasyon için Merkezî Sohbet HTTPS API v1'i kullanın.
AeroNyx Sohbet Aktarıcısı merkeziyetsiz mi?
Sohbet Aktarıcısı, AeroNyx'in merkezî teslim hizmetidir. AeroNyx ayrıca sohbet şifreli metnini ağ çeşitliliğine sahip iki atlamalı bir rota üzerinden taşıyabilen açık kaynaklı (AGPL-3.0) bir düğüm ağı işletir. İki yol bir arada var olur: aktarıcı hızlı ve güvenilir teslim ile çevrimdışı kuyruklar sağlar; düğüm yolu ise herhangi bir tekil operatörün gözlemleyebileceklerini azaltan isteğe bağlı bir rotadır.
Mesajım neden verification_required ile reddediliyor?
Alıcı yalnızca kişilerinden gelen mesajları kabul eder. contact_request: true içeren tek bir ilk mesaj gönderin; alıcı bunu bir kişi isteği olarak görür. Her alıcı için herhangi bir 24 saatlik zaman aralığında en fazla üç kişi isteğine izin verilir.
Doğrulanmış iki atlamalı teslim
Uygun ve kimliği doğrulanmış ChatRelay trafiğinde kaynak, ağ çeşitliliğine sahip iki atlamalı bir yol seçebilir ve teslimi ancak beklenen uç düğümün imzalı alındısını doğruladıktan sonra sayabilir. Aktarıcı düğümler şifreli metni yönlendirir ve uçtan uca (E2E) yükü ayrıştırmaz. Kanıt modelinin tamamı için Düğüm Keşfi ve Doğrulanmış Şifreli Aktarıcı Teslimi sayfasına bakın.
<!-- verified-two-hop-delivery-v1:end -->