Nesco.Licensing 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Nesco.Licensing --version 1.0.0
                    
NuGet\Install-Package Nesco.Licensing -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nesco.Licensing" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nesco.Licensing" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Nesco.Licensing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nesco.Licensing --version 1.0.0
                    
#r "nuget: Nesco.Licensing, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nesco.Licensing@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nesco.Licensing&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Nesco.Licensing&version=1.0.0
                    
Install as a Cake Tool

🔐 LicenseActivation.Components

NuGet Version License: MIT .NET Blazor

Blazor component library for license activation with browser fingerprinting, EULA support, and token-based activation.

Features

  • MudLicenseActivationComponent - MudBlazor-based with Material Design
  • HtmlLicenseActivationComponent - Lightweight HTML/CSS implementation
  • Machine fingerprinting for device identification (consistent across browsers)
  • EULA acceptance workflow with dialog presentation
  • Two-step activation process (attempts without EULA first, then with EULA if required)
  • Parameter support for pre-filled EULA acceptance

Installation

dotnet add package Nesco.Licensing

Setup

1. Add to Program.cs

using LicenseActivation.Components.Extensions;
using MudBlazor.Services; // Only if using MudLicenseActivationComponent

// Add MudBlazor (only if using MudLicenseActivationComponent)
builder.Services.AddMudServices();

// Add License Activation services
builder.Services.AddNescoLicensing(options =>
{
    options.ApiBaseUrl = "https://your-api-url.com";
    options.PublicKey = "your-rsa-public-key"; // Optional for signature validation
});

2. Add to App.razor


<script src="_content/LicenseActivation.Components/js/lic.min.js"></script>

Component Usage

MudLicenseActivationComponent (requires MudBlazor)

@page "/license"
@using LicenseActivation.Components

<MudLicenseActivationComponent 
    ProductCode="YOUR_PRODUCT_CODE"
    AcceptedByName="@userName"       @* Optional: Pre-fill EULA name *@
    AcceptedByEmail="@userEmail"     @* Optional: Pre-fill EULA email *@
    MachineFingerprint="@machineId"  @* Optional: Override machine fingerprint *@
    OnActivationSuccess="OnSuccess"
    OnActivationError="OnError" />

@code {
    private async Task OnSuccess(TokenActivationResponse result)
    {
        // Handle successful activation
    }
    
    private async Task OnError(string error)
    {
        // Handle error
    }
}

HtmlLicenseActivationComponent (no dependencies)

@page "/license"
@using LicenseActivation.Components

<HtmlLicenseActivationComponent 
    ProductCode="YOUR_PRODUCT_CODE"
    AcceptedByName="@userName"       @* Optional: Pre-fill EULA name *@
    AcceptedByEmail="@userEmail"     @* Optional: Pre-fill EULA email *@
    MachineFingerprint="@machineId"  @* Optional: Override machine fingerprint *@
    OnActivationSuccess="OnSuccess"
    OnActivationError="OnError" />

HeartbeatTestComponent (testing utility)

@page "/heartbeat-test"
@using LicenseActivation.Components

<HeartbeatTestComponent />

This component provides a complete testing interface for heartbeat functionality with:

  • Input fields for activation ID, customer email, and machine fingerprint
  • Auto-generation of machine fingerprints when field is left empty
  • Real-time heartbeat testing with detailed results
  • Security token visualization
  • Response analysis and validation status display
  • Copy functionality for sharing test results

Component Parameters

Parameter Type Description
ProductCode string Required. Product code for license validation
AcceptedByName string? Pre-fill name for EULA acceptance
AcceptedByEmail string? Pre-fill email for EULA acceptance
MachineFingerprint string? Override machine fingerprint. When provided, disables manual input and skips auto-generation
OnActivationSuccess EventCallback<TokenActivationResponse> Success callback
OnActivationError EventCallback<string> Error callback

Service Methods (ILicenseActivationService)

The service is automatically registered when you call AddLicenseActivationComponent(). Available methods:

public interface ILicenseActivationService
{
    // Check for duplicate activations
    Task<DuplicateCheckResponse?> CheckDuplicateActivationAsync(LicenseActivationRequest request);
    
    // Deactivate a license
    Task<bool> DeactivateLicenseAsync(LicenseDeactivationRequest request);
    
    // Validate license status
    Task<LicenseValidationResponse?> ValidateLicenseAsync(LicenseValidationRequest request);
    
    // Send secure heartbeat to check activation validity with token-based authentication
    // Automatically generates machine fingerprint when MachineFingerprint is empty
    Task<HeartbeatResponse?> SendHeartbeatAsync(HeartbeatRequest request);
    
    // Activate with token (handles EULA requirements)
    Task<TokenActivationResponse> ActivateWithTokenAsync(TokenActivationRequest request);
}

HttpLicenseActivationService Implementation

  • Configured with base URL from settings
  • Endpoints:
    • POST /api/license/check-duplicate
    • POST /api/license/deactivate
    • POST /api/license/validate
    • POST /api/license/heartbeat
    • POST /api/license/activate

Key Features

Two-Step Activation Process

  1. First attempts activation without EULA
  2. If EULA is required, automatically opens dialog for acceptance
  3. After EULA acceptance, completes activation

EULA Acceptance

  • Modal dialog presentation
  • Pre-fillable name/email fields via parameters
  • Fields hidden when pre-filled values provided
  • Validation before activation

Machine Fingerprinting

Creates unique machine identifiers that are consistent across different browsers on the same machine using:

  • Hardware characteristics (CPU cores, memory, platform)
  • Physical display properties (resolution, color depth)
  • System settings (timezone, installed fonts)
  • GPU hardware capabilities (WebGL renderer, vendor)
  • Audio hardware specifications
  • All hashed with SHA-256 for privacy and uniqueness
Machine Fingerprint Parameter

Both activation components support an optional MachineFingerprint parameter that allows you to override the fingerprint behavior:


<MudLicenseActivationComponent ProductCode="MYPRODUCT" />


<MudLicenseActivationComponent 
    ProductCode="MYPRODUCT" 
    MachineFingerprint="custom-machine-identifier" />


<HtmlLicenseActivationComponent 
    ProductCode="MYPRODUCT" 
    MachineFingerprint="@storedMachineId" />

Behavior:

  • When MachineFingerprint is provided:

    • Uses the provided value as the machine fingerprint
    • Disables the manual Machine ID input field
    • Skips auto-generation completely
    • Field becomes read-only with visual indication
  • When MachineFingerprint is NOT provided:

    • User can manually enter a Machine ID (takes priority)
    • If Manual Machine ID is empty, auto-generates fingerprint
    • Field remains editable and functional

Use Cases:

  • Fixed Machine IDs: When you want to enforce a specific machine identifier
  • Integration with External Systems: Use fingerprints from other parts of your application
  • Testing: Provide consistent test machine identifiers
  • Custom Logic: Generate fingerprints using your own algorithm and pass them to the component

Secure Heartbeat System

The heartbeat system uses JWT-like tokens for enhanced security validation:

Usage Example:
// Inject the service
@inject ILicenseActivationService LicenseService

// Create heartbeat request with security token
var heartbeatRequest = new HeartbeatRequest(
    activationId: myActivationId,
    customerEmail: "user@company.com",
    machineFingerprint: "browser-fingerprint-hash"
);

// Send heartbeat (fingerprint auto-generated if empty)
var response = await LicenseService.SendHeartbeatAsync(heartbeatRequest);

if (response?.IsValid == true)
{
    // License is still valid
    Console.WriteLine($"License valid until: {response.ExpiryDate}");
}
else
{
    // License invalid or expired
    Console.WriteLine("License validation failed");
}
Periodic Heartbeat Implementation:
public class LicenseHeartbeatService : IHostedService, IDisposable
{
    private readonly ILicenseActivationService _licenseService;
    private Timer? _timer;
    private readonly Guid _activationId;
    private readonly string _customerEmail;
    private readonly string _machineFingerprint;

    public LicenseHeartbeatService(ILicenseActivationService licenseService)
    {
        _licenseService = licenseService;
        // Initialize with your application's values
        _activationId = GetStoredActivationId();
        _customerEmail = GetCurrentUserEmail();
        _machineFingerprint = GetBrowserFingerprint();
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Send heartbeat every 5 minutes
        _timer = new Timer(SendHeartbeat, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
        return Task.CompletedTask;
    }

    private async void SendHeartbeat(object? state)
    {
        try
        {
            var request = new HeartbeatRequest(_activationId, _customerEmail, _machineFingerprint);
            // Machine fingerprint is auto-generated if empty for consistent identification
            var response = await _licenseService.SendHeartbeatAsync(request);
            
            if (response?.IsValid != true)
            {
                // Handle license validation failure
                await HandleLicenseInvalidation();
            }
        }
        catch (Exception ex)
        {
            // Log heartbeat failure
            Console.WriteLine($"Heartbeat failed: {ex.Message}");
        }
    }

    private async Task HandleLicenseInvalidation()
    {
        // Implement your license invalidation logic
        // E.g., disable features, show reactivation dialog, etc.
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public void Dispose() => _timer?.Dispose();
}
Security Features:
  • Token-based Authentication: Uses JWT-like tokens containing {activationId}.{customerEmail}.{machineFingerprint}
  • Customer Validation: Optionally validates that the heartbeat customer matches the license customer
  • Machine Validation: Optionally validates that the heartbeat machine fingerprint matches the activation fingerprint
  • Configurable Security: License-level flags CheckCustomer and CheckFingerprint control validation behavior
  • Replay Attack Protection: Tokens include unique machine fingerprints and customer identifiers
  • Graceful Degradation: Empty customer emails or fingerprints are handled gracefully for testing scenarios
HeartbeatRequest Structure:
public class HeartbeatRequest
{
    public string Token { get; set; } // JWT-like security token
    
    // Read-only properties for accessing token components:
    public string ActivationId { get; }       // Parsed from token
    public string CustomerEmail { get; }      // Parsed from token  
    public string MachineFingerprint { get; } // Parsed from token
    
    // Constructor options:
    public HeartbeatRequest(string token);
    public HeartbeatRequest(Guid activationId, string customerEmail, string machineFingerprint);
}
HeartbeatResponse Structure:
public class HeartbeatResponse
{
    public bool IsValid { get; set; }              // Overall validity
    public bool IsActiveActivation { get; set; }   // Activation status
    public bool IsValidLicense { get; set; }       // License status
    public Guid ActivationId { get; set; }
    public string ProductName { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public string Params { get; set; }             // Product parameters
}
Error Handling:

The heartbeat system provides specific error messages for different validation failures:

  • "Invalid token format" - Token parsing failed
  • "Activation not found" - ActivationId doesn't exist in database
  • "License not found for this activation" - License associated with activation is missing
  • "The license does not belong to this customer" - Customer email validation failed (when CheckCustomer = true)
  • "The license does not belong to this machine" - Machine fingerprint validation failed (when CheckFingerprint = true)
Auto-Generated Fingerprints:

The SendHeartbeatAsync method automatically generates machine fingerprints when empty:

// Create request with empty fingerprint - will be auto-generated
var request = new HeartbeatRequest(activationId, customerEmail, "");
var response = await LicenseService.SendHeartbeatAsync(request);

// Create request with specific fingerprint - will use provided value
var request = new HeartbeatRequest(activationId, customerEmail, "specific-fingerprint");  
var response = await LicenseService.SendHeartbeatAsync(request);

Auto-Generation Behavior:

  • When MachineFingerprint is empty string: Automatically generates machine fingerprint
  • When MachineFingerprint has value: Uses the provided fingerprint
  • Cross-Browser Consistency: Generated fingerprints are the same across Chrome, Firefox, Edge, etc.
  • Hardware-Based: Uses actual machine characteristics, not browser-specific features
Best Practices:
  1. Store Activation Data Securely: Keep activation ID, customer email, and machine fingerprint in secure storage
  2. Use Auto-Generated Fingerprints: Pass empty string for machine fingerprint to enable automatic generation for consistent identification across browsers
  3. Handle Network Failures: Implement retry logic with exponential backoff for network errors
  4. Graceful Degradation: Continue operation when heartbeat fails, but limit functionality after extended failures
  5. Frequency Balance: Too frequent heartbeats waste bandwidth; too infrequent allows longer unauthorized usage
  6. Security Configuration: Enable CheckCustomer and CheckFingerprint for production licenses
  7. Monitor Heartbeat Health: Track successful/failed heartbeats for monitoring and analytics

Shared Utilities

The ActivationUtilities class provides:

  • ValidateLicenseToken() - Token validation with product code and signature checks
  • ValidateEulaAcceptance() - EULA field validation
  • GetFinalEulaValues() - Priority handling for parameter vs form values
  • IsEulaRequired() - Checks if response requires EULA

Requirements

  • .NET 9.0 or later
  • Blazor Server, WebAssembly, or Hybrid
  • MudBlazor 8.0+ (only for MudLicenseActivationComponent)

License

MIT License


Built with Blazor and MudBlazor

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 129 9/9/2025
1.0.0 114 9/7/2025