diff --git a/src/EventStore.Plugins/Authentication/AuthenticationProviderBase.cs b/src/EventStore.Plugins/Authentication/AuthenticationProviderBase.cs index ac860f4..6afdfbb 100644 --- a/src/EventStore.Plugins/Authentication/AuthenticationProviderBase.cs +++ b/src/EventStore.Plugins/Authentication/AuthenticationProviderBase.cs @@ -6,13 +6,11 @@ public abstract class AuthenticationProviderBase(PluginOptions options) : Plugin protected AuthenticationProviderBase( string? name = null, string? version = null, - string? licensePublicKey = null, string? diagnosticsName = null, params KeyValuePair[] diagnosticsTags ) : this(new() { Name = name, Version = version, - LicensePublicKey = licensePublicKey, DiagnosticsName = diagnosticsName, DiagnosticsTags = diagnosticsTags }) { } diff --git a/src/EventStore.Plugins/Authorization/AuthorizationProviderBase.cs b/src/EventStore.Plugins/Authorization/AuthorizationProviderBase.cs index bd608c8..1951aec 100644 --- a/src/EventStore.Plugins/Authorization/AuthorizationProviderBase.cs +++ b/src/EventStore.Plugins/Authorization/AuthorizationProviderBase.cs @@ -6,13 +6,11 @@ public abstract class AuthorizationProviderBase(PluginOptions options) : Plugin( protected AuthorizationProviderBase( string? name = null, string? version = null, - string? licensePublicKey = null, string? diagnosticsName = null, params KeyValuePair[] diagnosticsTags ) : this(new() { Name = name, Version = version, - LicensePublicKey = licensePublicKey, DiagnosticsName = diagnosticsName, DiagnosticsTags = diagnosticsTags }) { } diff --git a/src/EventStore.Plugins/EventStore.Plugins.csproj b/src/EventStore.Plugins/EventStore.Plugins.csproj index 6a2b73d..e93e343 100644 --- a/src/EventStore.Plugins/EventStore.Plugins.csproj +++ b/src/EventStore.Plugins/EventStore.Plugins.csproj @@ -28,11 +28,9 @@ - - diff --git a/src/EventStore.Plugins/IPlugableComponent.cs b/src/EventStore.Plugins/IPlugableComponent.cs index 29938aa..825be55 100644 --- a/src/EventStore.Plugins/IPlugableComponent.cs +++ b/src/EventStore.Plugins/IPlugableComponent.cs @@ -33,11 +33,6 @@ public interface IPlugableComponent { /// bool Enabled { get; } - /// - /// The public key used for licensing. - /// - string? LicensePublicKey { get; } - /// /// Configures the services using the provided IServiceCollection and IConfiguration. /// diff --git a/src/EventStore.Plugins/LicenseException.cs b/src/EventStore.Plugins/LicenseException.cs deleted file mode 100644 index 7f07a50..0000000 --- a/src/EventStore.Plugins/LicenseException.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace EventStore.Plugins; - -public class LicenseException(string featureName, Exception? inner = null) : Exception( - $"A license is required to use the {featureName} feature, but was not found. " + - "Please obtain a license or disable the feature.", - inner -) { - public string FeatureName { get; } = featureName; -} - -public class LicenseEntitlementException(string featureName, string entitlement) : Exception( - $"{featureName} feature requires the {entitlement} entitlement. Please contact EventStore support.") { - public string FeatureName { get; } = featureName; - public string MissingEntitlement { get; } = entitlement; -} diff --git a/src/EventStore.Plugins/Licensing/ILicenseService.cs b/src/EventStore.Plugins/Licensing/ILicenseService.cs deleted file mode 100644 index 064b8cd..0000000 --- a/src/EventStore.Plugins/Licensing/ILicenseService.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace EventStore.Plugins.Licensing; - -// Allows plugins to access the current license, get updates to it, and reject a license -// if it is missing entitlements -public interface ILicenseService { - // For checking that the license service itself is authentic - License SelfLicense { get; } - - License? CurrentLicense { get; } - - // The current license and updates to it - IObservable Licenses { get; } - - void RejectLicense(Exception ex); -} diff --git a/src/EventStore.Plugins/Licensing/License.cs b/src/EventStore.Plugins/Licensing/License.cs deleted file mode 100644 index 0854b5a..0000000 --- a/src/EventStore.Plugins/Licensing/License.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Security.Cryptography; -using Microsoft.IdentityModel.JsonWebTokens; -using Microsoft.IdentityModel.Tokens; -using static System.Convert; - -namespace EventStore.Plugins.Licensing; - -public record License(JsonWebToken Token) { - public string? CurrentCultureIgnoreCase { get; private set; } - - public async Task ValidateAsync(string publicKey) { - var result = await ValidateTokenAsync(publicKey, Token.EncodedToken); - return result.IsValid; - } - - public async Task TryValidateAsync(string publicKey) { - try { - return await ValidateAsync(publicKey); - } catch { - return false; - } - } - - public bool HasEntitlements(string[] entitlements, [MaybeNullWhen(true)] out string missing) { - foreach (var entitlement in entitlements) { - if (!HasEntitlement(entitlement)) { - missing = entitlement; - return false; - } - } - - missing = default; - return true; - } - - public bool HasEntitlement(string entitlement) { - foreach (var claim in Token.Claims) - if (claim.Type.Equals(entitlement, StringComparison.CurrentCultureIgnoreCase) && - claim.Value.Equals("true", StringComparison.CurrentCultureIgnoreCase)) - return true; - - return false; - } - - public static async Task CreateAsync( - string publicKey, - string privateKey, - IDictionary claims) { - using var rsa = RSA.Create(); - rsa.ImportRSAPrivateKey(FromBase64String(privateKey), out _); - var tokenHandler = new JsonWebTokenHandler(); - var token = tokenHandler.CreateToken(new SecurityTokenDescriptor { - Audience = "esdb", - Issuer = "esdb", - Expires = DateTime.UtcNow + TimeSpan.FromHours(1), - Claims = claims, - SigningCredentials = new(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256) - }); - - var result = await ValidateTokenAsync(publicKey, token); - - if (!result.IsValid) - throw new("Token could not be validated"); - - if (result.SecurityToken is not JsonWebToken jwt) - throw new("Token is not a JWT"); - - return new(jwt); - } - - public static License Create(string publicKey, string privateKey, IDictionary? claims = null) => - CreateAsync(publicKey, privateKey, claims ?? new Dictionary()).GetAwaiter().GetResult(); - - public static License Create(byte[] publicKey, byte[] privateKey, IDictionary? claims = null) => - CreateAsync(ToBase64String(publicKey), ToBase64String(privateKey), claims ?? new Dictionary()).GetAwaiter().GetResult(); - - static async Task ValidateTokenAsync(string publicKey, string token) { - // not very satisfactory https://github.com/dotnet/runtime/issues/43087 - CryptoProviderFactory.Default.CacheSignatureProviders = false; - - using var rsa = RSA.Create(); - rsa.ImportRSAPublicKey(FromBase64String(publicKey), out _); - var result = await new JsonWebTokenHandler().ValidateTokenAsync( - token, - new() { - ValidIssuer = "esdb", - ValidAudience = "esdb", - IssuerSigningKey = new RsaSecurityKey(rsa), - ValidateAudience = true, - ValidateIssuerSigningKey = true, - ValidateIssuer = true, - ValidateLifetime = true - }); - - return result; - } -} diff --git a/src/EventStore.Plugins/Licensing/LicenseConstants.cs b/src/EventStore.Plugins/Licensing/LicenseConstants.cs deleted file mode 100644 index 9a727c9..0000000 --- a/src/EventStore.Plugins/Licensing/LicenseConstants.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace EventStore.Plugins.Licensing; - -public static class LicenseConstants { - public const string LicensePublicKey = "MEgCQQDGtRXIWmeJqkdpQryJdKBFVvLaMNHFkDcVXSoaDzg1ahrtCrAgwYpARAvGyFs0bcwYJZaZSt9aNwpgkAPOPQM5AgMBAAE="; -} diff --git a/src/EventStore.Plugins/Licensing/LicenseMonitor.cs b/src/EventStore.Plugins/Licensing/LicenseMonitor.cs deleted file mode 100644 index 65fe7ca..0000000 --- a/src/EventStore.Plugins/Licensing/LicenseMonitor.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace EventStore.Plugins.Licensing; - -public static class LicenseMonitor { - // the EULA prevents tampering with the license mechanism. we make the license mechanism - // robust enough that circumventing it requires intentional tampering. - public static async Task MonitorAsync( - string featureName, - string[] requiredEntitlements, - ILicenseService licenseService, - ILogger logger, - string licensePublicKey = LicenseConstants.LicensePublicKey, - Action? onCriticalError = null) { - - onCriticalError ??= Environment.Exit; - - // authenticate the license service itself so that we can trust it to - // 1. send us any licences at all - // 2. respect our decision to reject licences - var authentic = await licenseService.SelfLicense.TryValidateAsync(licensePublicKey); - if (!authentic) { - // this should never happen, but could if we end up with some unknown LicenseService. - logger.LogCritical("LicenseService could not be authenticated"); - onCriticalError(11); - } - - // authenticate the licenses that the license service sends us - return licenseService.Licenses.Subscribe( - onNext: async license => { - if (await license.TryValidateAsync(licensePublicKey)) { - // got an authentic license. check required entitlements - if (license.HasEntitlement("ALL")) - return; - - if (!license.HasEntitlements(requiredEntitlements, out var missing)) { - licenseService.RejectLicense(new LicenseEntitlementException(featureName, missing)); - } - } else { - // this should never happen - logger.LogCritical("ESDB License was not valid"); - licenseService.RejectLicense(new LicenseException(featureName, new Exception("ESDB License was not valid"))); - onCriticalError(12); - } - }, - onError: ex => { - licenseService.RejectLicense(new LicenseException(featureName, ex)); - }); - } -} diff --git a/src/EventStore.Plugins/Plugin.cs b/src/EventStore.Plugins/Plugin.cs index 490215b..9407cfa 100644 --- a/src/EventStore.Plugins/Plugin.cs +++ b/src/EventStore.Plugins/Plugin.cs @@ -1,6 +1,5 @@ using System.Diagnostics; using EventStore.Plugins.Diagnostics; -using EventStore.Plugins.Licensing; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -13,8 +12,6 @@ namespace EventStore.Plugins; public record PluginOptions { public string? Name { get; init; } public string? Version { get; init; } - public string? LicensePublicKey { get; init; } - public string[]? RequiredEntitlements { get; init; } public string? DiagnosticsName { get; init; } public KeyValuePair[] DiagnosticsTags { get; init; } = []; } @@ -24,8 +21,6 @@ public abstract class Plugin : IPlugableComponent, IDisposable { protected Plugin( string? name = null, string? version = null, - string? licensePublicKey = null, - string[]? requiredEntitlements = null, string? diagnosticsName = null, params KeyValuePair[] diagnosticsTags) { @@ -40,9 +35,6 @@ protected Plugin( Version = GetPluginVersion(version, pluginType); - LicensePublicKey = licensePublicKey; - RequiredEntitlements = requiredEntitlements; - DiagnosticsName = diagnosticsName ?? Name; DiagnosticsTags = diagnosticsTags; @@ -68,15 +60,9 @@ static string GetPluginVersion(string? pluginVersion, Type pluginType) { protected Plugin(PluginOptions options) : this( options.Name, options.Version, - options.LicensePublicKey, - options.RequiredEntitlements, options.DiagnosticsName, options.DiagnosticsTags) { } - public string? LicensePublicKey { get; } - - public string[]? RequiredEntitlements { get; } - DiagnosticListener DiagnosticListener { get; } (bool Enabled, string EnableInstructions) IsEnabledResult { get; set; } @@ -134,18 +120,6 @@ void IPlugableComponent.ConfigureApplication(IApplicationBuilder app, IConfigura return; } - if (Enabled && LicensePublicKey is not null) { - // the plugin is enabled and requires a license - var licenseService = app.ApplicationServices.GetRequiredService(); - - _ = LicenseMonitor.MonitorAsync( - Name, - RequiredEntitlements ?? [], - licenseService, - logger, - LicensePublicKey); - } - // there is still a chance to disable the plugin when configuring the application // this is useful when the plugin is enabled, but some conditions that can only be checked here are not met ConfigureApplication(app, Configuration); diff --git a/src/EventStore.Plugins/SubsystemsPlugin.cs b/src/EventStore.Plugins/SubsystemsPlugin.cs index 9653e0c..9255a65 100644 --- a/src/EventStore.Plugins/SubsystemsPlugin.cs +++ b/src/EventStore.Plugins/SubsystemsPlugin.cs @@ -20,16 +20,12 @@ protected SubsystemsPlugin(SubsystemsPluginOptions options) : base(options) { protected SubsystemsPlugin( string? name = null, string? version = null, - string? licensePublicKey = null, - string[]? requiredEntitlements = null, string? commandLineName = null, string? diagnosticsName = null, params KeyValuePair[] diagnosticsTags ) : this(new() { Name = name, Version = version, - LicensePublicKey = licensePublicKey, - RequiredEntitlements = requiredEntitlements, DiagnosticsName = diagnosticsName, DiagnosticsTags = diagnosticsTags, CommandLineName = commandLineName diff --git a/test/EventStore.Plugins.Tests/Licensing/LicenseMonitorTests.cs b/test/EventStore.Plugins.Tests/Licensing/LicenseMonitorTests.cs deleted file mode 100644 index 5d0d87e..0000000 --- a/test/EventStore.Plugins.Tests/Licensing/LicenseMonitorTests.cs +++ /dev/null @@ -1,106 +0,0 @@ -using EventStore.Plugins.Licensing; -using Microsoft.Extensions.Logging.Testing; - -namespace EventStore.Plugins.Tests.Licensing; - -public class LicenseMonitorTests { - [Fact] - public async Task valid_license_with_correct_entitlements() { - var licenseService = new PluginBaseTests.FakeLicenseService( - createLicense: true, - entitlements: ["MY_ENTITLEMENT"]); - - var criticalError = false; - - using var subscription = await LicenseMonitor.MonitorAsync( - featureName: "TestFeature", - requiredEntitlements: ["MY_ENTITLEMENT"], - licenseService: licenseService, - logger: new FakeLogger(), - licensePublicKey: licenseService.PublicKey, - onCriticalError: _ => criticalError = true); - - licenseService.RejectionException.Should().BeNull(); - criticalError.Should().BeFalse(); - } - - [Fact] - public async Task valid_license_with_all_entitlement() { - var licenseService = new PluginBaseTests.FakeLicenseService( - createLicense: true, - entitlements: ["ALL"]); - - var criticalError = false; - - using var subscription = await LicenseMonitor.MonitorAsync( - featureName: "TestFeature", - requiredEntitlements: ["MY_ENTITLEMENT"], - licenseService: licenseService, - logger: new FakeLogger(), - licensePublicKey: licenseService.PublicKey, - onCriticalError: _ => criticalError = true); - - licenseService.RejectionException.Should().BeNull(); - criticalError.Should().BeFalse(); - } - - [Fact] - public async Task valid_license_with_missing_entitlement() { - var licenseService = new PluginBaseTests.FakeLicenseService( - createLicense: true, - entitlements: []); - - var criticalError = false; - - using var subscription = await LicenseMonitor.MonitorAsync( - featureName: "TestFeature", - requiredEntitlements: ["MY_ENTITLEMENT"], - licenseService: licenseService, - logger: new FakeLogger(), - licensePublicKey: licenseService.PublicKey, - onCriticalError: _ => criticalError = true); - - licenseService.RejectionException.Should().BeOfType() - .Which.MissingEntitlement.Should().Be("MY_ENTITLEMENT"); - criticalError.Should().BeFalse(); - } - - [Fact] - public async Task no_license() { - var licenseService = new PluginBaseTests.FakeLicenseService( - createLicense: false); - - var criticalError = false; - - using var subscription = await LicenseMonitor.MonitorAsync( - featureName: "TestFeature", - requiredEntitlements: [], - licenseService: licenseService, - logger: new FakeLogger(), - licensePublicKey: licenseService.PublicKey, - onCriticalError: _ => criticalError = true); - - licenseService.RejectionException.Should().BeOfType(); - criticalError.Should().BeFalse(); - } - - [Fact] - public async Task license_is_not_valid() { - var licenseService = new PluginBaseTests.FakeLicenseService( - createLicense: true, - entitlements: []); - - var criticalError = false; - - using var subscription = await LicenseMonitor.MonitorAsync( - featureName: "TestFeature", - requiredEntitlements: [], - licenseService: licenseService, - logger: new FakeLogger(), - licensePublicKey: "a_different_public_key", - onCriticalError: _ => criticalError = true); - - licenseService.RejectionException.Should().BeOfType(); - criticalError.Should().BeTrue(); - } -} diff --git a/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs b/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs deleted file mode 100644 index d3ca72a..0000000 --- a/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Security.Cryptography; -using EventStore.Plugins.Licensing; - -namespace EventStore.Plugins.Tests.Licensing; - -public class LicenseTests { - static (string PublicKey, string PrivateKey) CreateKeyPair() { - using var rsa = RSA.Create(1024); // was failing with 512?!? - var publicKey = Convert.ToBase64String(rsa.ExportRSAPublicKey()); - var privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey()); - return (publicKey, privateKey); - } - - [Fact] - public async Task can_create_and_validate_license() { - var (publicKey, privateKey) = CreateKeyPair(); - - var license = await License.CreateAsync(publicKey, privateKey, new Dictionary { - { "foo", "bar" }, - { "my_entitlement", "true" }, - }); - - // check repeatedly because of https://github.com/dotnet/runtime/issues/43087 - (await license.ValidateAsync(publicKey)).Should().BeTrue(); - (await license.ValidateAsync(publicKey)).Should().BeTrue(); - (await license.ValidateAsync(publicKey)).Should().BeTrue(); - - license.Token.Claims.First(c => c.Type == "foo").Value.Should().Be("bar"); - license.HasEntitlement("my_entitlement").Should().BeTrue(); - license.HasEntitlements(["my_entitlement", "missing_entitlement"], out var missing).Should().BeFalse(); - missing.Should().Be("missing_entitlement"); - } - - [Fact] - public async Task detects_incorrect_public_key() { - var (publicKey, privateKey) = CreateKeyPair(); - var (publicKey2, _) = CreateKeyPair(); - - var license = await License.CreateAsync(publicKey, privateKey, new Dictionary { - { "foo", "bar" } - }); - - (await license.ValidateAsync(publicKey2)).Should().BeFalse(); - } - - [Fact] - public async Task cannot_create_with_inconsistent_keys() { - var (publicKey, _) = CreateKeyPair(); - var (_, privateKey) = CreateKeyPair(); - - Func act = () => License.CreateAsync(publicKey, privateKey, new Dictionary { - { "foo", "bar" } - }); - - await act.Should().ThrowAsync().WithMessage("Token could not be validated"); - } -} diff --git a/test/EventStore.Plugins.Tests/PluginBaseTests.cs b/test/EventStore.Plugins.Tests/PluginBaseTests.cs index ce7e11d..8d05057 100644 --- a/test/EventStore.Plugins.Tests/PluginBaseTests.cs +++ b/test/EventStore.Plugins.Tests/PluginBaseTests.cs @@ -1,13 +1,9 @@ // ReSharper disable AccessToDisposedClosure -using System.Reactive.Subjects; -using System.Security.Cryptography; using EventStore.Plugins.Diagnostics; -using EventStore.Plugins.Licensing; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using static System.Convert; namespace EventStore.Plugins.Tests; @@ -43,11 +39,11 @@ public void subsystems_plugin_base_sets_defaults_automatically() { public void plugin_diagnostics_snapshot_is_not_overriden_internally() { // Arrange var userDiagnosticsData = new Dictionary { - ["first_value"] = 1, + ["first_value"] = 1, ["second_value"] = 2 }; - IPlugableComponent plugin = new NightCityPlugin(new(){ Name = Guid.NewGuid().ToString() }) { + IPlugableComponent plugin = new NightCityPlugin(new() { Name = Guid.NewGuid().ToString() }) { OnConfigureServices = x => x.PublishDiagnosticsData(userDiagnosticsData), OnConfigureApplication = x => x.Disable("Disabled on ConfigureApplication because I can") }; @@ -71,86 +67,10 @@ public void plugin_diagnostics_snapshot_is_not_overriden_internally() { .Which.Data.Should().BeEquivalentTo(expectedDiagnosticsData); } - [Fact] - public void commercial_plugin_is_disabled_when_licence_is_missing() { - // Arrange - var licenseService = new FakeLicenseService(createLicense: false); - - IPlugableComponent plugin = new NightCityPlugin(new() { - LicensePublicKey = licenseService.PublicKey, - RequiredEntitlements = ["starlight"], - }); - - var builder = WebApplication.CreateBuilder(); - - builder.Services.AddSingleton(licenseService); - - plugin.ConfigureServices(builder.Services, builder.Configuration); - - using var app = builder.Build(); - - // Act - plugin.ConfigureApplication(app, app.Configuration); - - // Assert - licenseService.RejectionException.Should().BeOfType().Which - .FeatureName.Should().Be(plugin.Name); - } - - [Fact] - public void commercial_plugin_is_disabled_when_licence_is_missing_entitlement() { - // Arrange - var licenseService = new FakeLicenseService(createLicense: true); - - IPlugableComponent plugin = new NightCityPlugin(new() { - LicensePublicKey = licenseService.PublicKey, - RequiredEntitlements = ["starlight"], - }); - - var builder = WebApplication.CreateBuilder(); - - builder.Services.AddSingleton(licenseService); - - plugin.ConfigureServices(builder.Services, builder.Configuration); - - using var app = builder.Build(); - - // Act - plugin.ConfigureApplication(app, app.Configuration); - - // Assert - licenseService.RejectionException.Should().BeOfType().Which - .FeatureName.Should().Be(plugin.Name); - } - - [Fact] - public void commercial_plugin_is_enabled_when_licence_is_present() { - // Arrange - var licenseService = new FakeLicenseService(createLicense: true, "starlight"); - - IPlugableComponent plugin = new NightCityPlugin(new() { - LicensePublicKey = licenseService.PublicKey, - RequiredEntitlements = ["starlight"], - }); - - var builder = WebApplication.CreateBuilder(); - - builder.Services.AddSingleton(licenseService); - - plugin.ConfigureServices(builder.Services, builder.Configuration); - - using var app = builder.Build(); - - var configure = () => plugin.ConfigureApplication(app, builder.Configuration); - - // Act & Assert - configure.Should().NotThrow(); - } - [Fact] public void plugin_can_be_disabled_on_ConfigureServices() { // Arrange - IPlugableComponent plugin = new NightCityPlugin(new(){ Name = Guid.NewGuid().ToString() }) { + IPlugableComponent plugin = new NightCityPlugin(new() { Name = Guid.NewGuid().ToString() }) { OnConfigureServices = x => x.Disable("Disabled on ConfigureServices because I can") }; @@ -173,7 +93,7 @@ public void plugin_can_be_disabled_on_ConfigureServices() { [Fact] public void plugin_can_be_disabled_on_ConfigureApplication() { // Arrange - IPlugableComponent plugin = new NightCityPlugin(new(){ Name = Guid.NewGuid().ToString() }) { + IPlugableComponent plugin = new NightCityPlugin(new() { Name = Guid.NewGuid().ToString() }) { OnConfigureApplication = x => x.Disable("Disabled on ConfigureApplication because I can") }; @@ -197,51 +117,11 @@ public void plugin_can_be_disabled_on_ConfigureApplication() { .WhoseValue.Should().BeEquivalentTo(false); } - public class FakeLicenseService : ILicenseService { - public FakeLicenseService( - bool createLicense, - params string[] entitlements) { - - using var rsa = RSA.Create(1024); - - PublicKey = ToBase64String(rsa.ExportRSAPublicKey()); - var privateKey = ToBase64String(rsa.ExportRSAPrivateKey()); - - SelfLicense = License.Create(PublicKey, privateKey); - - if (createLicense) { - CurrentLicense = License.Create(PublicKey, privateKey, entitlements.ToDictionary( - x => x, - x => (object)"true")); - Licenses = new BehaviorSubject(CurrentLicense); - } else { - CurrentLicense = null; - var licenses = new Subject(); - licenses.OnError(new Exception("license expired, say")); - Licenses = licenses; - } - } - - public string PublicKey { get; } - public License SelfLicense { get; } - - public License? CurrentLicense { get; } - - public IObservable Licenses { get; } - - public void RejectLicense(Exception ex) { - RejectionException = ex; - } - - public Exception? RejectionException { get; private set; } - } - class NightCityPlugin : Plugin { public NightCityPlugin(PluginOptions options) : base(options) { Options = options with { Name = Name, Version = Version, - RequiredEntitlements = RequiredEntitlements, DiagnosticsName = DiagnosticsName, }; } @@ -250,7 +130,7 @@ public NightCityPlugin() : this(new()) { } public PluginOptions Options { get; } - public Action? OnConfigureServices { get; set; } + public Action? OnConfigureServices { get; set; } public Action? OnConfigureApplication { get; set; } public override void ConfigureServices(IServiceCollection services, IConfiguration configuration) =>