// AuthGuard client SDK for C# (.NET 6+). // Requires the NuGet package NSec.Cryptography (Ed25519): dotnet add package NSec.Cryptography using System; using System.Collections.Generic; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Win32; using NSec.Cryptography; namespace AuthGuardSdk { public class AuthGuardException : Exception { public JsonElement? Response { get; } public AuthGuardException(string message, JsonElement? response = null) : base(message) { Response = response; } public bool UpdateRequired => Response is JsonElement r && r.TryGetProperty("update_required", out var u) && u.GetBoolean(); public string? DownloadUrl => Response is JsonElement r && r.TryGetProperty("download_url", out var d) && d.ValueKind == JsonValueKind.String ? d.GetString() : null; } public class AuthGuard { // The explicit user agent matters: some hosts' firewalls block requests that do not send one. private static readonly HttpClient Http = CreateClient(); private static HttpClient CreateClient() { var client = new HttpClient { Timeout = TimeSpan.FromSeconds(15) }; client.DefaultRequestHeaders.UserAgent.ParseAdd("AuthGuard-SDK/1.0"); return client; } private readonly string _appId, _version, _url; private readonly PublicKey _publicKey; private string? _sessionId; public string Hwid { get; } = GetHwid(); public JsonElement Info { get; private set; } public AuthGuard(string appId, string version, string publicKeyHex, string url = "https://authguard.dk/api/client") { _appId = appId; _version = version; _url = url; _publicKey = PublicKey.Import(SignatureAlgorithm.Ed25519, Convert.FromHexString(publicKeyHex), KeyBlobFormat.RawPublicKey); } public static string GetHwid() { string raw; try { using var key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"); raw = key?.GetValue("MachineGuid")?.ToString() ?? Environment.MachineName; } catch { raw = Environment.MachineName; } return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(raw))).ToLowerInvariant(); } private async Task Request(string type, Dictionary? fields = null) { var nonce = Convert.ToHexString(RandomNumberGenerator.GetBytes(16)).ToLowerInvariant(); var body = new Dictionary { ["type"] = type, ["app_id"] = _appId, ["nonce"] = nonce }; if (_sessionId != null && type != "init") body["sessionid"] = _sessionId; if (fields != null) foreach (var kv in fields) body[kv.Key] = kv.Value; string payload, signature; try { var res = await Http.PostAsync(_url, new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json")); using var outer = JsonDocument.Parse(await res.Content.ReadAsStringAsync()); payload = outer.RootElement.GetProperty("payload").GetString()!; signature = outer.RootElement.GetProperty("signature").GetString()!; } catch (Exception e) { throw new AuthGuardException("Could not reach the license server (" + e.GetType().Name + ")"); } byte[] sig; try { sig = Convert.FromHexString(signature); } catch { throw new AuthGuardException("Invalid server signature"); } if (!SignatureAlgorithm.Ed25519.Verify(_publicKey, Encoding.UTF8.GetBytes(payload), sig)) throw new AuthGuardException("Invalid server signature"); var data = JsonDocument.Parse(payload).RootElement.Clone(); var ts = data.GetProperty("timestamp").GetInt64(); if (data.GetProperty("nonce").GetString() != nonce || Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - ts) > 300) throw new AuthGuardException("Invalid server response"); if (!data.GetProperty("success").GetBoolean()) throw new AuthGuardException(data.GetProperty("message").GetString() ?? "Request failed", data); return data; } public async Task Init() { var data = await Request("init", new() { ["version"] = _version, ["hwid"] = Hwid }); _sessionId = data.GetProperty("sessionid").GetString(); } public async Task License(string key) => Info = (await Request("license", new() { ["key"] = key.Trim(), ["hwid"] = Hwid })).GetProperty("info"); public async Task Register(string username, string password, string key) => Info = (await Request("register", new() { ["username"] = username, ["password"] = password, ["key"] = key.Trim(), ["hwid"] = Hwid })).GetProperty("info"); public async Task Login(string username, string password) => Info = (await Request("login", new() { ["username"] = username, ["password"] = password, ["hwid"] = Hwid })).GetProperty("info"); public async Task Var(string name) => (await Request("var", new() { ["name"] = name })).GetProperty("value").GetString() ?? ""; public async Task Check() { try { await Request("check"); return true; } catch (AuthGuardException) { return false; } } } }