Š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
+63
View File
@@ -0,0 +1,63 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sepot/models/identity.dart';
import 'package:sepot/providers/storage_provider.dart';
/// Stav identity uživatele
class IdentityNotifier extends AsyncNotifier<LocalIdentity?> {
@override
Future<LocalIdentity?> build() async {
final storage = ref.read(storageProvider);
return storage.loadIdentity();
}
/// Vytvoř novou identitu
Future<LocalIdentity> createIdentity(String displayName) async {
final identity = await LocalIdentity.create(displayName);
final storage = ref.read(storageProvider);
await storage.saveIdentity(identity);
state = AsyncData(identity);
return identity;
}
/// Obnov identitu z 24slovné zálohovací fráze (recovery flow).
///
/// Obnoví IDENTITU (stejný klíč → stejný SEP kód a safety number, kontakty
/// tě dál poznají), ne historii zpráv. `LocalIdentity.recover` vyhodí
/// [FormatException] při neplatné frázi. Po uložení messaging_provider
/// sám spustí registraci u relaye (nová delivery adresa + bundle).
Future<LocalIdentity> recoverIdentity(
List<String> words, String displayName) async {
final identity = await LocalIdentity.recover(
mnemonicWords: words,
displayName: displayName,
);
final storage = ref.read(storageProvider);
await storage.saveIdentity(identity);
await storage.saveSeedPhrase(identity.mnemonic);
state = AsyncData(identity);
return identity;
}
/// Znovu načti z úložiště
Future<void> reload() async {
final storage = ref.read(storageProvider);
state = AsyncData(await storage.loadIdentity());
}
}
final identityProvider =
AsyncNotifierProvider<IdentityNotifier, LocalIdentity?>(
IdentityNotifier.new,
);
/// Zkontroluj, zda je onboarding hotový
final isOnboardingCompleteProvider = FutureProvider<bool>((ref) async {
final storage = ref.read(storageProvider);
return storage.isOnboardingComplete();
});
/// Zkontroluj, zda existuje PIN
final hasPinProvider = FutureProvider<bool>((ref) async {
final storage = ref.read(storageProvider);
return storage.hasPin();
});