import 'package:flutter/foundation.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'secure_credential_storage.dart'; enum HiveBoxType { normal, lazy } const String kDataBox = "apidash-data"; const String kKeyDataBoxIds = "ids"; const String kEnvironmentBox = "apidash-environments"; const String kKeyEnvironmentBoxIds = "environmentIds"; const String kHistoryMetaBox = "apidash-history-meta"; const String kHistoryBoxIds = "historyIds"; const String kHistoryLazyBox = "apidash-history-lazy"; const String kDashBotBox = "apidash-dashbot-data"; const String kKeyDashBotBoxIds = 'messages'; const kHiveBoxes = [ (kDataBox, HiveBoxType.normal), (kEnvironmentBox, HiveBoxType.normal), (kHistoryMetaBox, HiveBoxType.normal), (kHistoryLazyBox, HiveBoxType.lazy), (kDashBotBox, HiveBoxType.lazy), ]; Future initHiveBoxes( bool initializeUsingPath, String? workspaceFolderPath, ) async { try { if (initializeUsingPath) { if (workspaceFolderPath != null) { Hive.init(workspaceFolderPath); } else { return false; } } else { await Hive.initFlutter(); } final openHiveBoxesStatus = await openHiveBoxes(); return openHiveBoxesStatus; } catch (e) { return false; } } Future openHiveBoxes() async { try { for (var box in kHiveBoxes) { if (box.$2 == HiveBoxType.normal) { await Hive.openBox(box.$1); } else if (box.$2 == HiveBoxType.lazy) { await Hive.openLazyBox(box.$1); } } return true; } catch (e) { debugPrint("ERROR OPEN HIVE BOXES: $e"); return false; } } Future clearHiveBoxes() async { try { for (var box in kHiveBoxes) { if (Hive.isBoxOpen(box.$1)) { if (box.$2 == HiveBoxType.normal) { await Hive.box(box.$1).clear(); } else if (box.$2 == HiveBoxType.lazy) { await Hive.lazyBox(box.$1).clear(); } } } } catch (e) { debugPrint("ERROR CLEAR HIVE BOXES: $e"); } } Future deleteHiveBoxes() async { try { for (var box in kHiveBoxes) { if (Hive.isBoxOpen(box.$1)) { if (box.$2 == HiveBoxType.normal) { await Hive.box(box.$1).deleteFromDisk(); } else if (box.$2 == HiveBoxType.lazy) { await Hive.lazyBox(box.$1).deleteFromDisk(); } } } await Hive.close(); } catch (e) { debugPrint("ERROR DELETE HIVE BOXES: $e"); } } final hiveHandler = HiveHandler(); class HiveHandler { late final Box dataBox; late final Box environmentBox; late final Box historyMetaBox; late final LazyBox historyLazyBox; late final LazyBox dashBotBox; HiveHandler() { debugPrint("Trying to open Hive boxes"); dataBox = Hive.box(kDataBox); environmentBox = Hive.box(kEnvironmentBox); historyMetaBox = Hive.box(kHistoryMetaBox); historyLazyBox = Hive.lazyBox(kHistoryLazyBox); dashBotBox = Hive.lazyBox(kDashBotBox); } dynamic getIds() => dataBox.get(kKeyDataBoxIds); Future setIds(List? ids) => dataBox.put(kKeyDataBoxIds, ids); dynamic getRequestModel(String id) => dataBox.get(id); Future setRequestModel( String id, Map? requestModelJson) => dataBox.put(id, requestModelJson); void delete(String key) => dataBox.delete(key); dynamic getEnvironmentIds() => environmentBox.get(kKeyEnvironmentBoxIds); Future setEnvironmentIds(List? ids) => environmentBox.put(kKeyEnvironmentBoxIds, ids); dynamic getEnvironment(String id) => environmentBox.get(id); /// Sets environment with automatic encryption of secrets Future setEnvironment( String id, Map? environmentJson) async { if (environmentJson == null) { return environmentBox.put(id, null); } // Create a copy to avoid modifying the original final secureEnvData = Map.from(environmentJson); // Check if values array exists and process secrets if (secureEnvData['values'] is List) { final values = secureEnvData['values'] as List; for (var i = 0; i < values.length; i++) { final variable = values[i]; if (variable is Map && variable['type'] == 'secret' && variable['value'] != null && variable['value'].toString().isNotEmpty) { // Store secret in secure storage try { await SecureCredentialStorage.storeEnvironmentSecret( environmentId: id, variableKey: variable['key'] ?? 'unknown_$i', value: variable['value'].toString(), ); // Replace value with placeholder in Hive secureEnvData['values'][i] = { ...variable, 'value': '***SECURE***', 'isEncrypted': true, }; } catch (e) { // If secure storage fails, keep original value but log // In production, consider proper error handling } } } } return environmentBox.put(id, secureEnvData); } /// Gets environment with automatic decryption of secrets Future?> getEnvironmentSecure(String id) async { final data = environmentBox.get(id); if (data == null) return null; // Create a copy to modify final envData = Map.from(data); // Process encrypted values if (envData['values'] is List) { final values = List.from(envData['values']); for (var i = 0; i < values.length; i++) { final variable = values[i]; if (variable is Map && variable['isEncrypted'] == true && variable['type'] == 'secret') { // Retrieve secret from secure storage try { final decryptedValue = await SecureCredentialStorage.retrieveEnvironmentSecret( environmentId: id, variableKey: variable['key'] ?? 'unknown_$i', ); if (decryptedValue != null) { values[i] = { ...variable, 'value': decryptedValue, 'isEncrypted': false, }; } } catch (e) { // If decryption fails, keep placeholder } } } envData['values'] = values; } return envData; } Future deleteEnvironment(String id) async { // Clean up secure storage for this environment try { await SecureCredentialStorage.clearEnvironmentSecrets( environmentId: id, ); } catch (e) { // Log error but continue with deletion } return environmentBox.delete(id); } dynamic getHistoryIds() => historyMetaBox.get(kHistoryBoxIds); Future setHistoryIds(List? ids) => historyMetaBox.put(kHistoryBoxIds, ids); dynamic getHistoryMeta(String id) => historyMetaBox.get(id); Future setHistoryMeta( String id, Map? historyMetaJson) => historyMetaBox.put(id, historyMetaJson); Future deleteHistoryMeta(String id) => historyMetaBox.delete(id); Future getHistoryRequest(String id) async => await historyLazyBox.get(id); Future setHistoryRequest( String id, Map? historyRequestJson) => historyLazyBox.put(id, historyRequestJson); Future deleteHistoryRequest(String id) => historyLazyBox.delete(id); Future getDashbotMessages() async => await dashBotBox.get(kKeyDashBotBoxIds); Future saveDashbotMessages(String messages) => dashBotBox.put(kKeyDashBotBoxIds, messages); Future clearAllHistory() async { await historyMetaBox.clear(); await historyLazyBox.clear(); } Future clear() async { await dataBox.clear(); await environmentBox.clear(); await historyMetaBox.clear(); await historyLazyBox.clear(); await dashBotBox.clear(); } Future removeUnused() async { var ids = getIds(); if (ids != null) { ids = ids as List; for (var key in dataBox.keys.toList()) { if (key != kKeyDataBoxIds && !ids.contains(key)) { await dataBox.delete(key); } } } var environmentIds = getEnvironmentIds(); if (environmentIds != null) { environmentIds = environmentIds as List; for (var key in environmentBox.keys.toList()) { if (key != kKeyEnvironmentBoxIds && !environmentIds.contains(key)) { await environmentBox.delete(key); } } } } }