diff --git a/CHANGELOG.md b/CHANGELOG.md index d5c4f5f..8c837db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,38 @@ Format angelehnt an [Keep a Changelog](https://keepachangelog.com/de/1.0.0/). ## [Unreleased] +### 🔑 Manuelle Baka-Anmeldung ĂŒbernahm das neue Passwort nie dauerhaft; Auto-Login-Fehler wurde verworfen (2026-08-29) + +- 🐛 **Wer sich nach einer fehlgeschlagenen Auto-Anmeldung manuell im + "Baka-Konto"-Dialog mit dem korrekten (neuen) Passwort anmeldete, bekam + denselben Fehler beim nĂ€chsten App-Start (nach Ablauf des 7-Tage-Tokens) + garantiert wieder** — unabhĂ€ngig vom Server-Zustand. Grund: Navidrome- + und Baka-Konto teilen sich laut Design dieselben Zugangsdaten + (`navidrome_service.dart`), aber der manuelle Anmelde-Dialog + (`_AnmeldeDialogState._anmelden()` in `downloads_screen.dart`) schrieb + das eingegebene Passwort nur ins `BakaAuth`-Token — nie zurĂŒck in die + lokale Navidrome-Zugangsdaten-Ablage (`NavidromeService`), aus der + `BakaAuth.autoAnmelden()` sich beim nĂ€chsten Start bedient. Der manuelle + Login "half" also nur bis zum nĂ€chsten Token-Ablauf. +- 🔧 **Fix:** Nach erfolgreichem manuellem Login persistiert der Dialog die + neuen Zugangsdaten jetzt zusĂ€tzlich ĂŒber + `NavidromeService.speichereZugangsdaten(...)`. DafĂŒr bekam + `NavidromeService` einen fehlenden öffentlichen Getter `serverUrl`. +- 🐛 **`BakaAuth.autoAnmelden()` verwarf den Fehlertext von `anmelden()` + komplett** — aus der App war nicht diagnostizierbar, ob ein Auto-Login + an falschem Passwort, Rate-Limit oder Verbindungsfehler scheiterte. +- 🔧 **Fix:** neues Feld `BakaAuth.letzterAutoLoginFehler` hĂ€lt den + Fehlertext des letzten Auto-Login-Versuchs fest (zusĂ€tzlich per + `debugPrint` geloggt) — die bestehende Race-Condition-Absicherung ĂŒber + `_laufenderAutoLogin` bleibt unverĂ€ndert erhalten. +- ✅ **Getestet (RED→GREEN):** neuer Widget-Test in `online_screen_test.dart` + bestĂ€tigt, dass `nav.passwort`/`nav.benutzer` nach erfolgreichem + manuellem Login den neu eingegebenen Wert zeigen; neuer Unit-Test in + `baka_auth_test.dart` bestĂ€tigt, dass `letzterAutoLoginFehler` nach + einem fehlgeschlagenen `autoAnmelden()` den Fehlertext trĂ€gt statt + `null` zu bleiben. Volle Suite (601 Tests) grĂŒn, `flutter analyze` ohne + Befund. + ### 🎧 "Zuletzt" zeigte neu HinzugefĂŒgtes statt zuletzt Gehörtem; Herz saß fern vom Songnamen (2026-08-29) - 🐛 **Der Schnellzugriff "Zuletzt" auf "Meine Musik" zeigte "zuletzt hinzugefĂŒgte" Songs, diff --git a/lib/downloads/downloads_screen.dart b/lib/downloads/downloads_screen.dart index 5326a71..8fbdce1 100644 --- a/lib/downloads/downloads_screen.dart +++ b/lib/downloads/downloads_screen.dart @@ -903,6 +903,14 @@ class _AnmeldeDialogState extends State<_AnmeldeDialog> { final fehler = await auth.anmelden(_benutzer.text.trim(), _passwort.text); if (!mounted) return; if (fehler == null) { + // Navidrome- und Baka-Konto teilen sich die Zugangsdaten (siehe + // navidrome_service.dart) — ohne diese Übernahme wĂŒrde der nĂ€chste + // Auto-Login nach Ablauf des Baka-Tokens wieder mit dem alten + // Passwort scheitern. + final nav = context.read().navidrome; + await nav.speichereZugangsdaten( + nav.serverUrl, _benutzer.text.trim(), _passwort.text); + if (!mounted) return; Navigator.pop(context); return; } diff --git a/lib/services/baka_auth.dart b/lib/services/baka_auth.dart index 29c0cba..ca10d08 100644 --- a/lib/services/baka_auth.dart +++ b/lib/services/baka_auth.dart @@ -54,6 +54,10 @@ class BakaAuth extends ChangeNotifier { /// lösen beim App-Start gleichzeitig autoAnmelden aus). Future? _laufenderAutoLogin; + /// Fehlertext des letzten automatischen Anmeldeversuchs — fĂŒr Diagnose, + /// da autoAnmelden() (anders als anmelden()) keinen RĂŒckgabewert hat. + String? letzterAutoLoginFehler; + bool get istAngemeldet => _token != null && _token!.isNotEmpty; String get benutzer => _benutzer; @@ -114,11 +118,19 @@ class BakaAuth extends ChangeNotifier { /// authentifizierten Aufruf ohnehin automatisch. Future autoAnmelden(String benutzer, String passwort) async { if (istAngemeldet || benutzer.isEmpty || passwort.isEmpty) return; - _laufenderAutoLogin ??= anmelden(benutzer, passwort) + _laufenderAutoLogin ??= _autoAnmeldenIntern(benutzer, passwort) .whenComplete(() => _laufenderAutoLogin = null); await _laufenderAutoLogin; } + Future _autoAnmeldenIntern(String benutzer, String passwort) async { + final fehler = await anmelden(benutzer, passwort); + letzterAutoLoginFehler = fehler; + if (fehler != null) { + debugPrint('Auto-Anmeldung fehlgeschlagen: $fehler'); + } + } + Future abmelden() async { _token = null; _benutzer = ''; diff --git a/lib/services/navidrome_service.dart b/lib/services/navidrome_service.dart index a55bafe..92995af 100644 --- a/lib/services/navidrome_service.dart +++ b/lib/services/navidrome_service.dart @@ -145,6 +145,7 @@ class NavidromeService { /// Zugangsdaten. String get benutzer => _user; String get passwort => _password; + String get serverUrl => _serverUrl; /// Dekodiert eine Subsonic-JSON-Antwort und wirft [NavidromeException], /// wenn der Server `status:"failed"` meldet (z. B. falsches Passwort) — diff --git a/test/downloads/online_screen_test.dart b/test/downloads/online_screen_test.dart index d439c99..607104b 100644 --- a/test/downloads/online_screen_test.dart +++ b/test/downloads/online_screen_test.dart @@ -268,6 +268,39 @@ void main() { expect(feld.controller!.text, 'Tinker'); }); + testWidgets( + 'Erfolgreiches manuelles Anmelden ĂŒbernimmt das neue Passwort auch ' + 'fĂŒr Navidrome — sonst kommt der Auto-Login-Fehler nach Ablauf des ' + 'Baka-Tokens garantiert wieder', (tester) async { + final auth = BakaAuth( + client: MockClient((request) async { + final body = jsonDecode(request.body) as Map; + if (body['password'] == 'neuesPasswort') { + return http.Response(jsonEncode({'token': 'jwt-neu'}), 200); + } + return http.Response('', 500); + }), + speicher: _MemorySpeicher(), + ); + final nav = NavidromeService() + ..setCredentials('https://musik.baka-net.de', 'Tinker', 'altesPasswort'); + + await tester.pumpWidget(_wrap(auth, + db: db, categories: categories, navidrome: nav)); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Beim Baka-Konto anmelden')); + await tester.pumpAndSettle(); + + await tester.enterText(find.byType(TextField).last, 'neuesPasswort'); + await tester.tap(find.text('Anmelden')); + await tester.pumpAndSettle(); + + expect(nav.passwort, 'neuesPasswort'); + expect(nav.benutzer, 'Tinker'); + expect(auth.istAngemeldet, isTrue); + }); + testWidgets( 'Server-User meldet sich im Hintergrund mit denselben Zugangsdaten ' 'beim Baka-Konto an', (tester) async { diff --git a/test/services/baka_auth_test.dart b/test/services/baka_auth_test.dart index 97e5357..2e0b74f 100644 --- a/test/services/baka_auth_test.dart +++ b/test/services/baka_auth_test.dart @@ -139,6 +139,20 @@ void main() { expect(auth.benutzer, 'Tinker'); }); + test( + 'autoAnmelden merkt sich den Fehlergrund fĂŒr die Diagnose, da es ' + 'selbst keinen RĂŒckgabewert liefert', () async { + final client = MockClient((_) async => http.Response( + jsonEncode({'status': 'error', 'message': 'Falsches Passwort'}), + 200)); + final auth = BakaAuth(client: client, speicher: _MemorySpeicher()); + + await auth.autoAnmelden('Tinker', 'falsch'); + + expect(auth.letzterAutoLoginFehler, 'Falsches Passwort'); + expect(auth.istAngemeldet, isFalse); + }); + test('autoAnmelden tut nichts ohne Zugangsdaten', () async { var aufrufe = 0; final client = MockClient((_) async {