This commit is contained in:
GukSang.Jin
2026-04-22 08:55:16 +08:00
parent c28eca82b6
commit 5771b1663f

View File

@@ -9,10 +9,10 @@ public sealed class PasswordAccessService : IPasswordAccessService
private const int ExpirationReminderDays = 3; private const int ExpirationReminderDays = 3;
private const string SettingsDirectoryName = "Cardiopulmonarybypasssystems"; private const string SettingsDirectoryName = "Cardiopulmonarybypasssystems";
private const string StatusFileName = "password-access.json"; private const string StatusFileName = "password-access.json";
public const string FirstStagePassword = "152026"; public const string FirstStagePassword = "152026001";
public const string SecondStagePassword = "302026"; public const string SecondStagePassword = "302026002";
private const int FirstStageDays = 15; private const int InitialAccessDays = 20;
private const int SecondStageDays = 30; private const int ExtendedAccessDays = 30;
private static readonly string StatusFilePath = Path.Combine( private static readonly string StatusFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
@@ -21,14 +21,14 @@ public sealed class PasswordAccessService : IPasswordAccessService
public PasswordAccessStatus GetStatus() public PasswordAccessStatus GetStatus()
{ {
var state = LoadState(); var state = LoadOrCreateState();
return BuildStatus(state, persistState: true); return BuildStatus(state, persistState: true);
} }
public bool TryUnlock(string password, out PasswordAccessStatus status, out string message) public bool TryUnlock(string password, out PasswordAccessStatus status, out string message)
{ {
var normalizedPassword = password?.Trim() ?? string.Empty; var normalizedPassword = password?.Trim() ?? string.Empty;
var state = LoadState(); var state = LoadOrCreateState();
var currentStatus = BuildStatus(state, persistState: true); var currentStatus = BuildStatus(state, persistState: true);
if (currentStatus.IsPermanent) if (currentStatus.IsPermanent)
@@ -38,82 +38,81 @@ public sealed class PasswordAccessService : IPasswordAccessService
return true; return true;
} }
if (currentStatus.Stage == 1 && currentStatus.CanLaunch) if (currentStatus.CanLaunch)
{ {
status = currentStatus; status = currentStatus;
message = "第 1 阶段仍在有效期内,无需再次输入密码。"; message = currentStatus.ShouldPromptAtStartup
return true; ? $"当前仍在有效期内,可直接进入系统;满 {GetStageDays(currentStatus.Stage)} 天后再输入密码。"
: $"{GetStageName(currentStatus.Stage)}仍在有效期内,无需再次输入密码。";
return false;
} }
if (currentStatus.Stage == 2 && currentStatus.CanLaunch) var expectedPassword = currentStatus.Stage switch
{ {
status = currentStatus; 0 => FirstStagePassword,
message = "第 2 阶段仍在有效期内,无需再次输入密码。"; 1 => SecondStagePassword,
return true; _ => string.Empty
}
var nextStage = currentStatus.Stage switch
{
<= 0 => 1,
1 => 2,
_ => 0
}; };
if (nextStage == 0)
{
status = BuildStatus(state, persistState: true);
message = "当前版本已转为永久有效,不再需要密码。";
return true;
}
var expectedPassword = nextStage == 1 ? FirstStagePassword : SecondStagePassword;
if (!string.Equals(normalizedPassword, expectedPassword, StringComparison.Ordinal)) if (!string.Equals(normalizedPassword, expectedPassword, StringComparison.Ordinal))
{ {
status = currentStatus; status = currentStatus;
message = $"密码错误,请输入第 {nextStage} 次时效密码。"; message = currentStatus.Stage switch
{
0 => "密码错误,请输入第 1 次时效密码。",
1 => "密码错误,请输入第 2 次时效密码。",
_ => "密码错误。"
};
return false; return false;
} }
var now = DateTime.Now; var now = DateTime.Now;
var expiresAt = now.AddDays(nextStage == 1 ? FirstStageDays : SecondStageDays);
if (currentStatus.Stage == 1)
{
var permanentState = new PasswordAccessState
{
Stage = 2,
ActivatedAt = state?.ActivatedAt ?? now,
ExpiresAt = null
};
SaveState(permanentState);
status = BuildStatus(permanentState, persistState: false);
message = "第 2 次密码验证通过,系统已永久有效。";
return true;
}
var expiresAt = now.AddDays(ExtendedAccessDays);
var nextState = new PasswordAccessState var nextState = new PasswordAccessState
{ {
Stage = nextStage, Stage = 1,
ActivatedAt = now, ActivatedAt = now,
ExpiresAt = expiresAt ExpiresAt = expiresAt
}; };
SaveState(nextState); SaveState(nextState);
status = BuildStatus(nextState, persistState: false); status = BuildStatus(nextState, persistState: false);
message = nextStage == 1 message = $"第 1 次密码验证通过,已继续开放 {ExtendedAccessDays} 天,有效期至 {expiresAt:yyyy-MM-dd HH:mm}。";
? $"第 1 次时效已生效,有效期至 {expiresAt:yyyy-MM-dd HH:mm}。"
: $"第 2 次时效已生效,有效期至 {expiresAt:yyyy-MM-dd HH:mm};到期后自动转为永久有效。";
return true; return true;
} }
private static PasswordAccessStatus BuildStatus(PasswordAccessState? state, bool persistState) private static PasswordAccessStatus BuildStatus(PasswordAccessState? state, bool persistState)
{ {
if (state is null || state.Stage <= 0) if (state is null)
{ {
return new PasswordAccessStatus state = CreateInitialState();
if (persistState)
{ {
Stage = 0, SaveState(state);
CanLaunch = false, }
IsPermanent = false,
ShouldPromptAtStartup = true,
CanSubmitPassword = true,
StageText = "当前阶段:未开始",
StatusTitle = "需要输入第 1 次时效密码",
StatusDetail = $"输入 15 天密码后进入系统。",
RemainingDays = 0
};
} }
if (state.Stage >= 3) if (state.Stage >= 2)
{ {
return new PasswordAccessStatus return new PasswordAccessStatus
{ {
Stage = 3, Stage = 2,
CanLaunch = true, CanLaunch = true,
IsPermanent = true, IsPermanent = true,
ShouldPromptAtStartup = false, ShouldPromptAtStartup = false,
@@ -129,63 +128,96 @@ public sealed class PasswordAccessService : IPasswordAccessService
if (state.ExpiresAt > now) if (state.ExpiresAt > now)
{ {
var remainingDays = Math.Max(1, (int)Math.Ceiling((state.ExpiresAt.Value - now).TotalDays)); var remainingDays = Math.Max(1, (int)Math.Ceiling((state.ExpiresAt.Value - now).TotalDays));
var isReminderWindow = remainingDays <= ExpirationReminderDays;
var isInitialStage = state.Stage == 0;
return new PasswordAccessStatus return new PasswordAccessStatus
{ {
Stage = state.Stage, Stage = state.Stage,
CanLaunch = true, CanLaunch = true,
IsPermanent = false, IsPermanent = false,
ShouldPromptAtStartup = state.Stage == 1 && remainingDays <= ExpirationReminderDays, ShouldPromptAtStartup = isReminderWindow,
CanSubmitPassword = state.Stage == 1 && remainingDays <= ExpirationReminderDays, CanSubmitPassword = false,
StageText = state.Stage == 1 ? "当前阶段:第 1 次时效15 天)" : "当前阶段:第 2时效30 天)", StageText = isInitialStage ? $"当前阶段:首次使用({InitialAccessDays} 天)" : $"当前阶段:第 1续期({ExtendedAccessDays} 天)",
StatusTitle = state.Stage == 1 && remainingDays <= ExpirationReminderDays ? "第 1 次时效即将到期" : "时效有效", StatusTitle = isReminderWindow
StatusDetail = state.Stage == 1 && remainingDays <= ExpirationReminderDays ? isInitialStage ? "首次使用即将到期" : "第 1 次续期即将到期"
? $"剩余 {remainingDays} 天,可提前输入 30 天密码。" : "时效有效",
StatusDetail = isReminderWindow
? isInitialStage
? $"剩余 {remainingDays} 天,到期后需输入第 1 次时效密码。"
: $"剩余 {remainingDays} 天,到期后需输入第 2 次时效密码。"
: $"当前可直接进入系统。", : $"当前可直接进入系统。",
RemainingDays = remainingDays, RemainingDays = remainingDays,
ExpiresAt = state.ExpiresAt ExpiresAt = state.ExpiresAt
}; };
} }
if (state.Stage == 1) if (state.Stage == 0)
{ {
return new PasswordAccessStatus return new PasswordAccessStatus
{ {
Stage = 1, Stage = 0,
CanLaunch = false, CanLaunch = false,
IsPermanent = false, IsPermanent = false,
ShouldPromptAtStartup = true, ShouldPromptAtStartup = true,
CanSubmitPassword = true, CanSubmitPassword = true,
StageText = "当前阶段:第 1 次时效已到期", StageText = "当前阶段:首次使用已到期",
StatusTitle = "需要输入第 2 次时效密码", StatusTitle = "需要输入第 1 次时效密码",
StatusDetail = $"输入 30 天密码后继续使用。", StatusDetail = $"输入密码后继续使用 {ExtendedAccessDays} 天。",
RemainingDays = 0, RemainingDays = 0,
ExpiresAt = state.ExpiresAt ExpiresAt = state.ExpiresAt
}; };
} }
var permanentState = new PasswordAccessState
{
Stage = 3,
ActivatedAt = state.ActivatedAt,
ExpiresAt = null
};
if (persistState)
{
SaveState(permanentState);
}
return new PasswordAccessStatus return new PasswordAccessStatus
{ {
Stage = 3, Stage = 1,
CanLaunch = true, CanLaunch = false,
IsPermanent = true, IsPermanent = false,
ShouldPromptAtStartup = false, ShouldPromptAtStartup = true,
CanSubmitPassword = false, CanSubmitPassword = true,
StageText = "当前阶段:永久有效", StageText = "当前阶段:第 1 次续期已到期",
StatusTitle = "系统已永久有效", StatusTitle = "需要输入第 2 次时效密码",
StatusDetail = "当前可直接进入系统。", StatusDetail = "输入密码后系统转为永久有效。",
RemainingDays = int.MaxValue RemainingDays = 0,
ExpiresAt = state.ExpiresAt
};
}
private static int GetStageDays(int stage) => stage switch
{
0 => InitialAccessDays,
1 => ExtendedAccessDays,
_ => 0
};
private static string GetStageName(int stage) => stage switch
{
0 => "首次使用阶段",
1 => "第 1 次续期阶段",
_ => "当前阶段"
};
private static PasswordAccessState LoadOrCreateState()
{
var state = LoadState();
if (state is not null)
{
return state;
}
var initialState = CreateInitialState();
SaveState(initialState);
return initialState;
}
private static PasswordAccessState CreateInitialState()
{
var now = DateTime.Now;
return new PasswordAccessState
{
Stage = 0,
ActivatedAt = now,
ExpiresAt = now.AddDays(InitialAccessDays)
}; };
} }