Fix: Renew expired licenses from today and report the actual expiry

Preset renewal stored its target date as the old expiry plus the entered
days, while the authorization actually issued to the client is always
today plus a day count. For a license that had already expired, the
preset date was therefore in the past: SendPendingRenewal clamped the
day count to one, the client received a one-day license starting today,
but the renewal tip and the logs still printed the stale preset date.
The result was a message such as "renewed until 2026-05-30" while the
license really ran until tomorrow.

Presetting a renewal now bases the new date on today when the license
has already expired, and on the original expiry date otherwise, which
matches the one-day-per-day extension admins expect for live licenses.
The renewal dialog and the success prompt state which base was used, so
the computed date is never ambiguous. Renewal tips and both logging
paths (heartbeat-driven SendPendingRenewal and client-requested
GenerateRenewalInfo) now print the date that was actually issued, which
also corrects legacy preset records whose stored date has already
passed.

Co-Authored-By: deepseek-flash
This commit is contained in:
yuanyuanxianganddeepseek-flash committed 2026-10-19 15:15:49 +02:00
1 parent 39c8daa9b0
commit f76cd79bb0
2 files changed
+34 -12

No files matched your search

+14 -7
View File
@@ -7445,8 +7445,10 @@ std::pair<std::string, std::string> CMy2015RemoteDlg::GenerateRenewalInfo(
newHmac = std::to_string(hmacVal);
}
// 新 passcode 的到期日是“今天 + days” (见上面的 newPasscode);
// 预设日期已过去时 days 被钳制为 1,日志应显示实际日期。
Mprintf("[TOKEN_AUTH] 生成续期: %s, %s -> %s, %d并发数, 配额剩余%d\n",
sn.c_str(), currentExpire.c_str(), renewal.ExpireDate.c_str(), renewal.HostNum, renewal.Quota - 1);
sn.c_str(), currentExpire.c_str(), getDateStr(days).c_str(), renewal.HostNum, renewal.Quota - 1);
// 配额递减,配额用完后自动清除预设续期记录
DecrementPendingQuota(sn);
@@ -7546,13 +7548,18 @@ void CMy2015RemoteDlg::SendPendingRenewal(CONTEXT_OBJECT* ctx, const std::string
int days = (int)span.GetDays();
if (days <= 0) days = 1;
// 客户端按“今天 + days”签发新授权(CMD_AUTHORIZATION 使用 getDateStr(0/days))。
// 预设日期若已经过去(过期授权在旧版本中设置的预设),实际到期日是今天 + 1,
// 日志和提示必须显示实际日期,而不是已失效的预设日期。
std::string actualExpire = getDateStr(days);
// 构建并发送 CMD_AUTHORIZATION
if (source) {
Mprintf("[%s] 自动下发续期: %s, %s -> %s, %d并发数\n",
source, sn.c_str(), currentExpire.c_str(), renewal.ExpireDate.c_str(), renewal.HostNum);
source, sn.c_str(), currentExpire.c_str(), actualExpire.c_str(), renewal.HostNum);
} else {
Mprintf("自动下发续期: %s, %s -> %s, %d并发数\n",
sn.c_str(), currentExpire.c_str(), renewal.ExpireDate.c_str(), renewal.HostNum);
sn.c_str(), currentExpire.c_str(), actualExpire.c_str(), renewal.HostNum);
}
BYTE bToken[32] = { CMD_AUTHORIZATION };
@@ -7571,10 +7578,10 @@ void CMy2015RemoteDlg::SendPendingRenewal(CONTEXT_OBJECT* ctx, const std::string
bool hasRemainingQuota = DecrementPendingQuota(sn);
Mprintf("[HEARTBEAT] 续期下发完成: %s, 剩余配额: %s\n", sn.c_str(), hasRemainingQuota ? "有" : "无");
// 提示续期已下发
std::string expireFmt = renewal.ExpireDate.substr(0, 4) + "-" +
renewal.ExpireDate.substr(4, 2) + "-" +
renewal.ExpireDate.substr(6, 2);
// 提示续期已下发(显示实际到期日)
std::string expireFmt = actualExpire.substr(0, 4) + "-" +
actualExpire.substr(4, 2) + "-" +
actualExpire.substr(6, 2);
std::string tip = sn + g_Lang.Get(std::string(" 已自动续期至 ")) + expireFmt;
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
}
+20 -5
View File
@@ -563,6 +563,17 @@ void CLicenseDlg::OnLicenseRenewal()
if (defaultHostNum <= 0) defaultHostNum = 100;
int defaultQuota = lic.PendingQuota > 0 ? lic.PendingQuota : 1;
// 判断当前授权是否已过期。续期从“今天”起算:客户端收到 days 后按
// getDateStr(0) + days 签发新授权(见 CMD_AUTHORIZATION 处理)。
// 若从已过去的原到期日加天数,预设日期会落在过去,下发时被
// SendPendingRenewal 钳制成 1 天,实际到期日与预设/提示不一致。
CTime now = CTime::GetCurrentTime();
CTime today(now.GetYear(), now.GetMonth(), now.GetDay(), 0, 0, 0);
CString strToday;
strToday.Format(_T("%04d%02d%02d"), now.GetYear(), now.GetMonth(), now.GetDay());
bool expired = currentExpireDate.length() == 8 &&
currentExpireDate < std::string(CT2A(strToday));
// 格式化当前过期日期显示
CString strCurrentExpire;
if (currentExpireDate.length() == 8) {
@@ -570,6 +581,9 @@ void CLicenseDlg::OnLicenseRenewal()
currentExpireDate.substr(0, 4).c_str(),
currentExpireDate.substr(4, 2).c_str(),
currentExpireDate.substr(6, 2).c_str());
if (expired) {
strCurrentExpire += _L(" (已过期,续期从今天起算)");
}
} else {
strCurrentExpire = _TR("当前到期: 未知");
}
@@ -595,15 +609,13 @@ void CLicenseDlg::OnLicenseRenewal()
return;
}
// 计算新的过期日期 (从原到期日期开始加天数)
CTime baseTime;
if (currentExpireDate.length() == 8) {
// 计算新的过期日期:未过期从原到期日加天数;已过期从今天起算。
CTime baseTime = today;
if (!expired && currentExpireDate.length() == 8) {
int year = atoi(currentExpireDate.substr(0, 4).c_str());
int month = atoi(currentExpireDate.substr(4, 2).c_str());
int day = atoi(currentExpireDate.substr(6, 2).c_str());
baseTime = CTime(year, month, day, 0, 0, 0);
} else {
baseTime = CTime::GetCurrentTime(); // 无法解析时用当前日期
}
CTimeSpan span(days, 0, 0, 0);
CTime newExpireTime = baseTime + span;
@@ -635,6 +647,9 @@ void CLicenseDlg::OnLicenseRenewal()
CString msg;
msg.FormatL("已预设续期至: %s\n并发连接数: %d\n配额: %d (支持%d台机器续期)\n客户端上线时将自动下发新授权",
strPending, hostNum, quota, quota);
if (expired) {
msg += _L("\n(原授权已过期,续期从今天起算)");
}
MessageBox(msg, _TR("预设成功"), MB_ICONINFORMATION);
}
}