KyrosDev's picture
Initial commit: Complete KSTools License Management System
ad67bb9
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace KSTools.Licensing
{
/// <summary>
/// KSTools 授權管理器
/// 提供完整的授權管理功能,包括授權儲存、驗證、快取等
/// </summary>
public class LicenseManager
{
private const string REGISTRY_KEY_PATH = @"HKEY_CURRENT_USER\Software\KSTools\RevitPlugin";
private const string LICENSE_CODE_KEY = "LicenseCode";
private const string LICENSE_CACHE_KEY = "LicenseCache";
private const string LAST_VALIDATION_KEY = "LastValidation";
private const int VALIDATION_CACHE_HOURS = 1; // 快取驗證結果1小時
private readonly ApiClient _apiClient;
private readonly string _hardwareId;
/// <summary>
/// 初始化授權管理器
/// </summary>
/// <param name="apiBaseUrl">API 基礎 URL</param>
public LicenseManager(string apiBaseUrl = null)
{
_apiClient = new ApiClient(apiBaseUrl);
_hardwareId = HardwareFingerprint.GetHardwareId();
}
/// <summary>
/// 取得當前硬體指紋ID
/// </summary>
/// <returns>硬體指紋ID</returns>
public string GetHardwareId()
{
return _hardwareId;
}
/// <summary>
/// 取得硬體資訊摘要
/// </summary>
/// <returns>硬體資訊</returns>
public string GetHardwareInfo()
{
return HardwareFingerprint.GetHardwareInfo();
}
/// <summary>
/// 啟用授權並儲存到本地
/// </summary>
/// <param name="licenseCode">授權碼</param>
/// <returns>啟用結果</returns>
public async Task<ActivationResult> ActivateLicenseAsync(string licenseCode)
{
try
{
var result = await _apiClient.ActivateLicenseAsync(licenseCode, _hardwareId);
if (result.Success)
{
// 儲存授權碼到註冊表
StoreLicenseCode(licenseCode);
// 儲存快取資訊
StoreLicenseCache(result);
// 記錄最後驗證時間
StoreLastValidation();
}
return result;
}
catch (Exception ex)
{
return new ActivationResult
{
Success = false,
Message = $"啟用過程發生錯誤: {ex.Message}"
};
}
}
/// <summary>
/// 驗證授權 (使用快取機制)
/// </summary>
/// <param name="forceOnlineCheck">是否強制進行線上檢查</param>
/// <returns>驗證結果</returns>
public async Task<ValidationResult> ValidateLicenseAsync(bool forceOnlineCheck = false)
{
try
{
string licenseCode = GetStoredLicenseCode();
if (string.IsNullOrEmpty(licenseCode))
{
return new ValidationResult
{
Valid = false,
Message = "尚未啟用授權,請先輸入授權碼"
};
}
// 如果不強制線上檢查,先嘗試使用快取
if (!forceOnlineCheck)
{
var cachedResult = GetCachedValidation();
if (cachedResult != null)
{
return cachedResult;
}
}
// 進行線上驗證
var result = await _apiClient.ValidateLicenseAsync(licenseCode, _hardwareId);
if (result.Valid)
{
// 更新快取
StoreLicenseCache(new ActivationResult
{
Success = true,
Message = result.Message,
ExpiresAt = result.ExpiresAt,
UserName = result.UserName,
HardwareId = result.HardwareId
});
StoreLastValidation();
}
else
{
// 驗證失敗,清除快取
ClearLicenseCache();
}
return result;
}
catch (Exception ex)
{
// 網路錯誤時,嘗試使用快取的驗證結果
var cachedResult = GetCachedValidation();
if (cachedResult != null)
{
cachedResult.Message += " (離線模式)";
return cachedResult;
}
return new ValidationResult
{
Valid = false,
Message = $"驗證過程發生錯誤: {ex.Message}"
};
}
}
/// <summary>
/// 檢查是否已有有效授權 (快速檢查)
/// </summary>
/// <returns>是否有有效授權</returns>
public bool HasValidLicense()
{
try
{
string licenseCode = GetStoredLicenseCode();
if (string.IsNullOrEmpty(licenseCode))
return false;
var cachedResult = GetCachedValidation();
return cachedResult?.Valid == true;
}
catch
{
return false;
}
}
/// <summary>
/// 取得授權資訊
/// </summary>
/// <returns>授權資訊,如果沒有授權則返回 null</returns>
public LicenseInfo GetLicenseInfo()
{
try
{
string licenseCode = GetStoredLicenseCode();
if (string.IsNullOrEmpty(licenseCode))
return null;
var cachedData = GetRegistryValue(LICENSE_CACHE_KEY);
if (!string.IsNullOrEmpty(cachedData))
{
var parts = cachedData.Split('|');
if (parts.Length >= 4)
{
return new LicenseInfo
{
LicenseCode = licenseCode,
UserName = parts[0],
ExpiresAt = DateTime.TryParse(parts[1], out var expires) ? expires : (DateTime?)null,
HardwareId = parts[2],
LastValidation = DateTime.TryParse(parts[3], out var lastVal) ? lastVal : (DateTime?)null
};
}
}
return new LicenseInfo
{
LicenseCode = licenseCode,
HardwareId = _hardwareId
};
}
catch
{
return null;
}
}
/// <summary>
/// 清除儲存的授權資訊
/// </summary>
public void ClearLicense()
{
try
{
Registry.SetValue(REGISTRY_KEY_PATH, LICENSE_CODE_KEY, "");
ClearLicenseCache();
}
catch
{
// 忽略錯誤
}
}
/// <summary>
/// 測試 API 連接
/// </summary>
/// <returns>是否連接成功</returns>
public async Task<bool> TestApiConnectionAsync()
{
return await _apiClient.TestConnectionAsync();
}
#region 私有方法
/// <summary>
/// 儲存授權碼到註冊表
/// </summary>
/// <param name="licenseCode">授權碼</param>
private void StoreLicenseCode(string licenseCode)
{
Registry.SetValue(REGISTRY_KEY_PATH, LICENSE_CODE_KEY, licenseCode);
}
/// <summary>
/// 從註冊表取得授權碼
/// </summary>
/// <returns>授權碼</returns>
private string GetStoredLicenseCode()
{
return GetRegistryValue(LICENSE_CODE_KEY);
}
/// <summary>
/// 儲存授權快取資訊
/// </summary>
/// <param name="result">啟用或驗證結果</param>
private void StoreLicenseCache(ActivationResult result)
{
string cacheData = $"{result.UserName}|{result.ExpiresAt}|{result.HardwareId}|{DateTime.Now}";
Registry.SetValue(REGISTRY_KEY_PATH, LICENSE_CACHE_KEY, cacheData);
}
/// <summary>
/// 記錄最後驗證時間
/// </summary>
private void StoreLastValidation()
{
Registry.SetValue(REGISTRY_KEY_PATH, LAST_VALIDATION_KEY, DateTime.Now.ToString());
}
/// <summary>
/// 取得快取的驗證結果
/// </summary>
/// <returns>驗證結果,如果快取無效則返回 null</returns>
private ValidationResult GetCachedValidation()
{
try
{
string lastValidationStr = GetRegistryValue(LAST_VALIDATION_KEY);
if (string.IsNullOrEmpty(lastValidationStr))
return null;
if (!DateTime.TryParse(lastValidationStr, out var lastValidation))
return null;
// 檢查快取是否過期
if (DateTime.Now - lastValidation > TimeSpan.FromHours(VALIDATION_CACHE_HOURS))
return null;
string cacheData = GetRegistryValue(LICENSE_CACHE_KEY);
if (string.IsNullOrEmpty(cacheData))
return null;
var parts = cacheData.Split('|');
if (parts.Length < 4)
return null;
DateTime.TryParse(parts[1], out var expiresAt);
// 檢查是否已過期
if (expiresAt > DateTime.MinValue && expiresAt < DateTime.Now)
{
return new ValidationResult
{
Valid = false,
Message = "授權已過期"
};
}
return new ValidationResult
{
Valid = true,
Message = "授權有效 (快取)",
ExpiresAt = expiresAt > DateTime.MinValue ? expiresAt : (DateTime?)null,
UserName = parts[0],
HardwareId = parts[2]
};
}
catch
{
return null;
}
}
/// <summary>
/// 清除授權快取
/// </summary>
private void ClearLicenseCache()
{
try
{
Registry.SetValue(REGISTRY_KEY_PATH, LICENSE_CACHE_KEY, "");
Registry.SetValue(REGISTRY_KEY_PATH, LAST_VALIDATION_KEY, "");
}
catch
{
// 忽略錯誤
}
}
/// <summary>
/// 從註冊表取得值
/// </summary>
/// <param name="keyName">鍵名</param>
/// <returns></returns>
private string GetRegistryValue(string keyName)
{
try
{
return Registry.GetValue(REGISTRY_KEY_PATH, keyName, "")?.ToString() ?? "";
}
catch
{
return "";
}
}
#endregion
}
/// <summary>
/// 授權資訊
/// </summary>
public class LicenseInfo
{
/// <summary>
/// 授權碼
/// </summary>
public string LicenseCode { get; set; }
/// <summary>
/// 用戶名稱
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 到期時間
/// </summary>
public DateTime? ExpiresAt { get; set; }
/// <summary>
/// 硬體指紋ID
/// </summary>
public string HardwareId { get; set; }
/// <summary>
/// 最後驗證時間
/// </summary>
public DateTime? LastValidation { get; set; }
/// <summary>
/// 是否即將到期 (7天內)
/// </summary>
public bool IsExpiringSoon => ExpiresAt.HasValue && ExpiresAt.Value.Subtract(DateTime.Now).TotalDays <= 7;
/// <summary>
/// 剩餘天數
/// </summary>
public int DaysRemaining => ExpiresAt.HasValue ? Math.Max(0, (int)ExpiresAt.Value.Subtract(DateTime.Now).TotalDays) : 0;
}
}