using System.Security.Cryptography; using System.Text.Json; using KronaStaffTerminal.Models; namespace KronaStaffTerminal.Services; public sealed class TerminalStore { private static readonly byte[] Entropy = "Krona.Staff.Terminal.v1"u8.ToArray(); private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; private readonly string _filePath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Krona", "StaffTerminal", "terminal-state.dat"); public async Task LoadAsync() { try { var sourcePath = File.Exists(_filePath) ? _filePath : FindLegacyPackagedState(); if (sourcePath is null) return new TerminalState(); var encrypted = await File.ReadAllBytesAsync(sourcePath); var clear = ProtectedData.Unprotect(encrypted, Entropy, DataProtectionScope.CurrentUser); var state = JsonSerializer.Deserialize(clear, JsonOptions) ?? new TerminalState(); var migrated = MigrateFingerprints(state); if (migrated || !string.Equals(sourcePath, _filePath, StringComparison.OrdinalIgnoreCase)) { await SaveAsync(state); } return state; } catch { return new TerminalState(); } } private static bool MigrateFingerprints(TerminalState state) { var changed = false; foreach (var employee in state.Employees) { employee.Fingerprints ??= []; if (employee.FingerprintId <= 0 || string.IsNullOrWhiteSpace(employee.FingerprintTemplate)) { continue; } if (employee.Fingerprints.All(item => item.Id != employee.FingerprintId)) { employee.Fingerprints.Add(new FingerprintRecord { Id = employee.FingerprintId, Template = employee.FingerprintTemplate, Label = "Отпечаток 1" }); } employee.FingerprintId = 0; employee.FingerprintTemplate = null; changed = true; } return changed; } public async Task SaveAsync(TerminalState state) { var directory = Path.GetDirectoryName(_filePath)!; Directory.CreateDirectory(directory); var clear = JsonSerializer.SerializeToUtf8Bytes(state, JsonOptions); var encrypted = ProtectedData.Protect(clear, Entropy, DataProtectionScope.CurrentUser); var temporaryPath = _filePath + ".tmp"; await File.WriteAllBytesAsync(temporaryPath, encrypted); File.Move(temporaryPath, _filePath, true); } private static string? FindLegacyPackagedState() { var packagesPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Packages"); if (!Directory.Exists(packagesPath)) return null; return Directory.EnumerateDirectories(packagesPath, "223A9635-262B-4298-9F19-1D2FE0A6B5F7_*") .Select(directory => Path.Combine(directory, "LocalCache", "Local", "Krona", "StaffTerminal", "terminal-state.dat")) .FirstOrDefault(File.Exists); } }