|
1 | 1 | import 'package:flutter/foundation.dart'; |
2 | 2 | import 'package:hive_flutter/hive_flutter.dart'; |
| 3 | +import 'secure_credential_storage.dart'; |
3 | 4 |
|
4 | 5 | enum HiveBoxType { normal, lazy } |
5 | 6 |
|
@@ -127,11 +128,110 @@ class HiveHandler { |
127 | 128 | environmentBox.put(kKeyEnvironmentBoxIds, ids); |
128 | 129 |
|
129 | 130 | dynamic getEnvironment(String id) => environmentBox.get(id); |
| 131 | + |
| 132 | + /// Sets environment with automatic encryption of secrets |
130 | 133 | Future<void> setEnvironment( |
131 | | - String id, Map<String, dynamic>? environmentJson) => |
132 | | - environmentBox.put(id, environmentJson); |
| 134 | + String id, Map<String, dynamic>? environmentJson) async { |
| 135 | + if (environmentJson == null) { |
| 136 | + return environmentBox.put(id, null); |
| 137 | + } |
| 138 | + |
| 139 | + // Create a copy to avoid modifying the original |
| 140 | + final secureEnvData = Map<String, dynamic>.from(environmentJson); |
| 141 | + |
| 142 | + // Check if values array exists and process secrets |
| 143 | + if (secureEnvData['values'] is List) { |
| 144 | + final values = secureEnvData['values'] as List; |
| 145 | + |
| 146 | + for (var i = 0; i < values.length; i++) { |
| 147 | + final variable = values[i]; |
| 148 | + |
| 149 | + if (variable is Map && |
| 150 | + variable['type'] == 'secret' && |
| 151 | + variable['value'] != null && |
| 152 | + variable['value'].toString().isNotEmpty) { |
| 153 | + |
| 154 | + // Store secret in secure storage |
| 155 | + try { |
| 156 | + await SecureCredentialStorage.storeEnvironmentSecret( |
| 157 | + environmentId: id, |
| 158 | + variableKey: variable['key'] ?? 'unknown_$i', |
| 159 | + value: variable['value'].toString(), |
| 160 | + ); |
| 161 | + |
| 162 | + // Replace value with placeholder in Hive |
| 163 | + secureEnvData['values'][i] = { |
| 164 | + ...variable, |
| 165 | + 'value': '***SECURE***', |
| 166 | + 'isEncrypted': true, |
| 167 | + }; |
| 168 | + } catch (e) { |
| 169 | + // If secure storage fails, keep original value but log |
| 170 | + // In production, consider proper error handling |
| 171 | + } |
| 172 | + } |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + return environmentBox.put(id, secureEnvData); |
| 177 | + } |
| 178 | + |
| 179 | + /// Gets environment with automatic decryption of secrets |
| 180 | + Future<Map<String, dynamic>?> getEnvironmentSecure(String id) async { |
| 181 | + final data = environmentBox.get(id); |
| 182 | + if (data == null) return null; |
| 183 | + |
| 184 | + // Create a copy to modify |
| 185 | + final envData = Map<String, dynamic>.from(data); |
133 | 186 |
|
134 | | - Future<void> deleteEnvironment(String id) => environmentBox.delete(id); |
| 187 | + // Process encrypted values |
| 188 | + if (envData['values'] is List) { |
| 189 | + final values = List.from(envData['values']); |
| 190 | + |
| 191 | + for (var i = 0; i < values.length; i++) { |
| 192 | + final variable = values[i]; |
| 193 | + |
| 194 | + if (variable is Map && |
| 195 | + variable['isEncrypted'] == true && |
| 196 | + variable['type'] == 'secret') { |
| 197 | + |
| 198 | + // Retrieve secret from secure storage |
| 199 | + try { |
| 200 | + final decryptedValue = await SecureCredentialStorage.retrieveEnvironmentSecret( |
| 201 | + environmentId: id, |
| 202 | + variableKey: variable['key'] ?? 'unknown_$i', |
| 203 | + ); |
| 204 | + |
| 205 | + if (decryptedValue != null) { |
| 206 | + values[i] = { |
| 207 | + ...variable, |
| 208 | + 'value': decryptedValue, |
| 209 | + 'isEncrypted': false, |
| 210 | + }; |
| 211 | + } |
| 212 | + } catch (e) { |
| 213 | + // If decryption fails, keep placeholder |
| 214 | + } |
| 215 | + } |
| 216 | + } |
| 217 | + |
| 218 | + envData['values'] = values; |
| 219 | + } |
| 220 | + |
| 221 | + return envData; |
| 222 | + } |
| 223 | + |
| 224 | + Future<void> deleteEnvironment(String id) async { |
| 225 | + // Clean up secure storage for this environment |
| 226 | + try { |
| 227 | + await SecureCredentialStorage.clearEnvironmentSecrets( |
| 228 | + environmentId: id, |
| 229 | + ); |
| 230 | + } catch (e) { |
| 231 | + // Log error but continue with deletion |
| 232 | + } |
| 233 | + return environmentBox.delete(id); |
| 234 | + } |
135 | 235 |
|
136 | 236 | dynamic getHistoryIds() => historyMetaBox.get(kHistoryBoxIds); |
137 | 237 | Future<void> setHistoryIds(List<String>? ids) => |
|
0 commit comments