Š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
+40
View File
@@ -0,0 +1,40 @@
import 'package:sepot/core/constants/app_constants.dart';
import 'package:sepot/core/errors.dart';
import 'package:sepot/core/storage/secure_storage.dart' show DecoyPinConflict;
import 'package:sepot/l10n/generated/app_localizations.dart';
/// Přeloží chybu na větu pro uživatele.
///
/// Typované chyby (`SepotUserError`, `DecoyPinConflict`) mají vlastní
/// lokalizované hlášky; cokoli neznámého spadne do obecné hlášky
/// s technickým popisem — radši ošklivá pravda než němé selhání.
String describeError(AppLocalizations l10n, Object error) => switch (error) {
TrustRootChangedError() => l10n.errorTrustRootChanged,
RelayUnavailableError() => l10n.errorRelayUnavailable,
AttachmentTooLargeError(:final maxMb) =>
l10n.errorAttachmentTooLarge(maxMb),
GroupNeedsMemberError() => l10n.errorGroupNeedsMember,
GroupTooLargeError(:final maxMembers) =>
l10n.errorGroupMaxMembers(maxMembers),
MemberNoDeliveryAddressError(:final displayName) =>
l10n.errorMemberNoDeliveryAddress(displayName),
ContactNoDeliveryAddressError() => l10n.errorContactNoDeliveryAddress,
IdentityKeyMismatchError() => l10n.errorIdentityKeyMismatch,
MnemonicWordCountError(:final count, :final expected) =>
l10n.restoreErrorMnemonicWordCount(count, expected),
MnemonicInvalidError(:final detail) =>
l10n.restoreErrorInvalidMnemonic(detail),
BackupCorruptedError() => l10n.backupErrorCorruptedFile,
BackupUnknownFormatError() => l10n.backupErrorUnknownFormat,
BackupWrongIdentityError() => l10n.backupErrorWrongIdentity,
ContactAlreadyExistsError() => l10n.contactsErrorAlreadyExists,
ReportEmptyDescriptionError() => l10n.reportErrorEmptyDescription,
ReportConnectionError() =>
l10n.reportErrorConnection(AppConstants.supportEmail),
ReportRateLimitedError() =>
l10n.reportErrorRateLimited(AppConstants.supportEmail),
ReportServerError(:final statusCode) =>
l10n.reportErrorServer(statusCode, AppConstants.supportEmail),
DecoyPinConflict() => l10n.settingsDecoyPinConflict,
_ => l10n.errorGeneric(error.toString()),
};
+23
View File
@@ -0,0 +1,23 @@
import 'dart:ui';
import 'package:flutter/widgets.dart';
import 'package:sepot/l10n/generated/app_localizations.dart';
export 'package:sepot/l10n/generated/app_localizations.dart';
/// Zkratka pro přístup k lokalizovaným textům: `context.l10n.klic`.
extension L10nX on BuildContext {
AppLocalizations get l10n => AppLocalizations.of(this);
}
/// Lokalizace mimo widget tree (notifikace, headless push start).
///
/// Preferuje ruční volbu jazyka (`override`, typicky
/// `LocaleNotifier.readStored()`), jinak jazyk systému; nepodporovaný
/// jazyk spadne na angličtinu — stejné pořadí jako `supportedLocales`.
AppLocalizations l10nFor(Locale? override) {
final locale = override ?? PlatformDispatcher.instance.locale;
final lang = Locale(locale.languageCode);
final supported = AppLocalizations.delegate.isSupported(lang);
return lookupAppLocalizations(supported ? lang : const Locale('en'));
}