55 lines
2.2 KiB
C#
55 lines
2.2 KiB
C#
using System.Net.Http.Json;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Win32;
|
|
using PatchProbe.Cli.Auth;
|
|
using PatchProbe.Engine.Contracts.ApiModels;
|
|
|
|
namespace PatchProbe.Cli.Services;
|
|
|
|
internal sealed class EnrollmentService(
|
|
IHttpClientFactory httpClientFactory,
|
|
IDeviceCredentialStore credentialStore,
|
|
ILogger<EnrollmentService> logger)
|
|
{
|
|
public async Task EnrollAsync(string serverUrl, string enrollmentKey, CancellationToken ct = default)
|
|
{
|
|
using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
|
var publicKeySpki = Convert.ToBase64String(ecdsa.ExportSubjectPublicKeyInfo());
|
|
var privateKeyPkcs8 = Convert.ToBase64String(ecdsa.ExportPkcs8PrivateKey());
|
|
|
|
var requestBody = new EnrollmentRequest(
|
|
EnrollmentKey: enrollmentKey,
|
|
MachineName: Environment.MachineName,
|
|
DeviceFingerprint: GetMachineFingerprint(),
|
|
PublicKeySpki: publicKeySpki);
|
|
|
|
var http = httpClientFactory.CreateClient();
|
|
var url = $"{serverUrl.TrimEnd('/')}/api/enrollments";
|
|
|
|
logger.LogInformation("Enrolling device with server at {Url}", url);
|
|
|
|
var response = await http.PostAsJsonAsync(url, requestBody, ct);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<EnrollmentResponse>(cancellationToken: ct)
|
|
?? throw new InvalidOperationException("Server returned an empty enrollment response.");
|
|
|
|
credentialStore.Save(new DeviceCredentials(
|
|
DeviceId: result.DeviceId,
|
|
PrivateKeyPkcs8: privateKeyPkcs8,
|
|
ServerUrl: serverUrl));
|
|
|
|
logger.LogInformation("Enrollment complete — Device ID: {DeviceId}", result.DeviceId);
|
|
}
|
|
|
|
private static string GetMachineFingerprint()
|
|
{
|
|
// MachineGuid is a stable, per-install GUID set by Windows Setup.
|
|
using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography");
|
|
var guid = key?.GetValue("MachineGuid")?.ToString() ?? Environment.MachineName;
|
|
return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(guid))).ToLowerInvariant();
|
|
}
|
|
}
|