Security: Cloud-Auth auf Bearer-JWT umgestellt (IDOR-Luecke geschlossen)

- cloud_service: echter Login gegen baka-auth, Token statt X-API-Key/X-User
- app_config: hartcodierten API-Key-Default entfernt
- download_service + melo_logger: Bearer-Token statt X-API-Key
- navidrome: Passwort in flutter_secure_storage (Keychain/Keystore)
- song: token-haltige stream_url wird nicht mehr in SQLite persistiert
- cloud_screen: Pfad-Traversal beim Download-Dateinamen gefixt (p.basename)
- home_screen: Login-Dialog mit Passwort-Feld, Auto-Sync nutzt restoreLogin
This commit is contained in:
Hermes (Server)
2026-07-31 14:31:12 +02:00
parent 3e9389ab59
commit 9a880b0f21
17 changed files with 1552 additions and 181 deletions
+29
View File
@@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../models/song.dart';
import '../database/db_helper.dart';
@@ -63,6 +64,10 @@ class SubsonicAlbum {
class NavidromeService {
final DbHelper _db = DbHelper();
/// Passwort & Zugangsdaten liegen verschlüsselt im Keychain/Keystore
/// (flutter_secure_storage) statt im Klartext in SharedPreferences.
static const _secure = FlutterSecureStorage();
String _serverUrl = '';
String _user = '';
String _password = '';
@@ -80,6 +85,30 @@ class NavidromeService {
_token = md5.convert(utf8.encode(_password + _salt)).toString();
}
Future<void> ladeGespeicherteZugangsdaten() async {
try {
final url = await _secure.read(key: 'navidrome_url');
final user = await _secure.read(key: 'navidrome_user');
final pass = await _secure.read(key: 'navidrome_pass');
if (url != null && user != null && pass != null && url.isNotEmpty) {
setCredentials(url, user, pass);
}
} catch (e) {
debugPrint('Fehler beim Laden der Navidrome-Zugangsdaten: $e');
}
}
Future<void> speichereZugangsdaten(String url, String user, String password) async {
setCredentials(url, user, password);
try {
await _secure.write(key: 'navidrome_url', value: url);
await _secure.write(key: 'navidrome_user', value: user);
await _secure.write(key: 'navidrome_pass', value: password);
} catch (e) {
debugPrint('Fehler beim Speichern der Navidrome-Zugangsdaten: $e');
}
}
bool get istVerbunden => _serverUrl.isNotEmpty && _user.isNotEmpty;
Uri _uri(String endpoint, [Map<String, String>? extra]) {