import 'dart:convert'; import 'dart:io'; import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as path; const defaultEndpoint = 'http://localhost:7700'; const defaultApiKey = 'masterKey'; // Cache for configuration String? _cachedEndpoint; String? _cachedApiKey; bool _isInitialized = false; // Get the config file path in the user's home directory Future _getConfigPath() async { final home = Platform.environment['HOME'] ?? Platform.environment['USERPROFILE']; if (home == null) { throw Exception('Could not find home directory'); } final configDir = Directory(path.join(home, '.journaler')); if (!await configDir.exists()) { await configDir.create(recursive: true); } return path.join(configDir.path, 'meilisearch_config.enc'); } // Simple encryption key derived from machine-specific data String _getEncryptionKey() { final machineId = Platform.operatingSystem + Platform.operatingSystemVersion + Platform.localHostname; return sha256.convert(utf8.encode(machineId)).toString(); } // Encrypt data String _encrypt(String data) { final key = _getEncryptionKey(); final bytes = utf8.encode(data); final encrypted = []; for (var i = 0; i < bytes.length; i++) { encrypted.add(bytes[i] ^ key.codeUnitAt(i % key.length)); } return base64.encode(encrypted); } // Decrypt data String _decrypt(String encrypted) { final key = _getEncryptionKey(); final bytes = base64.decode(encrypted); final decrypted = []; for (var i = 0; i < bytes.length; i++) { decrypted.add(bytes[i] ^ key.codeUnitAt(i % key.length)); } return utf8.decode(decrypted); } // Initialize cache from file Future _initializeCache() async { if (_isInitialized) return; try { final configPath = await _getConfigPath(); final file = File(configPath); if (!await file.exists()) { _cachedEndpoint = defaultEndpoint; _cachedApiKey = defaultApiKey; _isInitialized = true; return; } final encrypted = await file.readAsString(); final decrypted = _decrypt(encrypted); final config = jsonDecode(decrypted); _cachedEndpoint = config['endpoint'] ?? defaultEndpoint; _cachedApiKey = config['apiKey'] ?? defaultApiKey; } catch (e) { _cachedEndpoint = defaultEndpoint; _cachedApiKey = defaultApiKey; } _isInitialized = true; } Future getMeilisearchEndpoint() async { await _initializeCache(); return _cachedEndpoint!; } Future getMeilisearchApiKey() async { await _initializeCache(); return _cachedApiKey!; } Future setMeilisearchEndpoint(String endpoint) async { final configPath = await _getConfigPath(); final file = File(configPath); Map config = {}; if (await file.exists()) { final encrypted = await file.readAsString(); final decrypted = _decrypt(encrypted); config = jsonDecode(decrypted); } config['endpoint'] = endpoint; final encrypted = _encrypt(jsonEncode(config)); await file.writeAsString(encrypted); // Update cache _cachedEndpoint = endpoint; } Future setMeilisearchApiKey(String apiKey) async { final configPath = await _getConfigPath(); final file = File(configPath); Map config = {}; if (await file.exists()) { final encrypted = await file.readAsString(); final decrypted = _decrypt(encrypted); config = jsonDecode(decrypted); } config['apiKey'] = apiKey; final encrypted = _encrypt(jsonEncode(config)); await file.writeAsString(encrypted); // Update cache _cachedApiKey = apiKey; }