using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Management;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace KeyNexus
{
///
/// KeyNexus .NET SDK Client
///
public class KeyNexusClient : IDisposable
{
private readonly HttpClient _httpClient;
private readonly string _appId;
private readonly string _secretKey;
private readonly string _apiUrl;
private string _sessionToken;
private string _hwid;
///
/// Initialize KeyNexus client
///
/// Your application ID from KeyNexus dashboard
/// Your secret key (keep this secure!)
/// API base URL (default: https://keynexus.es/api)
/// Automatically generate HWID (default: true)
public KeyNexusClient(string appId, string secretKey, string apiUrl = "https://keynexus.es/api", bool autoHwid = true)
{
_appId = appId ?? throw new ArgumentNullException(nameof(appId));
_secretKey = secretKey ?? throw new ArgumentNullException(nameof(secretKey));
_apiUrl = apiUrl.TrimEnd('/');
_httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
if (autoHwid)
{
_hwid = GenerateHWID();
}
}
///
/// Generate a unique hardware ID for this machine
///
/// Hardware ID string
public static string GenerateHWID()
{
try
{
var info = new StringBuilder();
// Get processor ID
using (var searcher = new ManagementObjectSearcher("SELECT ProcessorId FROM Win32_Processor"))
{
foreach (var obj in searcher.Get())
{
info.Append(obj["ProcessorId"]?.ToString() ?? "");
}
}
// Get motherboard serial
using (var searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard"))
{
foreach (var obj in searcher.Get())
{
info.Append(obj["SerialNumber"]?.ToString() ?? "");
}
}
// Get MAC address
using (var searcher = new ManagementObjectSearcher("SELECT MACAddress FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL"))
{
foreach (var obj in searcher.Get())
{
var mac = obj["MACAddress"]?.ToString();
if (!string.IsNullOrEmpty(mac))
{
info.Append(mac);
break;
}
}
}
// Create hash
using (var sha256 = SHA256.Create())
{
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(info.ToString()));
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
}
catch
{
// Fallback to machine name hash
using (var sha256 = SHA256.Create())
{
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(Environment.MachineName + Guid.NewGuid()));
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
}
}
///
/// Initialize application and verify it's active
///
/// Your application version
/// Initialization result
public async Task> InitializeAsync(string version = "1.0.0")
{
var data = new
{
action = "init",
appId = _appId,
secretKey = _secretKey,
version
};
var response = await PostAsync("/client", data);
return response;
}
///
/// Validate a license key
///
/// The license key to validate
/// Hardware ID (uses auto-generated if not provided)
/// Validation result with license info
public async Task> ValidateLicenseAsync(string licenseKey, string hwid = null)
{
var data = new
{
action = "license",
appId = _appId,
secretKey = _secretKey,
key = licenseKey,
hwid = hwid ?? _hwid
};
var response = await PostAsync("/client", data);
// Store session token if provided
if (response.Success && response.Data?.SessionToken != null)
{
_sessionToken = response.Data.SessionToken;
}
return response;
}
///
/// Login with username/password
///
/// User's username or email
/// User's password
/// Hardware ID (uses auto-generated if not provided)
/// Login result with user info and session token
public async Task> LoginWithPasswordAsync(string username, string password, string hwid = null)
{
var data = new
{
applicationId = _appId,
username,
password,
hwid = hwid ?? _hwid
};
var response = await PostAsync("/client/auth", data);
// Store session token
if (response.Success && response.Data?.Token != null)
{
_sessionToken = response.Data.Token;
}
return response;
}
///
/// Get current user information
///
/// Session token (uses stored token if not provided)
/// User information
public async Task> GetUserInfoAsync(string token = null)
{
var tokenToUse = token ?? _sessionToken;
if (string.IsNullOrEmpty(tokenToUse))
{
throw new InvalidOperationException("No active session. Please login first.");
}
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokenToUse);
try
{
var response = await _httpClient.GetAsync($"{_apiUrl}/client/me");
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject>(content);
}
finally
{
_httpClient.DefaultRequestHeaders.Authorization = null;
}
}
///
/// Logout current session
///
/// Logout result
public async Task> LogoutAsync()
{
if (string.IsNullOrEmpty(_sessionToken))
{
throw new InvalidOperationException("No active session");
}
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _sessionToken);
try
{
var response = await _httpClient.PostAsync($"{_apiUrl}/client/logout", null);
var content = await response.Content.ReadAsStringAsync();
// Clear session token
_sessionToken = null;
return JsonConvert.DeserializeObject>(content);
}
finally
{
_httpClient.DefaultRequestHeaders.Authorization = null;
}
}
///
/// Get the current hardware ID
///
/// Current HWID
public string GetHWID() => _hwid ?? GenerateHWID();
///
/// Manually set the hardware ID
///
/// Hardware ID to use
public void SetHWID(string hwid) => _hwid = hwid;
private async Task> PostAsync(string endpoint, object data)
{
try
{
var json = JsonConvert.SerializeObject(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{_apiUrl}{endpoint}", content);
var responseContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject>(responseContent);
}
catch (HttpRequestException ex)
{
return new KeyNexusResponse
{
Success = false,
Message = $"Network error: {ex.Message}"
};
}
catch (TaskCanceledException)
{
return new KeyNexusResponse
{
Success = false,
Message = "Request timeout"
};
}
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
#region Response Models
public class KeyNexusResponse
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("data")]
public T Data { get; set; }
}
public class AppInfo
{
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
}
public class LicenseInfo
{
[JsonProperty("license")]
public License License { get; set; }
[JsonProperty("sessionToken")]
public string SessionToken { get; set; }
}
public class License
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("expiresAt")]
public DateTime? ExpiresAt { get; set; }
[JsonProperty("daysLeft")]
public int? DaysLeft { get; set; }
}
public class UserInfo
{
[JsonProperty("user")]
public UserData User { get; set; }
[JsonProperty("token")]
public string Token { get; set; }
}
public class UserData
{
[JsonProperty("username")]
public string Username { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("subscriptionExpiry")]
public DateTime? SubscriptionExpiry { get; set; }
[JsonProperty("hwid")]
public string HWID { get; set; }
}
#endregion
}