Open xmenxwk opened 20 hours ago
RegistryDateTimeProvider
is a sample, not a core component, its primary purpose is to demonstrate the IValidationRule
feature. The library's main focus is on licensing and validation, but it does not have control over system-side date and time manipulation.
but surely you can fix it by adapting RegistryDateTimeProvider
to access current DateTime using any external API
using Microsoft.Win32;
using System.Net.Http;
using System.Text.Json;
namespace Aegis.Sample.Validation.DateTime.Windows;
public interface IDateTimeProvider
{
System.DateTime UtcNow { get; }
}
public class RegistryDateTimeProvider : IDateTimeProvider
{
private const string RegistryKeyPath = @"SOFTWARE\LSXPrime\Aegis";
private const string LastStartTimeValueName = "LastStartTime";
private const string TimeApiUrl = "https://timeapi.io/api/timezone/zone?timeZone=Europe%2FAmsterdam";
private readonly HttpClient _httpClient;
public bool Mock { get; set; } // Mock the current system time for testing purposes
public RegistryDateTimeProvider(HttpClient httpClient)
{
_httpClient = httpClient;
}
public System.DateTime UtcNow
{
get
{
var lastStartTime = GetLastStartTimeFromRegistry();
var currentUtcNow = GetCurrentUtcTimeFromApi();
if (lastStartTime > currentUtcNow)
{
return lastStartTime;
}
SetLastStartTimeInRegistry(currentUtcNow);
return currentUtcNow;
}
}
private System.DateTime GetCurrentUtcTimeFromApi()
{
var response = _httpClient.GetAsync(TimeApiUrl).Result;
response.EnsureSuccessStatusCode();
var content = response.Content.ReadAsStringAsync().Result;
var timeData = JsonSerializer.Deserialize<TimeApiResponse>(content);
return System.DateTime.Parse(timeData.currentLocalTime).ToUniversalTime();
}
private System.DateTime GetLastStartTimeFromRegistry()
{
using var key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath);
var lastStartTimeTicks = key?.GetValue(LastStartTimeValueName) as long? ?? 0;
return new System.DateTime(lastStartTimeTicks, DateTimeKind.Utc).AddHours(Mock ? 2 : 0);
}
private void SetLastStartTimeInRegistry(System.DateTime dateTime)
{
using var key = Registry.CurrentUser.CreateSubKey(RegistryKeyPath);
key?.SetValue(LastStartTimeValueName, dateTime.Ticks, RegistryValueKind.QWord);
}
private class TimeApiResponse
{
public string currentLocalTime { get; set; }
}
}
Checking online is very good alternative but it won't work for offline apps, since most of my apps are very little dependent on online connectivity. And can't force users to always be online so I might have to think some other way.
While its customizable but it only solves half the problem. Here are some test scenarios.
License Expires on 31 Jan 2024 and on 30th, User changes the system date to 1st Jan 2024. The provider will fail because it will keep reading 30th from registry.
Another is, everyday a user keep setting system date to same day the app was installed. It will never expire.