ConfigProtectionTests.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using System.Text.Json;
  2. using YZWater.Core.Models;
  3. using YZWater.Core.Services;
  4. namespace YZWater.Core.Tests.Services;
  5. /// <summary>
  6. /// 配置文件路径锚定 + 敏感项落盘加密的回归测试
  7. /// </summary>
  8. public class ConfigProtectionTests
  9. {
  10. private const string Token = "Hub-Token-S3cr3t";
  11. [Fact]
  12. public void HubToken_SerializedAsCiphertext()
  13. {
  14. if (!OperatingSystem.IsWindows()) return; // DPAPI 不可用时按明文降级
  15. var config = new SystemConfig { HubToken = Token };
  16. var json = JsonSerializer.Serialize(config);
  17. Assert.DoesNotContain(Token, json);
  18. Assert.Contains("enc:", json);
  19. }
  20. [Fact]
  21. public void HubToken_SurvivesJsonRoundTrip()
  22. {
  23. if (!OperatingSystem.IsWindows()) return;
  24. var json = JsonSerializer.Serialize(new SystemConfig { HubToken = Token });
  25. ProtectedStringJsonConverter.BeginRead();
  26. var restored = JsonSerializer.Deserialize<SystemConfig>(json);
  27. Assert.Equal(Token, restored?.HubToken);
  28. Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
  29. }
  30. [Fact]
  31. public void LegacyPlaintextHubToken_StillReadableAndMarkedForRewrite()
  32. {
  33. ProtectedStringJsonConverter.BeginRead();
  34. var restored = JsonSerializer.Deserialize<SystemConfig>("{\"HubToken\":\"" + Token + "\"}");
  35. Assert.Equal(Token, restored?.HubToken);
  36. Assert.True(ProtectedStringJsonConverter.NeedsRewrite);
  37. // ConfigService 据此回写一次,第二次加载就不该再要求改写
  38. var rewritten = JsonSerializer.Serialize(restored);
  39. ProtectedStringJsonConverter.BeginRead();
  40. var reloaded = JsonSerializer.Deserialize<SystemConfig>(rewritten);
  41. Assert.Equal(Token, reloaded?.HubToken);
  42. Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
  43. }
  44. [Fact]
  45. public void UndecryptableCiphertext_FallsBackToEmptyInsteadOfThrowing()
  46. {
  47. // 配置文件从别的机器/别的 Windows 用户拷来时会走到这里
  48. ProtectedStringJsonConverter.BeginRead();
  49. var restored = JsonSerializer.Deserialize<SystemConfig>("{\"HubToken\":\"enc:not-valid-cipher-text\"}");
  50. Assert.True(string.IsNullOrEmpty(restored?.HubToken));
  51. Assert.True(ProtectedStringJsonConverter.DecryptFailed);
  52. // 关键:解不开不等于"等待迁移"。若此处要求回写,ConfigService 会把这段密文
  53. // 覆盖成空值(还会顺手污染 .lastgood),操作员原机上配的令牌就彻底没了。
  54. Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
  55. }
  56. [Fact]
  57. public void LegacyPlaintext_MarksRewriteButNotDecryptFailure()
  58. {
  59. ProtectedStringJsonConverter.BeginRead();
  60. JsonSerializer.Deserialize<SystemConfig>("{\"HubToken\":\"" + Token + "\"}");
  61. Assert.True(ProtectedStringJsonConverter.NeedsRewrite);
  62. Assert.False(ProtectedStringJsonConverter.DecryptFailed);
  63. }
  64. [Fact]
  65. public void EmptyHubToken_StaysEmptyAndNeedsNoRewrite()
  66. {
  67. ProtectedStringJsonConverter.BeginRead();
  68. var restored = JsonSerializer.Deserialize<SystemConfig>(
  69. JsonSerializer.Serialize(new SystemConfig { HubToken = string.Empty }));
  70. Assert.Equal(string.Empty, restored?.HubToken);
  71. Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
  72. }
  73. }