using System.Security.Cryptography; using System.Text; using System.Text.Json; using LanMountainDesktop.Launcher.Models; namespace LanMountainDesktop.Launcher.Services; /// /// 隐私协议同意状态管理服务(带防篡改保护) /// internal sealed class PrivacyAgreementService { private readonly string _storagePath; private readonly string _secretKey; private const string ConfigFileName = "privacy-agreement.state.json"; private const string CurrentAgreementVersion = "1.0"; public PrivacyAgreementService(string launcherDataPath) { _storagePath = Path.Combine(launcherDataPath, ConfigFileName); // 使用机器特定信息生成密钥,增加篡改难度 _secretKey = GenerateMachineSpecificKey(); } /// /// 检查用户是否已同意隐私协议 /// public bool HasUserAgreed() { try { if (!File.Exists(_storagePath)) { Logger.Info("[PrivacyAgreementService] 未找到隐私协议同意状态文件"); return false; } var json = File.ReadAllText(_storagePath); var state = JsonSerializer.Deserialize(json, AppJsonContext.Default.PrivacyAgreementState); if (state == null) { Logger.Warn("[PrivacyAgreementService] 无法解析隐私协议状态文件"); return false; } // 验证数据完整性 if (!VerifyIntegrity(state)) { Logger.Warn("[PrivacyAgreementService] 隐私协议状态文件已被篡改!"); // 删除被篡改的文件 try { File.Delete(_storagePath); } catch (Exception ex) { Logger.Warn($"[PrivacyAgreementService] 删除被篡改文件失败: {ex.Message}"); } return false; } // 检查协议版本是否匹配 if (state.AgreementVersion != CurrentAgreementVersion) { Logger.Info($"[PrivacyAgreementService] 隐私协议版本已更新: {state.AgreementVersion} -> {CurrentAgreementVersion}"); return false; } Logger.Info($"[PrivacyAgreementService] 用户已于 {state.AgreedAtUtc:yyyy-MM-dd HH:mm:ss} UTC 同意隐私协议"); return state.IsAgreed; } catch (Exception ex) { Logger.Warn($"[PrivacyAgreementService] 检查同意状态时出错: {ex.Message}"); return false; } } /// /// 保存用户同意隐私协议的状态 /// public bool SaveAgreement(bool isAgreed, string userId, string deviceId) { try { // 确保目录存在 var directory = Path.GetDirectoryName(_storagePath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } // 生成随机盐值 var salt = GenerateRandomSalt(); var state = new PrivacyAgreementState { IsAgreed = isAgreed, AgreedAtUtc = DateTime.UtcNow, AgreementVersion = CurrentAgreementVersion, UserId = userId, DeviceId = deviceId, Salt = salt }; // 计算完整性哈希 state.IntegrityHash = CalculateIntegrityHash(state); // 保存到文件 var json = JsonSerializer.Serialize(state, AppJsonContext.Default.PrivacyAgreementState); File.WriteAllText(_storagePath, json); Logger.Info($"[PrivacyAgreementService] 隐私协议同意状态已保存: IsAgreed={isAgreed}"); return true; } catch (Exception ex) { Logger.Warn($"[PrivacyAgreementService] 保存同意状态失败: {ex.Message}"); return false; } } /// /// 获取当前的协议版本 /// public string GetCurrentAgreementVersion() => CurrentAgreementVersion; /// /// 清除同意状态(用于测试或重置) /// public bool ClearAgreement() { try { if (File.Exists(_storagePath)) { File.Delete(_storagePath); Logger.Info("[PrivacyAgreementService] 隐私协议同意状态已清除"); } return true; } catch (Exception ex) { Logger.Warn($"[PrivacyAgreementService] 清除同意状态失败: {ex.Message}"); return false; } } /// /// 生成机器特定的密钥 /// private string GenerateMachineSpecificKey() { try { // 组合多个机器特定信息生成密钥 var machineName = Environment.MachineName; var userName = Environment.UserName; var osVersion = Environment.OSVersion.Version.ToString(); var processorCount = Environment.ProcessorCount.ToString(); // 使用硬件信息(如果可用) var hardwareId = GetHardwareIdentifier(); var keyData = $"{machineName}:{userName}:{osVersion}:{processorCount}:{hardwareId}:LanMountainDesktop"; // 使用 SHA-256 生成固定长度的密钥 using var sha256 = SHA256.Create(); var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(keyData)); return Convert.ToHexString(hash); } catch { // 如果无法获取机器信息,使用备用密钥 return "LanMountainDesktop-Privacy-Agreement-Fallback-Key-2026"; } } /// /// 获取硬件标识符 /// private string GetHardwareIdentifier() { try { // 尝试使用系统目录创建时间作为硬件标识的一部分 var systemDir = Environment.SystemDirectory; var dirInfo = new DirectoryInfo(systemDir); return dirInfo.CreationTimeUtc.ToString("yyyyMMddHHmmss"); } catch { return "Unknown"; } } /// /// 生成随机盐值 /// private string GenerateRandomSalt() { var saltBytes = new byte[32]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(saltBytes); return Convert.ToHexString(saltBytes); } /// /// 计算完整性哈希(HMAC-SHA256) /// private string CalculateIntegrityHash(PrivacyAgreementState state) { // 构建需要哈希的数据字符串 var dataToHash = $"{state.IsAgreed}:{state.AgreedAtUtc:o}:{state.AgreementVersion}:{state.UserId}:{state.DeviceId}:{state.Salt}"; // 使用 HMAC-SHA256 计算哈希 using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_secretKey)); var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataToHash)); return Convert.ToHexString(hash); } /// /// 验证数据完整性 /// private bool VerifyIntegrity(PrivacyAgreementState state) { try { if (string.IsNullOrEmpty(state.IntegrityHash) || string.IsNullOrEmpty(state.Salt)) { return false; } var expectedHash = CalculateIntegrityHash(state); return CryptographicOperations.FixedTimeEquals( Encoding.UTF8.GetBytes(state.IntegrityHash), Encoding.UTF8.GetBytes(expectedHash)); } catch { return false; } } }