Šepot — end-to-end encrypted messenger

Initial public release. Anonymous on-device identity (no phone number,
e-mail, or password), Signal-protocol cryptography (X3DH + PQXDH, Double
Ratchet, sealed sender) via libsignal, a metadata-minimizing relay,
group chats, disappearing messages, encrypted local storage, optional
Tor transport, and a UI localized into Czech, English, German, Russian,
and Italian.

Monorepo: Flutter client (app/), Rust relay + wire types (rust/),
protobuf definitions (proto/), self-host deploy (deploy/).

Licensed under AGPL-3.0 with an app-store distribution exception (§7).
This commit is contained in:
Julius Joska
2026-07-11 17:06:39 +02:00
commit 8081d98c67
309 changed files with 44102 additions and 0 deletions
+153
View File
@@ -0,0 +1,153 @@
// Šepot wire protokol v1 — jediný zdroj pravdy pro Rust (prost) i Dart.
//
// Sémantika:
// server vidí JEN routing (dst_address, msg_uuid, content_hint); payload je
// opaque sealed-sender ciphertext, odesílatel i obsah jsou uvnitř.
// Žádné pole nesmí nést PII ani IP.
syntax = "proto3";
package sepot.v1;
// ── Obálka zprávy (klient→server i server→klient při DELIVER) ─────────
enum ContentHint {
CONTENT_HINT_DEFAULT = 0; // běžná zpráva
CONTENT_HINT_RESYNC = 1; // řízení retry po session poruše
CONTENT_HINT_SUPPLEMENTARY = 2; // doprovodná (receipt apod.)
}
message Envelope {
bytes dst_address = 1; // 32 B rotovatelný routing token příjemce
bytes msg_uuid = 2; // 16 B, generuje odesílatel; dedup/fanout
ContentHint content_hint = 3;
bytes payload = 4; // OPAQUE sealed-sender ciphertext (≤256 KiB)
}
// ── Potvrzení a stavy ──────────────────────────────────────────────────
message Ack {
bytes msg_uuid = 1; // klient potvrzuje vyzvednutí DELIVER
}
message Receipt {
enum Status {
STATUS_QUEUED = 0;
STATUS_DELIVERED_ONLINE = 1;
STATUS_STORED_OFFLINE = 2;
}
bytes msg_uuid = 1;
Status status = 2;
}
// ── Autentizace zařízení (podpis výzvy, žádné heslo/PII) ────────
message Auth {
bytes device_uuid = 1; // 16 B
bytes nonce_client = 2; // 16 B
}
message Challenge {
bytes nonce_server = 1; // 32 B
}
message AuthProof {
// XEdDSA podpis device klíčem nad: nonce_client || nonce_server || "sepot-auth-v1"
bytes signature = 1; // 64 B
}
// ── Provozní rámce ─────────────────────────────────────────────────────
message PrekeysLow {
uint32 remaining = 1; // hint: zbývající one-time prekeys
}
message Error {
uint32 code = 1;
string message = 2;
}
message Ping {}
message Pong {}
// Potvrzení úspěšné WS autentizace — teprve po něm smí klient hlásit
// „připojeno" a posílat obálky (fronta se vylévá hned po něm).
message AuthOk {}
// ── Push registrace ───────────────────────────────────────────────
// Posílá se JEN přes autentizovaný WS (endpoint se nikdy neposílá
// neautentizovaně a jde stejnou cestou jako provoz — klidně přes Tor).
// Relay endpoint NIKDY neloguje. Budíček je vždy prázdný „ťuk" — žádný
// obsah ani odesílatel neopustí sealed-sender kanál.
message RegisterPush {
enum Platform {
PLATFORM_NONE = 0; // vypnout push (anonymní režim) — smaže token
PLATFORM_FCM = 1; // opt-in fast mode (vystaví token Googlu)
PLATFORM_APNS = 2; // opt-in fast mode (Apple)
PLATFORM_UNIFIEDPUSH = 3; // default — endpoint distributora (ntfy)
PLATFORM_WEBPUSH = 4; // RFC 8030 endpoint
}
Platform platform = 1;
// UnifiedPush/WebPush endpoint URL (utf-8 bytes), nebo FCM/APNs token.
// Prázdné, když platform=NONE.
bytes endpoint = 2;
}
// ── Prekey typy (REST /v1/register, /v1/keys — sdílené s bundle fetch) ─
message SignedPreKey {
uint32 key_id = 1;
bytes public_key = 2; // 32 B Curve25519
bytes signature = 3; // 64 B XEdDSA podpis identity klíčem
}
message KyberPreKey {
uint32 key_id = 1;
bytes public_key = 2; // Kyber-1024, ~1569 B
bytes signature = 3;
bool is_last_resort = 4; // last-resort se nespotřebovává
}
message OneTimePreKey {
uint32 key_id = 1;
bytes public_key = 2; // 32 B Curve25519
}
message PreKeyBundle {
uint32 registration_id = 1;
uint32 device_id = 2;
bytes identity_key = 3; // 33 B (type byte + Curve25519)
SignedPreKey signed_prekey = 4;
KyberPreKey kyber_prekey = 5;
OneTimePreKey one_time_prekey = 6; // chybí, když OTP došly (povolený fallback)
}
// Bundle pro všechna zařízení identity (multi-device fanout).
message PreKeyBundles {
repeated PreKeyBundle devices = 1;
}
// ── Vrcholové rámce na WS (subprotocol "sepot.v1") ────────────────────
message ClientFrame {
oneof frame {
Auth auth = 1;
AuthProof auth_proof = 2;
Envelope envelope = 3;
Ack ack = 4;
Pong pong = 5;
RegisterPush register_push = 6;
}
}
message ServerFrame {
oneof frame {
Challenge challenge = 1;
Receipt receipt = 2;
Envelope deliver = 3;
PrekeysLow prekeys_low = 4;
Ping ping = 5;
Error error = 6;
AuthOk auth_ok = 7;
}
}