Š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:
@@ -0,0 +1,178 @@
|
||||
/// Typované chyby, které se zobrazují uživateli.
|
||||
///
|
||||
/// Service vrstva nemá přístup k lokalizaci (žádný BuildContext), proto
|
||||
/// nesmí formulovat texty pro uživatele — vyhazuje tyhle typy a UI je
|
||||
/// překládá přes `describeError` (core/l10n/error_messages.dart).
|
||||
/// `toString()` je anglický technický popis pro logy, ne pro UI.
|
||||
library;
|
||||
|
||||
sealed class SepotUserError implements Exception {
|
||||
const SepotUserError();
|
||||
}
|
||||
|
||||
/// Trust root relaye nesedí s pinovaným — server nelze ověřit.
|
||||
class TrustRootChangedError extends SepotUserError {
|
||||
const TrustRootChangedError();
|
||||
|
||||
@override
|
||||
String toString() => 'relay trust root changed — refusing to communicate';
|
||||
}
|
||||
|
||||
/// Relay nedostupný (typicky fetch sender certificate).
|
||||
class RelayUnavailableError extends SepotUserError {
|
||||
const RelayUnavailableError();
|
||||
|
||||
@override
|
||||
String toString() => 'relay unavailable';
|
||||
}
|
||||
|
||||
/// Příloha přesahuje serverový limit.
|
||||
class AttachmentTooLargeError extends SepotUserError {
|
||||
const AttachmentTooLargeError(this.maxBytes);
|
||||
|
||||
final int maxBytes;
|
||||
|
||||
int get maxMb => (maxBytes / (1024 * 1024)).round();
|
||||
|
||||
@override
|
||||
String toString() => 'attachment too large (max $maxBytes bytes)';
|
||||
}
|
||||
|
||||
/// Skupina bez jediného dalšího člena nedává smysl.
|
||||
class GroupNeedsMemberError extends SepotUserError {
|
||||
const GroupNeedsMemberError();
|
||||
|
||||
@override
|
||||
String toString() => 'group needs at least one member';
|
||||
}
|
||||
|
||||
/// Překročen strop počtu členů skupiny.
|
||||
class GroupTooLargeError extends SepotUserError {
|
||||
const GroupTooLargeError(this.maxMembers);
|
||||
|
||||
final int maxMembers;
|
||||
|
||||
@override
|
||||
String toString() => 'group exceeds $maxMembers members';
|
||||
}
|
||||
|
||||
/// Člen skupiny nemá doručovací adresu (starý odkaz bez routingu).
|
||||
class MemberNoDeliveryAddressError extends SepotUserError {
|
||||
const MemberNoDeliveryAddressError(this.displayName);
|
||||
|
||||
final String displayName;
|
||||
|
||||
@override
|
||||
String toString() => 'member "$displayName" has no delivery address';
|
||||
}
|
||||
|
||||
/// Kontakt nemá doručovací adresu (starý odkaz bez routingu).
|
||||
class ContactNoDeliveryAddressError extends SepotUserError {
|
||||
const ContactNoDeliveryAddressError();
|
||||
|
||||
@override
|
||||
String toString() => 'contact has no delivery address';
|
||||
}
|
||||
|
||||
/// Identity klíč z relaye nesedí s uloženým kontaktem — možný MITM.
|
||||
class IdentityKeyMismatchError extends SepotUserError {
|
||||
const IdentityKeyMismatchError();
|
||||
|
||||
@override
|
||||
String toString() => 'identity key mismatch — possible MITM, message not sent';
|
||||
}
|
||||
|
||||
// === Obnova účtu (mnemonic) ===
|
||||
|
||||
/// Fráze má špatný počet slov.
|
||||
class MnemonicWordCountError extends SepotUserError {
|
||||
const MnemonicWordCountError(this.count, this.expected);
|
||||
|
||||
final int count;
|
||||
final int expected;
|
||||
|
||||
@override
|
||||
String toString() => 'mnemonic has $count words, expected $expected';
|
||||
}
|
||||
|
||||
/// Fráze neprošla validací BIP39 (neznámé slovo, checksum…).
|
||||
class MnemonicInvalidError extends SepotUserError {
|
||||
const MnemonicInvalidError(this.detail);
|
||||
|
||||
final String detail;
|
||||
|
||||
@override
|
||||
String toString() => 'invalid mnemonic: $detail';
|
||||
}
|
||||
|
||||
// === Zálohy historie (backup_service) ===
|
||||
|
||||
/// Soubor zálohy je poškozený (nejde přečíst/dešifrovat strukturu).
|
||||
class BackupCorruptedError extends SepotUserError {
|
||||
const BackupCorruptedError();
|
||||
|
||||
@override
|
||||
String toString() => 'corrupted backup file';
|
||||
}
|
||||
|
||||
/// Soubor není záloha Šepotu.
|
||||
class BackupUnknownFormatError extends SepotUserError {
|
||||
const BackupUnknownFormatError();
|
||||
|
||||
@override
|
||||
String toString() => 'unknown backup format';
|
||||
}
|
||||
|
||||
/// Záloha je šifrovaná klíčem jiné identity.
|
||||
class BackupWrongIdentityError extends SepotUserError {
|
||||
const BackupWrongIdentityError();
|
||||
|
||||
@override
|
||||
String toString() => 'backup belongs to a different identity';
|
||||
}
|
||||
|
||||
// === Kontakty ===
|
||||
|
||||
/// Kontakt s tímto fingerprintem už existuje.
|
||||
class ContactAlreadyExistsError extends SepotUserError {
|
||||
const ContactAlreadyExistsError();
|
||||
|
||||
@override
|
||||
String toString() => 'contact already exists';
|
||||
}
|
||||
|
||||
// === Nahlášení zneužití (report_service) ===
|
||||
|
||||
/// Hlášení bez popisu nemá co řešit.
|
||||
class ReportEmptyDescriptionError extends SepotUserError {
|
||||
const ReportEmptyDescriptionError();
|
||||
|
||||
@override
|
||||
String toString() => 'report has empty description';
|
||||
}
|
||||
|
||||
/// Server hlášení je nedosažitelný.
|
||||
class ReportConnectionError extends SepotUserError {
|
||||
const ReportConnectionError();
|
||||
|
||||
@override
|
||||
String toString() => 'report endpoint unreachable';
|
||||
}
|
||||
|
||||
/// Rate limit hlášení (429).
|
||||
class ReportRateLimitedError extends SepotUserError {
|
||||
const ReportRateLimitedError();
|
||||
|
||||
@override
|
||||
String toString() => 'report rate limited';
|
||||
}
|
||||
|
||||
/// Server hlášení vrátil chybový kód.
|
||||
class ReportServerError extends SepotUserError {
|
||||
const ReportServerError(this.statusCode);
|
||||
|
||||
final int statusCode;
|
||||
|
||||
@override
|
||||
String toString() => 'report failed with status $statusCode';
|
||||
}
|
||||
Reference in New Issue
Block a user