using System.Text.Json;
using YZWater.Core.Models;
using YZWater.Core.Services;
namespace YZWater.Core.Tests.Services;
///
/// 配置文件路径锚定 + 敏感项落盘加密的回归测试
///
public class ConfigProtectionTests
{
private const string Token = "Hub-Token-S3cr3t";
[Fact]
public void HubToken_SerializedAsCiphertext()
{
if (!OperatingSystem.IsWindows()) return; // DPAPI 不可用时按明文降级
var config = new SystemConfig { HubToken = Token };
var json = JsonSerializer.Serialize(config);
Assert.DoesNotContain(Token, json);
Assert.Contains("enc:", json);
}
[Fact]
public void HubToken_SurvivesJsonRoundTrip()
{
if (!OperatingSystem.IsWindows()) return;
var json = JsonSerializer.Serialize(new SystemConfig { HubToken = Token });
ProtectedStringJsonConverter.BeginRead();
var restored = JsonSerializer.Deserialize(json);
Assert.Equal(Token, restored?.HubToken);
Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
}
[Fact]
public void LegacyPlaintextHubToken_StillReadableAndMarkedForRewrite()
{
ProtectedStringJsonConverter.BeginRead();
var restored = JsonSerializer.Deserialize("{\"HubToken\":\"" + Token + "\"}");
Assert.Equal(Token, restored?.HubToken);
Assert.True(ProtectedStringJsonConverter.NeedsRewrite);
// ConfigService 据此回写一次,第二次加载就不该再要求改写
var rewritten = JsonSerializer.Serialize(restored);
ProtectedStringJsonConverter.BeginRead();
var reloaded = JsonSerializer.Deserialize(rewritten);
Assert.Equal(Token, reloaded?.HubToken);
Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
}
[Fact]
public void UndecryptableCiphertext_FallsBackToEmptyInsteadOfThrowing()
{
// 配置文件从别的机器/别的 Windows 用户拷来时会走到这里
ProtectedStringJsonConverter.BeginRead();
var restored = JsonSerializer.Deserialize("{\"HubToken\":\"enc:not-valid-cipher-text\"}");
Assert.True(string.IsNullOrEmpty(restored?.HubToken));
Assert.True(ProtectedStringJsonConverter.DecryptFailed);
// 关键:解不开不等于"等待迁移"。若此处要求回写,ConfigService 会把这段密文
// 覆盖成空值(还会顺手污染 .lastgood),操作员原机上配的令牌就彻底没了。
Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
}
[Fact]
public void LegacyPlaintext_MarksRewriteButNotDecryptFailure()
{
ProtectedStringJsonConverter.BeginRead();
JsonSerializer.Deserialize("{\"HubToken\":\"" + Token + "\"}");
Assert.True(ProtectedStringJsonConverter.NeedsRewrite);
Assert.False(ProtectedStringJsonConverter.DecryptFailed);
}
[Fact]
public void EmptyHubToken_StaysEmptyAndNeedsNoRewrite()
{
ProtectedStringJsonConverter.BeginRead();
var restored = JsonSerializer.Deserialize(
JsonSerializer.Serialize(new SystemConfig { HubToken = string.Empty }));
Assert.Equal(string.Empty, restored?.HubToken);
Assert.False(ProtectedStringJsonConverter.NeedsRewrite);
}
}