feat: Logout-Warnung bei fehlendem Key-Backup (M1)
Beide Logout-Bestätigungsdialoge prüfen jetzt vorab per neuem isKeyBackupMissing(client) (bootstrap_dialog.dart), ob Cross-Signing/ Key-Backup eingerichtet ist. Fehlt es, zeigt der Dialog eine Klartext-Warnung: alte verschlüsselte Nachrichten wären nach dem Logout auf keinem Gerät mehr lesbar. Ohne fehlendes Backup bleibt der bisherige Text unverändert.
This commit is contained in:
+10
@@ -1134,3 +1134,13 @@
|
|||||||
2026-07-03 09:50 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
2026-07-03 09:50 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
2026-07-03 09:50 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
2026-07-03 09:50 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
2026-07-03 09:51 [Edit] /home/steggi/pyramid/lib/features/auth/login_notifier.dart
|
2026-07-03 09:51 [Edit] /home/steggi/pyramid/lib/features/auth/login_notifier.dart
|
||||||
|
2026-07-03 09:51 [Edit] /home/steggi/pyramid/ROADMAP.md
|
||||||
|
2026-07-03 09:52 [Edit] /home/steggi/pyramid/PROGRESS.md
|
||||||
|
2026-07-03 09:55 [Edit] /home/steggi/pyramid/ROADMAP.md
|
||||||
|
2026-07-03 09:55 [Edit] /home/steggi/pyramid/PROGRESS.md
|
||||||
|
2026-07-03 09:57 [Edit] /home/steggi/pyramid/lib/features/auth/bootstrap_dialog.dart
|
||||||
|
2026-07-03 09:58 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
|
2026-07-03 09:58 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
|
2026-07-03 09:58 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
|
2026-07-03 09:58 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
|
2026-07-03 09:58 [Edit] /home/steggi/pyramid/lib/widgets/settings_modal.dart
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ import 'package:matrix/encryption.dart';
|
|||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:pyramid/core/theme.dart';
|
import 'package:pyramid/core/theme.dart';
|
||||||
|
|
||||||
|
/// Ob Cross-Signing/Key-Backup fehlt oder nicht entsperrt ist — wenn ja, würde
|
||||||
|
/// ein Logout den Zugriff auf ältere verschlüsselte Nachrichten kosten.
|
||||||
|
Future<bool> isKeyBackupMissing(Client client) async {
|
||||||
|
final enc = client.encryption;
|
||||||
|
if (enc == null) return true;
|
||||||
|
if (!enc.crossSigning.enabled) return true;
|
||||||
|
return !(await enc.keyManager.isCached().catchError((_) => false));
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> showBootstrapDialog(
|
Future<void> showBootstrapDialog(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Client client, {
|
Client client, {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import 'package:pointycastle/export.dart' as pc;
|
|||||||
import 'package:pyramid/core/app_state.dart';
|
import 'package:pyramid/core/app_state.dart';
|
||||||
import 'package:pyramid/core/auth_log.dart';
|
import 'package:pyramid/core/auth_log.dart';
|
||||||
import 'package:pyramid/core/e2ee_diagnostics.dart';
|
import 'package:pyramid/core/e2ee_diagnostics.dart';
|
||||||
|
import 'package:pyramid/features/auth/bootstrap_dialog.dart' show isKeyBackupMissing;
|
||||||
import 'package:pyramid/core/livekit_call_manager.dart';
|
import 'package:pyramid/core/livekit_call_manager.dart';
|
||||||
import 'package:pyramid/core/matrix_client.dart';
|
import 'package:pyramid/core/matrix_client.dart';
|
||||||
import 'package:pyramid/core/voip_manager.dart';
|
import 'package:pyramid/core/voip_manager.dart';
|
||||||
@@ -567,6 +568,9 @@ class _LogoutNavButtonState extends ConsumerState<_LogoutNavButton> {
|
|||||||
|
|
||||||
Future<void> _logout() async {
|
Future<void> _logout() async {
|
||||||
final pt = widget.pt;
|
final pt = widget.pt;
|
||||||
|
final client = await ref.read(matrixClientProvider.future);
|
||||||
|
final backupMissing = await isKeyBackupMissing(client);
|
||||||
|
if (!mounted) return;
|
||||||
final confirmed = await showDialog<bool>(
|
final confirmed = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
@@ -575,8 +579,14 @@ class _LogoutNavButtonState extends ConsumerState<_LogoutNavButton> {
|
|||||||
borderRadius: BorderRadius.circular(pt.rXl), side: BorderSide(color: pt.border)),
|
borderRadius: BorderRadius.circular(pt.rXl), side: BorderSide(color: pt.border)),
|
||||||
title: Text('Abmelden?',
|
title: Text('Abmelden?',
|
||||||
style: TextStyle(color: pt.fg, fontSize: 16, fontWeight: FontWeight.w700)),
|
style: TextStyle(color: pt.fg, fontSize: 16, fontWeight: FontWeight.w700)),
|
||||||
content: Text('Du wirst von diesem Gerät abgemeldet.',
|
content: Text(
|
||||||
style: TextStyle(color: pt.fgMuted, fontSize: 13)),
|
backupMissing
|
||||||
|
? 'Du wirst von diesem Gerät abgemeldet. Es ist kein Schlüssel-Backup eingerichtet — '
|
||||||
|
'ältere verschlüsselte Nachrichten sind danach auf keinem Gerät mehr lesbar.'
|
||||||
|
: 'Du wirst von diesem Gerät abgemeldet.',
|
||||||
|
style: TextStyle(
|
||||||
|
color: backupMissing ? pt.danger : pt.fgMuted, fontSize: 13, height: 1.4),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(ctx, false),
|
onPressed: () => Navigator.pop(ctx, false),
|
||||||
@@ -596,7 +606,6 @@ class _LogoutNavButtonState extends ConsumerState<_LogoutNavButton> {
|
|||||||
setState(() => _loading = true);
|
setState(() => _loading = true);
|
||||||
try {
|
try {
|
||||||
widget.onClose();
|
widget.onClose();
|
||||||
final client = await ref.read(matrixClientProvider.future);
|
|
||||||
unawaited(AuthLog.write('User-initiated logout (Settings-Sidebar)'));
|
unawaited(AuthLog.write('User-initiated logout (Settings-Sidebar)'));
|
||||||
await client.logout();
|
await client.logout();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@@ -5108,6 +5117,9 @@ class _AboutSection extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _confirmLogout(BuildContext context, WidgetRef ref) async {
|
Future<void> _confirmLogout(BuildContext context, WidgetRef ref) async {
|
||||||
|
final client = await ref.read(matrixClientProvider.future);
|
||||||
|
final backupMissing = await isKeyBackupMissing(client);
|
||||||
|
if (!context.mounted) return;
|
||||||
final confirm = await showDialog<bool>(
|
final confirm = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (ctx) => AlertDialog(
|
||||||
@@ -5118,8 +5130,12 @@ class _AboutSection extends ConsumerWidget {
|
|||||||
title: Text('Abmelden?',
|
title: Text('Abmelden?',
|
||||||
style: TextStyle(color: pt.fg, fontSize: 16, fontWeight: FontWeight.w700)),
|
style: TextStyle(color: pt.fg, fontSize: 16, fontWeight: FontWeight.w700)),
|
||||||
content: Text(
|
content: Text(
|
||||||
'Du wirst auf diesem Gerät abgemeldet. Deine Nachrichten bleiben erhalten.',
|
backupMissing
|
||||||
style: TextStyle(color: pt.fgMuted, fontSize: 13),
|
? 'Du wirst auf diesem Gerät abgemeldet. Es ist kein Schlüssel-Backup eingerichtet — '
|
||||||
|
'ältere verschlüsselte Nachrichten sind danach auf keinem Gerät mehr lesbar.'
|
||||||
|
: 'Du wirst auf diesem Gerät abgemeldet. Deine Nachrichten bleiben erhalten.',
|
||||||
|
style: TextStyle(
|
||||||
|
color: backupMissing ? pt.danger : pt.fgMuted, fontSize: 13, height: 1.4),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -5139,7 +5155,6 @@ class _AboutSection extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (confirm == true) {
|
if (confirm == true) {
|
||||||
final client = await ref.read(matrixClientProvider.future);
|
|
||||||
unawaited(AuthLog.write('User-initiated logout (Settings)'));
|
unawaited(AuthLog.write('User-initiated logout (Settings)'));
|
||||||
await client.logout().catchError((_) {});
|
await client.logout().catchError((_) {});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user