Feat: Sub-license count limit - LicenseLimit field in licenses.ini + context menu
- Add LicenseLimit field to LicenseInfo struct (0 = not set, unlimited) - Add GetLicenseLimit/SetLicenseLimit: read/write LicenseLimit key in licenses.ini - Append |lic:N to reserved field in TOKEN_AUTH response only when LicenseLimit > 0; absent |lic: means no limit (client defaults to 9999), so super admin authenticating to its own server is never falsely terminated - Add "Sub-license limit" item in CLicenseDlg right-click menu (1-9999, empty = clear limit); menu label shows current value in real time - Limit change takes effect when sub-client re-authenticates Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5391,15 +5391,20 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
|
||||
offset += 1; // 空的 frpConfig
|
||||
}
|
||||
|
||||
// Reserved 字段:签名 "sig:<base64(64字节ECDSA签名)>" 防假服务器
|
||||
// 签名消息: "SN|valid(0/1)",客户端可用已知信息重建并验签
|
||||
// Reserved 字段:签名 + 下级数量上限
|
||||
// 格式: "sig:<88字符base64>"(无限制)或 "sig:<88字符base64>|lic:<N>"(有限制)
|
||||
// 签名消息: "SN|valid(0/1)";|lic:N 仅当 LicenseLimit 显式配置(>0)时才写入,
|
||||
// 未配置(=0)则不写,客户端视为 9999(不限制)。超管自身无需配置,永不受限。
|
||||
if (!m_v2KeyPath.empty() && len > 20) {
|
||||
std::string snForSig(szBuffer + 1, szBuffer + 20);
|
||||
while (!snForSig.empty() && snForSig.back() == '\0') snForSig.pop_back();
|
||||
std::string signMsg = snForSig + "|" + (valid ? "1" : "0");
|
||||
BYTE sig[V2_SIGNATURE_SIZE];
|
||||
if (SignMessageV2(m_v2KeyPath.c_str(), (const BYTE*)signMsg.c_str(), (int)signMsg.size(), sig)) {
|
||||
int licLimit = GetLicenseLimit(snForSig);
|
||||
std::string reservedStr = "sig:" + base64Encode(sig, V2_SIGNATURE_SIZE);
|
||||
if (licLimit > 0)
|
||||
reservedStr += "|lic:" + std::to_string(licLimit);
|
||||
if (offset + reservedStr.size() + 1 < sizeof(resp)) {
|
||||
memcpy(resp + offset, reservedStr.c_str(), reservedStr.size() + 1);
|
||||
offset += reservedStr.size() + 1;
|
||||
|
||||
Reference in New Issue
Block a user