Update: 2026-08-06 18:32:03

This commit is contained in:
Hamza-Ayed
2026-08-06 18:32:03 +03:00
parent c759c80c85
commit ca3d456795
8 changed files with 416 additions and 41 deletions
+60 -23
View File
@@ -1,8 +1,41 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'api_config.dart';
import 'hmac_interceptor.dart';
import '../storage/secure_storage.dart';
/// Request/response fields that must never reach a log sink.
const _sensitiveKeys = {
'password',
'password_confirmation',
'old_password',
'new_password',
'otp',
'access_token',
'refresh_token',
'device_secret',
'push_token',
};
/// Replaces sensitive values with a placeholder, recursing into nested maps.
///
/// Logging raw payloads printed live credentials into Xcode/logcat, where they
/// persist well beyond the debug session.
Object? _redact(Object? data) {
if (data is Map) {
return data.map((key, value) => MapEntry(
key,
_sensitiveKeys.contains(key.toString().toLowerCase())
? '***'
: _redact(value),
));
}
if (data is List) {
return data.map(_redact).toList();
}
return data;
}
class DioClient {
static const String baseUrl = ApiConfig.baseUrl;
late final Dio dio;
@@ -23,29 +56,33 @@ class DioClient {
// Add Interceptors
dio.interceptors.add(HmacInterceptor(SecureStorage()));
// Custom Logging Interceptor as requested
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
print('--- API REQUEST ---');
print('URL: ${options.method} ${options.uri}');
print('Payload: ${options.data}');
return handler.next(options);
},
onResponse: (response, handler) {
print('--- API RESPONSE ---');
print('URL: ${response.requestOptions.method} ${response.requestOptions.uri}');
print('Status Code: ${response.statusCode}');
print('Response: ${response.data}');
return handler.next(response);
},
onError: (DioException e, handler) {
print('--- API ERROR ---');
print('URL: ${e.requestOptions.method} ${e.requestOptions.uri}');
print('Status Code: ${e.response?.statusCode}');
print('Response: ${e.response?.data ?? e.message}');
return handler.next(e);
},
));
// Logging interceptor. Debug builds only, and credentials are redacted:
// these used to be bare print() calls, which also ran in release builds.
if (kDebugMode) {
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
debugPrint('--- API REQUEST ---');
debugPrint('URL: ${options.method} ${options.uri}');
debugPrint('Payload: ${_redact(options.data)}');
return handler.next(options);
},
onResponse: (response, handler) {
debugPrint('--- API RESPONSE ---');
debugPrint(
'URL: ${response.requestOptions.method} ${response.requestOptions.uri}');
debugPrint('Status Code: ${response.statusCode}');
debugPrint('Response: ${_redact(response.data)}');
return handler.next(response);
},
onError: (DioException e, handler) {
debugPrint('--- API ERROR ---');
debugPrint('URL: ${e.requestOptions.method} ${e.requestOptions.uri}');
debugPrint('Status Code: ${e.response?.statusCode}');
debugPrint('Response: ${_redact(e.response?.data) ?? e.message}');
return handler.next(e);
},
));
}
}
Dio get client => dio;