Skip to content

Commit

Permalink
Feat: Enhance Serialization and Hardware Identification
Browse files Browse the repository at this point in the history
## Key Changes

* **Serialization Improvements:** Introduced a new serialization mechanism with `ILicenseSerializer` and `JsonLicenseSerializer` to enhance flexibility and support different serialization formats.
* **Custom Hardware Identification:**  Added `IHardwareIdentifier` interface and `DefaultHardwareIdentifier` to allow custom hardware identification logic.
* **Simplified Offline Validation Logic:** Refactored offline validation in `LicenseManager` to provide a more streamlined approach and allow bypassing built-in validation logic using `SetBuiltInValidation(bool enable)`.
* **Dependency Removal:** Removed the `DeviceId` NuGet package dependency.
* **Saving Arguments Conflict:** Updated the `SaveLicense` method in `LicenseBuilder` to `SaveLicenseToPath` to fix conflicts caused by `privateKey` parameter.
* **Updated Tests:** Updated the tests to reflect the changes in the library.

## Detailed Changes

### New Files

* **Interfaces/IHardwareIdentifier.cs:** Defines the interface for custom hardware identification.
* **Interfaces/ILicenseSerializer.cs:** Defines the interface for license serialization.
* **Serialization/JsonLicenseSerializer.cs:** Provides a JSON implementation of the `ILicenseSerializer` interface.
* **Serialization/Converters/JsonLicenseConverter.cs:**  A custom JSON converter for handling license type inheritance.
* **Utilities/DefaultHardwareIdentifier.cs:** Provides the default hardware identification logic.

### Modified Files

* **LicenseBuilder.cs:** Changed `SaveLicense` to call `LicenseManager.SaveLicenseToPath`.
* **LicenseGenerator.cs:**  Now uses `IHardwareIdentifier` for retrieving hardware IDs. Has a new internal `SetHardwareIdentifier` method.
* **LicenseManager.cs:**
    * Added `SetSerializer` and `SetHardwareIdentifier` methods.
    * Added `SetBuiltInValidation` method.
    * Renamed `SaveLicense` to `SaveLicenseToPath`.
    * Now uses `_serializer.Serialize` for serialization.
* **LicenseValidator.cs:**
    * Added `SetSerializer` and `SetHardwareIdentifier` methods.
    * Uses injected `_serializer` for deserialization.
    * `ValidateNodeLockedLicense` method now uses the injected `_hardwareIdentifier`.
* **Exceptions/InvalidLicenseFormatException.cs:** Added constructors with `innerException` parameter.
* **Aegis.csproj:**
    * Updated version to 1.3.0.
    * Removed the `DeviceId` package reference.
* **Utilities/HardwareUtils.cs:**  Functionality moved to the new `DefaultHardwareIdentifier` class. File deleted.
* **Utilities/LicenseUtils.cs:** No functional changes, but the `LoadLicenseSecrets` method documentation was updated.
* **Utilities/SecurityUtils.cs:** No functional changes, but the `CalculateSha256Hash` method is now public.

## Upgrade Considerations

* If you were relying on the specific hardware identification implementation of the previous version using `HardwareUtils`, you will need to inject your custom implementation of `IHardwareIdentifier` or use the new provided `DefaultHardwareIdentifier`.
* If you were using a different serialization mechanism, you can now implement the `ILicenseSerializer` interface and inject it using `LicenseManager.SetSerializer`.
  • Loading branch information
LSXPrime authored and LSXPrime committed Nov 20, 2024
1 parent 32c9374 commit 3de1c86
Show file tree
Hide file tree
Showing 18 changed files with 401 additions and 86 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/greetings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Greetings

on: pull_request_target

jobs:
greeting:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: |
Welcome to Aegis repository! We appreciate you taking the time to contribute.
We're excited to review your pull request and look forward to collaborating with you. Please let us know if you have any questions or need any assistance.
Thank you for your contribution!
37 changes: 37 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests

on:
schedule:
- cron: '44 8 * * *'

jobs:
stale:

runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write

steps:
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: |
This issue has been automatically marked as stale because it has not had recent activity.
It will be closed if no further activity occurs.
If this issue is still relevant, please leave a comment indicating that you would like it to remain open.
Thank you for your contributions.
stale-pr-message: |
This pull request has been automatically marked as stale because it has not had recent activity.
It will be closed if no further activity occurs.
If you are still working on this pull request, please leave a comment indicating that you would like it to remain open.
Thank you for your contributions.
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'
105 changes: 94 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,12 @@ adapt the provided code to your specific needs.

### Custom Validation Rules

Aegis allows you to implement custom validation rules to enforce specific licensing requirements beyond the built-in validation logic. This provides greater flexibility and control over your licensing system.
Aegis allows you to implement custom validation rules to enforce specific licensing requirements beyond the built-in validation logic.
This provides greater flexibility and control over your licensing system.

1. **Implementing a Custom Rule**
To create a custom validation rule, implement the `IValidationRule` interface:

To create a custom validation rule, implement the `IValidationRule` interface:

```csharp
using Aegis.Interfaces;
Expand Down Expand Up @@ -304,15 +305,16 @@ Aegis allows you to implement custom validation rules to enforce specific licens

2. **Registering the Rule**

Once you have implemented your custom rule, register it with the `LicenseValidator`:
Once you have implemented your custom rule, register it with the `LicenseValidator`:

```csharp
LicenseValidator.AddValidationRule(new MyCustomRule());
```

3. **Example: Advanced Hardware Validation for Node-Locked Licenses**

This example demonstrates a more robust hardware validation for node-locked licenses, considering multiple hardware factors.
This example demonstrates a more robust hardware validation for node-locked licenses, considering multiple hardware
factors.

```csharp
using Aegis.Interfaces;
Expand Down Expand Up @@ -349,19 +351,100 @@ Aegis allows you to implement custom validation rules to enforce specific licens
}
```

**Usage:**
**Usage:**

```csharp
LicenseValidator.AddValidationRule(new AdvancedHardwareRule());

// ... during license loading ...
var license = await LicenseManager.LoadLicenseAsync("license.bin");
```

This example showcases how you can create a custom rule to enhance the security of your node-locked licenses by validating against multiple hardware identifiers.

You can adapt this example and implement your own logic for combining and validating different hardware factors to suit your specific needs. Remember to provide clear documentation and error messages within your custom rules to make them easy to understand and maintain.
This example showcases how you can create a custom rule to enhance the security of your node-locked licenses by
validating against multiple hardware identifiers.

You can adapt this example and implement your own logic for combining and validating different hardware factors to
suit your specific needs. Remember to provide clear documentation and error messages within your custom rules to make
them easy to understand and maintain.

### Custom Hardware Identification

By default, Aegis uses a `DefaultHardwareIdentifier` that combines Machine Name, User Name, OS Version, and MAC Address.
To implement a custom hardware identifier:

1. **Create a class that implements `IHardwareIdentifier`:**

```csharp
using Aegis.Interfaces;

public class MyCustomHardwareIdentifier : IHardwareIdentifier
{
public string GetHardwareIdentifier()
{
// Your custom logic to retrieve the hardware identifier.
// Example: CPU ID, Motherboard serial number, etc.
return "...";
}

public bool ValidateHardwareIdentifier(string hardwareIdentifier)
{
// Your custom logic to validate the hardware identifier.
return GetHardwareIdentifier() == hardwareIdentifier;
}
}
```

2. **Set the custom identifier:**

```csharp
LicenseManager.SetHardwareIdentifier(new MyCustomHardwareIdentifier());
```

### Custom Serialization

Aegis uses a `JsonLicenseSerializer` by default. To implement a custom serializer:

1. **Create a class that implements `ILicenseSerializer`:**

```csharp
using Aegis.Interfaces;
using Aegis.Models;

public class MyCustomSerializer : ILicenseSerializer
{
public string Serialize(BaseLicense license)
{
// Your custom serialization logic.
// Example: XML serialization, binary serialization, etc.
return "...";
}

public BaseLicense? Deserialize(string data)
{
// Your custom deserialization logic.
return ...;
}
}
```

2. **Set the custom serializer:**

```csharp
LicenseManager.SetSerializer(new MyCustomSerializer());
```

### Disabling Built-in Validation

You can disable Aegis's built-in validation logic if you want to rely solely on your custom validation rules or have a
different validation process.

```csharp
LicenseManager.SetBuiltInValidation(false);
```

This will prevent `LicenseManager` from performing its default validation checks for license type, expiry date, and
other built-in criteria. You will be responsible for implementing all necessary validation logic in your custom rules or
through other means.

### Architecture

Expand Down
6 changes: 3 additions & 3 deletions src/Aegis.Server/Aegis.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyVersion>1.1.0</AssemblyVersion>
<FileVersion>1.1.0</FileVersion>
<AssemblyVersion>1.3.0</AssemblyVersion>
<FileVersion>1.3.0</FileVersion>
<Title>Aegis.Server</Title>
<Description>Aegis is a robust and flexible .NET licensing library that simplifies the implementation of various licensing models for your applications. It offers strong security features, both online and offline validation, and easy integration with your existing projects. Securely manage your software licenses with Aegis.</Description>
<Copyright>Copyright (c) 2024 LSXPrime</Copyright>
Expand All @@ -16,7 +16,7 @@
<PackageIcon>Aegis.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>license, key, licensing, protect, shield</PackageTags>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<PackageReleaseNotes>https://github.com/LSXPrime/Aegis/releases</PackageReleaseNotes>
</PropertyGroup>

Expand Down
7 changes: 3 additions & 4 deletions src/Aegis/Aegis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyVersion>1.2.0</AssemblyVersion>
<FileVersion>1.2.0</FileVersion>
<AssemblyVersion>1.3.0</AssemblyVersion>
<FileVersion>1.3.0</FileVersion>
<Title>Aegis</Title>
<Description>Aegis is a robust and flexible .NET licensing library that simplifies the implementation of various licensing models for your applications. It offers strong security features, both online and offline validation, and easy integration with your existing projects. Securely manage your software licenses with Aegis.</Description>
<Copyright>Copyright (c) 2024 LSXPrime</Copyright>
Expand All @@ -16,12 +16,11 @@
<PackageIcon>Aegis.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>license, key, licensing, protect, shield</PackageTags>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<PackageReleaseNotes>https://github.com/LSXPrime/Aegis/releases</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="DeviceId" Version="6.7.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0"/>
</ItemGroup>

Expand Down
11 changes: 10 additions & 1 deletion src/Aegis/Exceptions/InvalidLicenseFormatException.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
namespace Aegis.Exceptions;

public class InvalidLicenseFormatException(string message) : LicenseValidationException(message);
public class InvalidLicenseFormatException : LicenseValidationException
{
public InvalidLicenseFormatException(string message) : base(message)
{
}

public InvalidLicenseFormatException(string message, Exception innerException) : base(message, innerException)
{
}
}
7 changes: 7 additions & 0 deletions src/Aegis/Interfaces/IHardwareIdentifier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Aegis.Interfaces;

public interface IHardwareIdentifier
{
string GetHardwareIdentifier();
bool ValidateHardwareIdentifier(string hardwareIdentifier);
}
9 changes: 9 additions & 0 deletions src/Aegis/Interfaces/ILicenseSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Aegis.Models;

namespace Aegis.Interfaces;

public interface ILicenseSerializer
{
string Serialize(BaseLicense license);
BaseLicense? Deserialize(string data);
}
2 changes: 1 addition & 1 deletion src/Aegis/LicenseBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static BaseLicense WithLicenseKey(this BaseLicense baseLicense, string li
/// <returns>The license object that was saved.</returns>
public static BaseLicense SaveLicense(this BaseLicense baseLicense, string filePath)
{
LicenseManager.SaveLicense(baseLicense, filePath);
LicenseManager.SaveLicenseToPath(baseLicense, filePath);
return baseLicense;
}
}
11 changes: 9 additions & 2 deletions src/Aegis/LicenseGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using Aegis.Models;
using Aegis.Interfaces;
using Aegis.Models;
using Aegis.Utilities;

namespace Aegis;

public static class LicenseGenerator
{
private static IHardwareIdentifier _hardwareIdentifier = new DefaultHardwareIdentifier();

/// <summary>
/// Generates a standard license.
/// </summary>
Expand Down Expand Up @@ -35,7 +38,7 @@ public static TrialLicense GenerateTrialLicense(TimeSpan trialPeriod)
/// <returns>A new NodeLockedLicense object.</returns>
public static NodeLockedLicense GenerateNodeLockedLicense(string? hardwareId = null)
{
hardwareId ??= HardwareUtils.GetHardwareId();
hardwareId ??= _hardwareIdentifier.GetHardwareIdentifier();
return new NodeLockedLicense(hardwareId);
}

Expand Down Expand Up @@ -71,4 +74,8 @@ public static ConcurrentLicense GenerateConcurrentLicense(string userName, int m
{
return new ConcurrentLicense(userName, maxActiveUsersCount);
}



internal static void SetHardwareIdentifier(IHardwareIdentifier hardwareIdentifier) => _hardwareIdentifier = hardwareIdentifier;
}
Loading

0 comments on commit 3de1c86

Please sign in to comment.