import 'dart:convert' show base64, utf8; import 'dart:convert' show jsonDecode, jsonEncode; import 'package:fotodocumentation/controller/base_controller.dart'; import 'package:fotodocumentation/dto/jwt_token_pair_dto.dart'; import 'package:fotodocumentation/main.dart' show logger; import 'package:fotodocumentation/utils/di_container.dart'; import 'package:fotodocumentation/utils/jwt_token_storage.dart'; import 'package:http/http.dart' as http; typedef AuthenticateReply = ({JwtTokenPairDto? jwtTokenPairDto}); abstract interface class LoginController { Future authenticate(String username, String password); Future refreshAccessToken(); bool isUsingJwtAuth(); } class LoginControllerImpl extends BaseController implements LoginController { final String path = "login"; JwtTokenStorage get _jwtTokenStorage => DiContainer.get(); @override Future authenticate(String username, String password) async { http.Client client = httpClientUtils.client; try { Header cred = _getLoginHeader(username, password); String uriStr = '${uriUtils.getBaseUrl()}$path'; Uri uri = Uri.parse(uriStr); var response = await client.get(uri, headers: {cred.name: cred.value}); if (response.statusCode == 200) { final Map data = Map.castFrom(jsonDecode(response.body)); final tokenPair = JwtTokenPairDto.fromJson(data); // Store tokens securely _jwtTokenStorage.saveTokens(tokenPair.accessToken, tokenPair.refreshToken); // Load user data using the new token return (jwtTokenPairDto: tokenPair); } else { logger.e('Authentication failed: ${response.statusCode} ${response.body}'); return (jwtTokenPairDto: null); } } catch (e) { logger.e("Authentication error: $e"); return (jwtTokenPairDto: null); } } @override Future refreshAccessToken() async { try { final refreshToken = _jwtTokenStorage.getRefreshToken(); if (refreshToken == null) { logger.i('No refresh token available'); return false; } String uriStr = '${uriUtils.getBaseUrl()}$path/login/refresh'; Uri uri = Uri.parse(uriStr); final response = await http.post( uri, headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'refreshToken': refreshToken, }), ); if (response.statusCode == 200) { final data = jsonDecode(response.body); final newAccessToken = data['accessToken'] as String; // Update only the access token (keep same refresh token) _jwtTokenStorage.updateAccessToken(newAccessToken); logger.d('Access token refreshed successfully'); return true; } else { logger.d('Token refresh failed: ${response.statusCode} ${response.body}'); return false; } } catch (e) { logger.e('Token refresh error: $e'); return false; } } @override bool isUsingJwtAuth() { return _jwtTokenStorage.hasTokens(); } Header _getLoginHeader(String username, String password) { String combined = "$username:$password"; final bytes = utf8.encode(combined); String asBase64 = base64.encode(bytes); return Header("Authorization", "Basic $asBase64"); } }