diff --git a/src/EventStore.Plugins/Authentication/AuthenticationRequest.cs b/src/EventStore.Plugins/Authentication/AuthenticationRequest.cs index 966c997..5b75769 100644 --- a/src/EventStore.Plugins/Authentication/AuthenticationRequest.cs +++ b/src/EventStore.Plugins/Authentication/AuthenticationRequest.cs @@ -3,69 +3,69 @@ namespace EventStore.Plugins.Authentication; public abstract class AuthenticationRequest { - /// - /// Whether a valid client certificate was supplied with the request - /// - public readonly bool HasValidClientCertificate; + /// + /// Whether a valid client certificate was supplied with the request + /// + public readonly bool HasValidClientCertificate; - /// - /// The Identifier for the source that this request came from - /// - public readonly string Id; + /// + /// The Identifier for the source that this request came from + /// + public readonly string Id; - /// - /// The name of the principal for the request - /// - public readonly string Name; + /// + /// The name of the principal for the request + /// + public readonly string Name; - /// - /// The supplied password for the request - /// - public readonly string SuppliedPassword; + /// + /// The supplied password for the request + /// + public readonly string SuppliedPassword; - /// - /// All supplied authentication tokens for the request - /// - public readonly IReadOnlyDictionary Tokens; + /// + /// All supplied authentication tokens for the request + /// + public readonly IReadOnlyDictionary Tokens; - protected AuthenticationRequest(string? id, IReadOnlyDictionary? tokens) { - ArgumentNullException.ThrowIfNull(id); - ArgumentNullException.ThrowIfNull(tokens); + protected AuthenticationRequest(string? id, IReadOnlyDictionary? tokens) { + ArgumentNullException.ThrowIfNull(id); + ArgumentNullException.ThrowIfNull(tokens); - Id = id; - Tokens = tokens; - Name = GetToken("uid") ?? ""; - SuppliedPassword = GetToken("pwd") ?? ""; - HasValidClientCertificate = GetToken("client-certificate") != null; - } + Id = id; + Tokens = tokens; + Name = GetToken("uid") ?? ""; + SuppliedPassword = GetToken("pwd") ?? ""; + HasValidClientCertificate = GetToken("client-certificate") != null; + } - /// - /// Gets the token corresponding to - /// - /// . - /// - /// - /// - public string? GetToken(string key) => Tokens.GetValueOrDefault(key); + /// + /// Gets the token corresponding to + /// + /// . + /// + /// + /// + public string? GetToken(string key) => Tokens.GetValueOrDefault(key); - /// - /// The request is unauthorized - /// - public abstract void Unauthorized(); + /// + /// The request is unauthorized + /// + public abstract void Unauthorized(); - /// - /// The request was successfully authenticated - /// - /// The of the authenticated request - public abstract void Authenticated(ClaimsPrincipal principal); + /// + /// The request was successfully authenticated + /// + /// The of the authenticated request + public abstract void Authenticated(ClaimsPrincipal principal); - /// - /// An error occurred during authentication - /// - public abstract void Error(); + /// + /// An error occurred during authentication + /// + public abstract void Error(); - /// - /// The authentication provider is not yet ready to service the request - /// - public abstract void NotReady(); + /// + /// The authentication provider is not yet ready to service the request + /// + public abstract void NotReady(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authentication/HttpAuthenticationRequest.cs b/src/EventStore.Plugins/Authentication/HttpAuthenticationRequest.cs index 6755d3b..e6a7250 100644 --- a/src/EventStore.Plugins/Authentication/HttpAuthenticationRequest.cs +++ b/src/EventStore.Plugins/Authentication/HttpAuthenticationRequest.cs @@ -5,60 +5,57 @@ namespace EventStore.Plugins.Authentication; public enum HttpAuthenticationRequestStatus { - None, - Error, - NotReady, - Unauthenticated, - Authenticated + None, + Error, + NotReady, + Unauthenticated, + Authenticated } public class HttpAuthenticationRequest : AuthenticationRequest { - readonly CancellationTokenRegistration _cancellationRegister; - readonly TaskCompletionSource<(HttpAuthenticationRequestStatus, ClaimsPrincipal?)> _tcs; - - public HttpAuthenticationRequest(HttpContext context, string authToken) : this(context, - new Dictionary { - ["jwt"] = authToken - }) { - } - - public HttpAuthenticationRequest(HttpContext context, string name, string suppliedPassword) : - this(context, new Dictionary { - ["uid"] = name, - ["pwd"] = suppliedPassword - }) { - } - - HttpAuthenticationRequest(HttpContext context, IReadOnlyDictionary tokens) : base( - context.TraceIdentifier, tokens) { - _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously); - _cancellationRegister = context.RequestAborted.Register(Cancel); - } - - public static HttpAuthenticationRequest CreateWithValidCertificate(HttpContext context, string name, X509Certificate2 clientCertificate) { - return new(context, new Dictionary { - ["uid"] = name, - ["client-certificate"] = clientCertificate.ExportCertificatePem() - }); - } - - void Cancel() { - _tcs.TrySetCanceled(); - _cancellationRegister.Dispose(); - } - - public override void Unauthorized() => - _tcs.TrySetResult((HttpAuthenticationRequestStatus.Unauthenticated, default)); - - public override void Authenticated(ClaimsPrincipal principal) => - _tcs.TrySetResult((HttpAuthenticationRequestStatus.Authenticated, principal)); - - public override void Error() => - _tcs.TrySetResult((HttpAuthenticationRequestStatus.Error, default)); - - public override void NotReady() => - _tcs.TrySetResult((HttpAuthenticationRequestStatus.NotReady, default)); - - public Task<(HttpAuthenticationRequestStatus, ClaimsPrincipal?)> AuthenticateAsync() => - _tcs.Task; + readonly CancellationTokenRegistration _cancellationRegister; + readonly TaskCompletionSource<(HttpAuthenticationRequestStatus, ClaimsPrincipal?)> _tcs; + + public HttpAuthenticationRequest(HttpContext context, string authToken) : this(context, + new Dictionary { + ["jwt"] = authToken + }) { } + + public HttpAuthenticationRequest(HttpContext context, string name, string suppliedPassword) : + this(context, new Dictionary { + ["uid"] = name, + ["pwd"] = suppliedPassword + }) { } + + HttpAuthenticationRequest(HttpContext context, IReadOnlyDictionary tokens) : base( + context.TraceIdentifier, tokens) { + _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously); + _cancellationRegister = context.RequestAborted.Register(Cancel); + } + + public static HttpAuthenticationRequest CreateWithValidCertificate(HttpContext context, string name, X509Certificate2 clientCertificate) => new(context, + new Dictionary { + ["uid"] = name, + ["client-certificate"] = clientCertificate.ExportCertificatePem() + }); + + void Cancel() { + _tcs.TrySetCanceled(); + _cancellationRegister.Dispose(); + } + + public override void Unauthorized() => + _tcs.TrySetResult((HttpAuthenticationRequestStatus.Unauthenticated, default)); + + public override void Authenticated(ClaimsPrincipal principal) => + _tcs.TrySetResult((HttpAuthenticationRequestStatus.Authenticated, principal)); + + public override void Error() => + _tcs.TrySetResult((HttpAuthenticationRequestStatus.Error, default)); + + public override void NotReady() => + _tcs.TrySetResult((HttpAuthenticationRequestStatus.NotReady, default)); + + public Task<(HttpAuthenticationRequestStatus, ClaimsPrincipal?)> AuthenticateAsync() => + _tcs.Task; } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authentication/IAuthenticationPlugin.cs b/src/EventStore.Plugins/Authentication/IAuthenticationPlugin.cs index fc3b9c1..e357b53 100644 --- a/src/EventStore.Plugins/Authentication/IAuthenticationPlugin.cs +++ b/src/EventStore.Plugins/Authentication/IAuthenticationPlugin.cs @@ -1,13 +1,13 @@ namespace EventStore.Plugins.Authentication; public interface IAuthenticationPlugin { - string Name { get; } - string Version { get; } - string CommandLineName { get; } + string Name { get; } + string Version { get; } + string CommandLineName { get; } - /// - /// Creates an authentication provider factory for the authentication plugin - /// - /// The path to the configuration file for the authentication plugin - IAuthenticationProviderFactory GetAuthenticationProviderFactory(string authenticationConfigPath); + /// + /// Creates an authentication provider factory for the authentication plugin + /// + /// The path to the configuration file for the authentication plugin + IAuthenticationProviderFactory GetAuthenticationProviderFactory(string authenticationConfigPath); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authentication/IAuthenticationProvider.cs b/src/EventStore.Plugins/Authentication/IAuthenticationProvider.cs index 94dfba4..9c33b1f 100644 --- a/src/EventStore.Plugins/Authentication/IAuthenticationProvider.cs +++ b/src/EventStore.Plugins/Authentication/IAuthenticationProvider.cs @@ -3,31 +3,31 @@ namespace EventStore.Plugins.Authentication; public interface IAuthenticationProvider : IPlugableComponent { - /// - /// Initialize the AuthenticationProvider. Event Store will wait until this task completes before becoming ready. - /// - Task Initialize(); + /// + /// Initialize the AuthenticationProvider. Event Store will wait until this task completes before becoming ready. + /// + Task Initialize(); - /// - /// Authenticate an AuthenticationRequest. Call the appropriate method on - /// depending on whether the request succeeded, failed, or errored. - /// - /// - void Authenticate(AuthenticationRequest authenticationRequest); + /// + /// Authenticate an AuthenticationRequest. Call the appropriate method on + /// depending on whether the request succeeded, failed, or errored. + /// + /// + void Authenticate(AuthenticationRequest authenticationRequest); - /// - /// Get public properties which may be required for the authentication flow. - /// - IEnumerable> GetPublicProperties(); + /// + /// Get public properties which may be required for the authentication flow. + /// + IEnumerable> GetPublicProperties(); - /// - /// Create any required endpoints. - /// - /// - void ConfigureEndpoints(IEndpointRouteBuilder endpointRouteBuilder); + /// + /// Create any required endpoints. + /// + /// + void ConfigureEndpoints(IEndpointRouteBuilder endpointRouteBuilder); - /// - /// Get supported authentication schemes. - /// - IReadOnlyList GetSupportedAuthenticationSchemes(); + /// + /// Get supported authentication schemes. + /// + IReadOnlyList GetSupportedAuthenticationSchemes(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authentication/IAuthenticationProviderFactory.cs b/src/EventStore.Plugins/Authentication/IAuthenticationProviderFactory.cs index aa0c62d..ea4c78d 100644 --- a/src/EventStore.Plugins/Authentication/IAuthenticationProviderFactory.cs +++ b/src/EventStore.Plugins/Authentication/IAuthenticationProviderFactory.cs @@ -3,13 +3,12 @@ namespace EventStore.Plugins.Authentication; public interface IAuthenticationProviderFactory { - /// - /// Build an AuthenticationProvider for the authentication plugin - /// - /// - /// Whether the Authentication Provider should log failed authentication - /// attempts - /// - /// The to use when logging in the plugin - IAuthenticationProvider Build(bool logFailedAuthenticationAttempts, ILogger logger); + /// + /// Build an AuthenticationProvider for the authentication plugin + /// + /// + /// Whether the Authentication Provider should log failed authentication attempts + /// + /// The to use when logging in the plugin + IAuthenticationProvider Build(bool logFailedAuthenticationAttempts, ILogger logger); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authentication/IHttpAuthenticationProvider.cs b/src/EventStore.Plugins/Authentication/IHttpAuthenticationProvider.cs index 63db486..1a388e7 100644 --- a/src/EventStore.Plugins/Authentication/IHttpAuthenticationProvider.cs +++ b/src/EventStore.Plugins/Authentication/IHttpAuthenticationProvider.cs @@ -3,10 +3,10 @@ namespace EventStore.Plugins.Authentication; public interface IHttpAuthenticationProvider { - /// - /// Return a unique name used to externally identify the authentication provider. - /// - string Name { get; } + /// + /// Return a unique name used to externally identify the authentication provider. + /// + string Name { get; } - bool Authenticate(HttpContext context, out HttpAuthenticationRequest request); + bool Authenticate(HttpContext context, out HttpAuthenticationRequest request); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authorization/IAuthorizationPlugin.cs b/src/EventStore.Plugins/Authorization/IAuthorizationPlugin.cs index 1136382..52c4454 100644 --- a/src/EventStore.Plugins/Authorization/IAuthorizationPlugin.cs +++ b/src/EventStore.Plugins/Authorization/IAuthorizationPlugin.cs @@ -1,13 +1,13 @@ namespace EventStore.Plugins.Authorization; public interface IAuthorizationPlugin { - string Name { get; } - string Version { get; } - string CommandLineName { get; } + string Name { get; } + string Version { get; } + string CommandLineName { get; } - /// - /// Creates an authorization provider factory for the authorization plugin - /// - /// The path to the configuration file for the authorization plugin - IAuthorizationProviderFactory GetAuthorizationProviderFactory(string authorizationConfigPath); + /// + /// Creates an authorization provider factory for the authorization plugin + /// + /// The path to the configuration file for the authorization plugin + IAuthorizationProviderFactory GetAuthorizationProviderFactory(string authorizationConfigPath); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authorization/IAuthorizationProvider.cs b/src/EventStore.Plugins/Authorization/IAuthorizationProvider.cs index 0d5398b..e15a0b7 100644 --- a/src/EventStore.Plugins/Authorization/IAuthorizationProvider.cs +++ b/src/EventStore.Plugins/Authorization/IAuthorizationProvider.cs @@ -3,8 +3,8 @@ namespace EventStore.Plugins.Authorization; public interface IAuthorizationProvider : IPlugableComponent { - /// - /// Check whether the provided has the rights to perform the - /// - ValueTask CheckAccessAsync(ClaimsPrincipal cp, Operation operation, CancellationToken ct); + /// + /// Check whether the provided has the rights to perform the + /// + ValueTask CheckAccessAsync(ClaimsPrincipal cp, Operation operation, CancellationToken ct); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authorization/IAuthorizationProviderFactory.cs b/src/EventStore.Plugins/Authorization/IAuthorizationProviderFactory.cs index 8af5c06..f150bda 100644 --- a/src/EventStore.Plugins/Authorization/IAuthorizationProviderFactory.cs +++ b/src/EventStore.Plugins/Authorization/IAuthorizationProviderFactory.cs @@ -1,8 +1,8 @@ namespace EventStore.Plugins.Authorization; public interface IAuthorizationProviderFactory { - /// - /// Build an AuthorizationProvider for the authorization plugin - /// - IAuthorizationProvider Build(); + /// + /// Build an AuthorizationProvider for the authorization plugin + /// + IAuthorizationProvider Build(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authorization/Operation.cs b/src/EventStore.Plugins/Authorization/Operation.cs index 0a8d4b8..af90357 100644 --- a/src/EventStore.Plugins/Authorization/Operation.cs +++ b/src/EventStore.Plugins/Authorization/Operation.cs @@ -1,60 +1,51 @@ using System.Text; -namespace EventStore.Plugins.Authorization { - public readonly struct Operation { - public string Resource { get; } - public string Action { get; } - public ReadOnlyMemory Parameters { get; } +namespace EventStore.Plugins.Authorization; - public Operation(OperationDefinition definition) : this(definition.Resource, definition.Action) { - } +public readonly struct Operation { + public string Resource { get; } + public string Action { get; } + public ReadOnlyMemory Parameters { get; } - public Operation(string resource, string action) : this(resource, action, Array.Empty()) { } + public Operation(OperationDefinition definition) : this(definition.Resource, definition.Action) { } - public Operation WithParameter(string name, string value) { - return WithParameters(new Parameter(name, value)); - } + public Operation(string resource, string action) : this(resource, action, Array.Empty()) { } - public Operation WithParameter(Parameter parameter) { - return WithParameters(parameter); - } + public Operation WithParameter(string name, string value) => WithParameters(new Parameter(name, value)); - public Operation WithParameters(ReadOnlyMemory parameters) { - var memory = new Memory(new Parameter[Parameters.Length + parameters.Length]); - if (!Parameters.IsEmpty) Parameters.CopyTo(memory); - parameters.CopyTo(memory.Slice(Parameters.Length)); - return new(Resource, Action, memory); - } + public Operation WithParameter(Parameter parameter) => WithParameters(parameter); - public Operation WithParameters(params Parameter[] parameters) { - return WithParameters(new ReadOnlyMemory(parameters)); - } + public Operation WithParameters(ReadOnlyMemory parameters) { + var memory = new Memory(new Parameter[Parameters.Length + parameters.Length]); + if (!Parameters.IsEmpty) Parameters.CopyTo(memory); + parameters.CopyTo(memory.Slice(Parameters.Length)); + return new(Resource, Action, memory); + } - public Operation(string resource, string action, Memory parameters) { - Resource = resource; - Action = action; - Parameters = parameters; - } + public Operation WithParameters(params Parameter[] parameters) => WithParameters(new ReadOnlyMemory(parameters)); - public static implicit operator OperationDefinition(Operation operation) { - return new(operation.Resource, operation.Action); - } + public Operation(string resource, string action, Memory parameters) { + Resource = resource; + Action = action; + Parameters = parameters; + } - public override string ToString() { - var sb = new StringBuilder(); - sb.Append($"{Resource} : {Action}"); - var parameters = Parameters.Span; - if (!parameters.IsEmpty) { - sb.Append(" p: {"); - while (!parameters.IsEmpty) { - sb.Append($"{parameters[0].Name} : {parameters[0].Value}"); - parameters = parameters.Slice(1); - } - - sb.Append("}"); + public static implicit operator OperationDefinition(Operation operation) => new(operation.Resource, operation.Action); + + public override string ToString() { + var sb = new StringBuilder(); + sb.Append($"{Resource} : {Action}"); + var parameters = Parameters.Span; + if (!parameters.IsEmpty) { + sb.Append(" p: {"); + while (!parameters.IsEmpty) { + sb.Append($"{parameters[0].Name} : {parameters[0].Value}"); + parameters = parameters.Slice(1); } - return sb.ToString(); + sb.Append("}"); } + + return sb.ToString(); } -} +} \ No newline at end of file diff --git a/src/EventStore.Plugins/Authorization/Operations.cs b/src/EventStore.Plugins/Authorization/Operations.cs index 4eb1488..a8edfca 100644 --- a/src/EventStore.Plugins/Authorization/Operations.cs +++ b/src/EventStore.Plugins/Authorization/Operations.cs @@ -1,191 +1,177 @@ namespace EventStore.Plugins.Authorization; public static class Operations { - public static class Node { - const string Resource = "node"; - public static readonly OperationDefinition Redirect = new Operation(Resource, "redirect"); - public static readonly OperationDefinition Options = new Operation(Resource, "options"); - public static readonly OperationDefinition Ping = new Operation(Resource, "ping"); + public static class Node { + const string Resource = "node"; + public static readonly OperationDefinition Redirect = new Operation(Resource, "redirect"); + public static readonly OperationDefinition Options = new Operation(Resource, "options"); + public static readonly OperationDefinition Ping = new Operation(Resource, "ping"); - public static readonly OperationDefinition StaticContent = new($"{Resource}/content", "read"); + public static readonly OperationDefinition StaticContent = new($"{Resource}/content", "read"); - public static readonly OperationDefinition Shutdown = new(Resource, "shutdown"); - public static readonly OperationDefinition ReloadConfiguration = new(Resource, "reloadConfiguration"); - public static readonly OperationDefinition MergeIndexes = new(Resource, "mergeIndexes"); - public static readonly OperationDefinition SetPriority = new(Resource, "setPriority"); - public static readonly OperationDefinition Resign = new(Resource, "resign"); + public static readonly OperationDefinition Shutdown = new(Resource, "shutdown"); + public static readonly OperationDefinition ReloadConfiguration = new(Resource, "reloadConfiguration"); + public static readonly OperationDefinition MergeIndexes = new(Resource, "mergeIndexes"); + public static readonly OperationDefinition SetPriority = new(Resource, "setPriority"); + public static readonly OperationDefinition Resign = new(Resource, "resign"); - public static readonly OperationDefinition Login = new Operation(Resource, "login"); + public static readonly OperationDefinition Login = new Operation(Resource, "login"); - public static class Scavenge { - const string Resource = $"{Node.Resource}/scavenge"; - public static readonly OperationDefinition Start = new(Resource, "start"); - public static readonly OperationDefinition Stop = new(Resource, "stop"); - public static readonly OperationDefinition Read = new(Resource, "read"); - } + public static class Scavenge { + const string Resource = $"{Node.Resource}/scavenge"; + public static readonly OperationDefinition Start = new(Resource, "start"); + public static readonly OperationDefinition Stop = new(Resource, "stop"); + public static readonly OperationDefinition Read = new(Resource, "read"); + } - public static class Redaction { - const string Resource = $"{Node.Resource}/redaction"; - public static readonly OperationDefinition SwitchChunk = new(Resource, "switchChunk"); - } - - public static class Information { - const string Resource = $"{Node.Resource}/info"; + public static class Redaction { + const string Resource = $"{Node.Resource}/redaction"; + public static readonly OperationDefinition SwitchChunk = new(Resource, "switchChunk"); + } - public static readonly OperationDefinition Subsystems = new($"{Resource}/subsystems", "read"); + public static class Information { + const string Resource = $"{Node.Resource}/info"; - public static readonly OperationDefinition Histogram = new($"{Resource}/histograms", "read"); + public static readonly OperationDefinition Subsystems = new($"{Resource}/subsystems", "read"); - public static readonly OperationDefinition Read = new(Resource, "read"); + public static readonly OperationDefinition Histogram = new($"{Resource}/histograms", "read"); - public static readonly OperationDefinition Options = new($"{Resource}/options", "read"); - } - - public static class Statistics { - const string Resource = $"{Node.Resource}/stats"; - public static readonly OperationDefinition Read = new(Resource, "read"); - - public static readonly OperationDefinition Replication = new($"{Resource}/replication", "read"); + public static readonly OperationDefinition Read = new(Resource, "read"); - public static readonly OperationDefinition Tcp = new($"{Resource}/tcp", "read"); - - public static readonly OperationDefinition Custom = new($"{Resource}/custom", "read"); - } + public static readonly OperationDefinition Options = new($"{Resource}/options", "read"); + } - public static class Elections { - const string Resource = $"{Node.Resource}/elections"; - public static readonly OperationDefinition ViewChange = new(Resource, "viewchange"); + public static class Statistics { + const string Resource = $"{Node.Resource}/stats"; + public static readonly OperationDefinition Read = new(Resource, "read"); - public static readonly OperationDefinition ViewChangeProof = new(Resource, "viewchangeproof"); - - public static readonly OperationDefinition Prepare = new(Resource, "prepare"); - public static readonly OperationDefinition PrepareOk = new(Resource, "prepareOk"); - public static readonly OperationDefinition Proposal = new(Resource, "proposal"); - public static readonly OperationDefinition Accept = new(Resource, "accept"); + public static readonly OperationDefinition Replication = new($"{Resource}/replication", "read"); - public static readonly OperationDefinition LeaderIsResigning = new(Resource, "leaderisresigning"); + public static readonly OperationDefinition Tcp = new($"{Resource}/tcp", "read"); - public static readonly OperationDefinition LeaderIsResigningOk = new(Resource, "leaderisresigningok"); - } + public static readonly OperationDefinition Custom = new($"{Resource}/custom", "read"); + } - public static class Gossip { - const string Resource = $"{Node.Resource}/gossip"; - public static readonly OperationDefinition Read = new(Resource, "read"); - public static readonly OperationDefinition Update = new(Resource, "update"); - public static readonly OperationDefinition ClientRead = new($"{Resource}/client", "read"); - } - } + public static class Elections { + const string Resource = $"{Node.Resource}/elections"; + public static readonly OperationDefinition ViewChange = new(Resource, "viewchange"); - public static class Streams { - const string Resource = "streams"; - public static readonly OperationDefinition Read = new(Resource, "read"); - public static readonly OperationDefinition Write = new(Resource, "write"); - public static readonly OperationDefinition Delete = new(Resource, "delete"); - public static readonly OperationDefinition MetadataRead = new(Resource, "metadataRead"); + public static readonly OperationDefinition ViewChangeProof = new(Resource, "viewchangeproof"); - public static readonly OperationDefinition MetadataWrite = new(Resource, "metadataWrite"); + public static readonly OperationDefinition Prepare = new(Resource, "prepare"); + public static readonly OperationDefinition PrepareOk = new(Resource, "prepareOk"); + public static readonly OperationDefinition Proposal = new(Resource, "proposal"); + public static readonly OperationDefinition Accept = new(Resource, "accept"); - public static class Parameters { - public static Parameter StreamId(string streamId) { - return new("streamId", streamId); - } + public static readonly OperationDefinition LeaderIsResigning = new(Resource, "leaderisresigning"); - public static Parameter TransactionId(long transactionId) { - return new("transactionId", transactionId.ToString("D")); - } - } - } + public static readonly OperationDefinition LeaderIsResigningOk = new(Resource, "leaderisresigningok"); + } - public static class Subscriptions { - const string Resource = "subscriptions"; - public static readonly OperationDefinition Statistics = new(Resource, "statistics"); - public static readonly OperationDefinition Create = new(Resource, "create"); - public static readonly OperationDefinition Update = new(Resource, "update"); - public static readonly OperationDefinition Delete = new(Resource, "delete"); - public static readonly OperationDefinition ReplayParked = new(Resource, "replay"); - public static readonly OperationDefinition Restart = new(Resource, "restart"); + public static class Gossip { + const string Resource = $"{Node.Resource}/gossip"; + public static readonly OperationDefinition Read = new(Resource, "read"); + public static readonly OperationDefinition Update = new(Resource, "update"); + public static readonly OperationDefinition ClientRead = new($"{Resource}/client", "read"); + } + } - public static readonly OperationDefinition ProcessMessages = new(Resource, "process"); + public static class Streams { + const string Resource = "streams"; + public static readonly OperationDefinition Read = new(Resource, "read"); + public static readonly OperationDefinition Write = new(Resource, "write"); + public static readonly OperationDefinition Delete = new(Resource, "delete"); + public static readonly OperationDefinition MetadataRead = new(Resource, "metadataRead"); + public static readonly OperationDefinition MetadataWrite = new(Resource, "metadataWrite"); - public static class Parameters { - public static Parameter SubscriptionId(string id) { - return new("subscriptionId", id); - } + public static class Parameters { + public static Parameter StreamId(string streamId) => new("streamId", streamId); - public static Parameter StreamId(string streamId) { - return new("streamId", streamId); - } - } - } + public static Parameter TransactionId(long transactionId) => new("transactionId", transactionId.ToString("D")); + } + } - public static class Users { - const string Resource = "users"; - public static readonly OperationDefinition Create = new(Resource, "create"); - public static readonly OperationDefinition Update = new(Resource, "update"); - public static readonly OperationDefinition Delete = new(Resource, "delete"); - public static readonly OperationDefinition List = new(Resource, "list"); - public static readonly OperationDefinition Read = new(Resource, "read"); - public static readonly OperationDefinition CurrentUser = new(Resource, "self"); - public static readonly OperationDefinition Enable = new(Resource, "enable"); - public static readonly OperationDefinition Disable = new(Resource, "disable"); + public static class Subscriptions { + const string Resource = "subscriptions"; + public static readonly OperationDefinition Statistics = new(Resource, "statistics"); + public static readonly OperationDefinition Create = new(Resource, "create"); + public static readonly OperationDefinition Update = new(Resource, "update"); + public static readonly OperationDefinition Delete = new(Resource, "delete"); + public static readonly OperationDefinition ReplayParked = new(Resource, "replay"); + public static readonly OperationDefinition Restart = new(Resource, "restart"); - public static readonly OperationDefinition ResetPassword = new(Resource, "resetPassword"); + public static readonly OperationDefinition ProcessMessages = new(Resource, "process"); - public static readonly OperationDefinition ChangePassword = new(Resource, "updatePassword"); - public static class Parameters { - public const string UserParameterName = "user"; + public static class Parameters { + public static Parameter SubscriptionId(string id) => new("subscriptionId", id); - public static Parameter User(string userId) { - return new(UserParameterName, userId); - } - } - } + public static Parameter StreamId(string streamId) => new("streamId", streamId); + } + } - public static class Projections { - const string Resource = "projections"; + public static class Users { + const string Resource = "users"; + public static readonly OperationDefinition Create = new(Resource, "create"); + public static readonly OperationDefinition Update = new(Resource, "update"); + public static readonly OperationDefinition Delete = new(Resource, "delete"); + public static readonly OperationDefinition List = new(Resource, "list"); + public static readonly OperationDefinition Read = new(Resource, "read"); + public static readonly OperationDefinition CurrentUser = new(Resource, "self"); + public static readonly OperationDefinition Enable = new(Resource, "enable"); + public static readonly OperationDefinition Disable = new(Resource, "disable"); - public static readonly OperationDefinition Create = new(Resource, "create"); - public static readonly OperationDefinition Update = new(Resource, "update"); - public static readonly OperationDefinition Read = new(Resource, "read"); - - public static readonly OperationDefinition Abort = new(Resource, "abort"); - - public static readonly OperationDefinition List = new(Resource, "list"); - public static readonly OperationDefinition Restart = new(Resource, "restart"); - public static readonly OperationDefinition Delete = new(Resource, "delete"); - public static readonly OperationDefinition Enable = new(Resource, "enable"); - public static readonly OperationDefinition Disable = new(Resource, "disable"); - public static readonly OperationDefinition Reset = new(Resource, "reset"); - - public static readonly OperationDefinition ReadConfiguration = new($"{Resource}/configuration", "read"); - - public static readonly OperationDefinition UpdateConfiguration = new($"{Resource}/configuration", "update"); - - public static readonly OperationDefinition Status = new(Resource, "status"); - - //can be Partition based - public static readonly OperationDefinition State = new(Resource, "state"); - public static readonly OperationDefinition Result = new(Resource, "state"); - - public static readonly OperationDefinition Statistics = new(Resource, "statistics"); - - //This one is a bit weird - public static readonly OperationDefinition DebugProjection = new(Resource, "debug"); - - public static class Parameters { - public static readonly Parameter Query = new("projectionType", "query"); - public static readonly Parameter OneTime = new("projectionType", "onetime"); - public static readonly Parameter Continuous = new("projectionType", "continuous"); - - public static Parameter Projection(string name) { - return new("projection", name); - } + public static readonly OperationDefinition ResetPassword = new(Resource, "resetPassword"); - public static Parameter RunAs(string name) { - return new("runas", name); - } - } - } + public static readonly OperationDefinition ChangePassword = new(Resource, "updatePassword"); + + public static class Parameters { + public const string UserParameterName = "user"; + + public static Parameter User(string userId) => new(UserParameterName, userId); + } + } + + public static class Projections { + const string Resource = "projections"; + + public static readonly OperationDefinition Create = new(Resource, "create"); + public static readonly OperationDefinition Update = new(Resource, "update"); + public static readonly OperationDefinition Read = new(Resource, "read"); + + public static readonly OperationDefinition Abort = new(Resource, "abort"); + + public static readonly OperationDefinition List = new(Resource, "list"); + public static readonly OperationDefinition Restart = new(Resource, "restart"); + public static readonly OperationDefinition Delete = new(Resource, "delete"); + public static readonly OperationDefinition Enable = new(Resource, "enable"); + public static readonly OperationDefinition Disable = new(Resource, "disable"); + public static readonly OperationDefinition Reset = new(Resource, "reset"); + + public static readonly OperationDefinition ReadConfiguration = new($"{Resource}/configuration", "read"); + + public static readonly OperationDefinition UpdateConfiguration = new($"{Resource}/configuration", "update"); + + public static readonly OperationDefinition Status = new(Resource, "status"); + + //can be Partition based + public static readonly OperationDefinition State = new(Resource, "state"); + public static readonly OperationDefinition Result = new(Resource, "state"); + + public static readonly OperationDefinition Statistics = new(Resource, "statistics"); + + //This one is a bit weird + public static readonly OperationDefinition DebugProjection = new(Resource, "debug"); + + public static class Parameters { + public static readonly Parameter Query = new("projectionType", "query"); + public static readonly Parameter OneTime = new("projectionType", "onetime"); + public static readonly Parameter Continuous = new("projectionType", "continuous"); + + public static Parameter Projection(string name) => new("projection", name); + + public static Parameter RunAs(string name) => new("runas", name); + } + } } \ No newline at end of file diff --git a/src/EventStore.Plugins/Authorization/Parameter.cs b/src/EventStore.Plugins/Authorization/Parameter.cs index 7a061b0..4abf66f 100644 --- a/src/EventStore.Plugins/Authorization/Parameter.cs +++ b/src/EventStore.Plugins/Authorization/Parameter.cs @@ -1,42 +1,5 @@ namespace EventStore.Plugins.Authorization; public readonly record struct Parameter(string Name, string Value) { - public override string ToString() => $"{Name} : {Value}"; -} - -// -// public readonly struct Parameter : IEquatable { -// public Parameter(string name, string value) { -// Name = name ?? throw new ArgumentNullException(nameof(name)); -// Value = value ?? throw new ArgumentNullException(nameof(value)); -// } -// -// public string Name { get; } -// public string Value { get; } -// -// public bool Equals(Parameter other) { -// return Name == other.Name && Value == other.Value; -// } -// -// public override bool Equals(object obj) { -// return obj is Parameter other && Equals(other); -// } -// -// public override int GetHashCode() { -// unchecked { -// return Name.GetHashCode() * 397 ^ Value.GetHashCode(); -// } -// } -// -// public static bool operator ==(Parameter left, Parameter right) { -// return left.Equals(right); -// } -// -// public static bool operator !=(Parameter left, Parameter right) { -// return !left.Equals(right); -// } -// -// public override string ToString() { -// return $"{Name} : {Value}"; -// } -// } \ No newline at end of file + public override string ToString() => $"{Name} : {Value}"; +} \ No newline at end of file diff --git a/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsData.cs b/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsData.cs index 47056d3..4f625ca 100644 --- a/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsData.cs +++ b/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsData.cs @@ -1,7 +1,7 @@ namespace EventStore.Plugins.Diagnostics; /// -/// Represents diagnostic data of a plugin. +/// Represents diagnostic data of a plugin. /// /// The source of the event that matches the DiagnosticsName /// The name of the event. The default is PluginDiagnosticsData. @@ -9,9 +9,9 @@ namespace EventStore.Plugins.Diagnostics; /// When the event occurred. /// Whether the event is a snapshot and should override previously collected data, by event name. Default value is true. public readonly record struct PluginDiagnosticsData( - string Source, - string EventName, - Dictionary Data, - DateTimeOffset Timestamp, - bool IsSnapshot = true + string Source, + string EventName, + Dictionary Data, + DateTimeOffset Timestamp, + bool IsSnapshot = true ); \ No newline at end of file diff --git a/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsDataCollector.cs b/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsDataCollector.cs index 702e273..541bd22 100644 --- a/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsDataCollector.cs +++ b/src/EventStore.Plugins/Diagnostics/PluginDiagnosticsDataCollector.cs @@ -4,108 +4,108 @@ namespace EventStore.Plugins.Diagnostics; /// -/// A delegate to handle events. +/// A delegate to handle events. /// public delegate void OnEventCollected(PluginDiagnosticsData diagnosticsData); /// -/// Component to collect diagnostics data from plugins. More specifically events. +/// Component to collect diagnostics data from plugins. More specifically events. /// [PublicAPI] public class PluginDiagnosticsDataCollector : IObserver, IObserver>, IDisposable { - /// - /// Creates a new instance of . - /// - /// - /// A delegate to handle events. - /// - /// - /// The plugin diagnostic names to collect diagnostics data from. - /// - public PluginDiagnosticsDataCollector(OnEventCollected onEventCollected, params string[] sources) { - OnEventCollected = onEventCollected; - Sources = [..sources]; - - if (sources.Length > 0) - DiagnosticListener.AllListeners.Subscribe(this); - } - - /// - /// Creates a new instance of . - /// - /// - /// The plugin diagnostic names to collect diagnostics data from. - /// - public PluginDiagnosticsDataCollector(params string[] sources) : this(static _ => {}, sources) { } - - ConcurrentDictionary CollectedEventsByPlugin { get; } = new(); - OnEventCollected OnEventCollected { get; } - List Sources { get; } - List Subscriptions { get; } = []; - - /// - /// The collected events. - /// - public ICollection CollectedEvents => CollectedEventsByPlugin.Values.ToArray(); - - void IObserver.OnNext(DiagnosticListener value) { - // if (Sources.Contains(value.Name) && value.IsEnabled(value.Name)) - if (Sources.Contains(value.Name)) - Subscriptions.Add(value.Subscribe(this)); - } - - void IObserver>.OnNext(KeyValuePair value) { - if (value.Key != nameof(PluginDiagnosticsData) || value.Value is not PluginDiagnosticsData pluginEvent) return; - - CollectedEventsByPlugin.AddOrUpdate( - pluginEvent.Source, - static (_, pluginEvent) => pluginEvent, - static (_, _, pluginEvent) => pluginEvent, - pluginEvent - ); - - try { - OnEventCollected(pluginEvent); - } - catch (Exception) { - // stay on target - } - } - - void IObserver.OnCompleted() { } - - void IObserver>.OnCompleted() { } - - void IObserver.OnError(Exception error) { } - - void IObserver>.OnError(Exception error) { } - - /// - public void Dispose() { - foreach (var subscription in Subscriptions) - subscription.Dispose(); - } - - /// - /// Starts the with the specified delegate and sources. - /// This method is a convenient way to create a new instance of the and start collecting data immediately. - /// - /// - /// A delegate to handle events. - /// - /// - /// The plugin diagnostic names to collect diagnostics data from. - /// - public static PluginDiagnosticsDataCollector Start(OnEventCollected onEventCollected, params string[] sources) => - new(onEventCollected, sources); - - /// - /// Starts the with the specified sources. - /// This method is a convenient way to create a new instance of the and start collecting data immediately. - /// - /// - /// The plugin diagnostic names to collect diagnostics data from. - /// - public static PluginDiagnosticsDataCollector Start(params string[] sources) => - new(sources); + /// + /// Creates a new instance of . + /// + /// + /// A delegate to handle events. + /// + /// + /// The plugin diagnostic names to collect diagnostics data from. + /// + public PluginDiagnosticsDataCollector(OnEventCollected onEventCollected, params string[] sources) { + OnEventCollected = onEventCollected; + Sources = [..sources]; + + if (sources.Length > 0) + DiagnosticListener.AllListeners.Subscribe(this); + } + + /// + /// Creates a new instance of . + /// + /// + /// The plugin diagnostic names to collect diagnostics data from. + /// + public PluginDiagnosticsDataCollector(params string[] sources) : this(static _ => { }, sources) { } + + ConcurrentDictionary CollectedEventsByPlugin { get; } = new(); + OnEventCollected OnEventCollected { get; } + List Sources { get; } + List Subscriptions { get; } = []; + + /// + /// The collected events. + /// + public ICollection CollectedEvents => CollectedEventsByPlugin.Values.ToArray(); + + void IObserver.OnNext(DiagnosticListener value) { + // if (Sources.Contains(value.Name) && value.IsEnabled(value.Name)) + if (Sources.Contains(value.Name)) + Subscriptions.Add(value.Subscribe(this)); + } + + void IObserver>.OnNext(KeyValuePair value) { + if (value.Key != nameof(PluginDiagnosticsData) || value.Value is not PluginDiagnosticsData pluginEvent) return; + + CollectedEventsByPlugin.AddOrUpdate( + pluginEvent.Source, + static (_, pluginEvent) => pluginEvent, + static (_, _, pluginEvent) => pluginEvent, + pluginEvent + ); + + try { + OnEventCollected(pluginEvent); + } + catch (Exception) { + // stay on target + } + } + + void IObserver.OnCompleted() { } + + void IObserver>.OnCompleted() { } + + void IObserver.OnError(Exception error) { } + + void IObserver>.OnError(Exception error) { } + + /// + public void Dispose() { + foreach (var subscription in Subscriptions) + subscription.Dispose(); + } + + /// + /// Starts the with the specified delegate and sources. + /// This method is a convenient way to create a new instance of the and start collecting data immediately. + /// + /// + /// A delegate to handle events. + /// + /// + /// The plugin diagnostic names to collect diagnostics data from. + /// + public static PluginDiagnosticsDataCollector Start(OnEventCollected onEventCollected, params string[] sources) => + new(onEventCollected, sources); + + /// + /// Starts the with the specified sources. + /// This method is a convenient way to create a new instance of the and start collecting data immediately. + /// + /// + /// The plugin diagnostic names to collect diagnostics data from. + /// + public static PluginDiagnosticsDataCollector Start(params string[] sources) => + new(sources); } \ No newline at end of file diff --git a/src/EventStore.Plugins/IPlugableComponent.cs b/src/EventStore.Plugins/IPlugableComponent.cs index 70dac46..c27f16f 100644 --- a/src/EventStore.Plugins/IPlugableComponent.cs +++ b/src/EventStore.Plugins/IPlugableComponent.cs @@ -5,46 +5,46 @@ namespace EventStore.Plugins; /// -/// Component that can be plugged into the main server. +/// Component that can be plugged into the main server. /// public interface IPlugableComponent { - /// - /// The name of the component. - /// - string Name { get; } - - /// - /// The name used for diagnostics. - /// - string DiagnosticsName { get; } - - /// - /// The tags used for diagnostics. - /// - KeyValuePair[] DiagnosticsTags { get; } - - /// - /// The version of the component. - /// - string Version { get; } - - /// - /// Indicates whether the component is enabled. - /// - bool Enabled { get; } - - /// - /// Configures the services using the provided IServiceCollection and IConfiguration. - /// - /// The IServiceCollection to use for configuration. - /// The IConfiguration to use for configuration. - /// The configured IServiceCollection. - IServiceCollection ConfigureServices(IServiceCollection services, IConfiguration configuration); - - /// - /// Configures the application using the provided WebHostBuilderContext and IApplicationBuilder. - /// - /// The IApplicationBuilder to use for configuration. - /// The configured IApplicationBuilder. - IApplicationBuilder Configure(IApplicationBuilder builder); + /// + /// The name of the component. + /// + string Name { get; } + + /// + /// The name used for diagnostics. + /// + string DiagnosticsName { get; } + + /// + /// The tags used for diagnostics. + /// + KeyValuePair[] DiagnosticsTags { get; } + + /// + /// The version of the component. + /// + string Version { get; } + + /// + /// Indicates whether the component is enabled. + /// + bool Enabled { get; } + + /// + /// Configures the services using the provided IServiceCollection and IConfiguration. + /// + /// The IServiceCollection to use for configuration. + /// The IConfiguration to use for configuration. + /// The configured IServiceCollection. + IServiceCollection ConfigureServices(IServiceCollection services, IConfiguration configuration); + + /// + /// Configures the application using the provided WebHostBuilderContext and IApplicationBuilder. + /// + /// The IApplicationBuilder to use for configuration. + /// The configured IApplicationBuilder. + IApplicationBuilder Configure(IApplicationBuilder builder); } \ No newline at end of file diff --git a/src/EventStore.Plugins/InflectorExtensions.cs b/src/EventStore.Plugins/InflectorExtensions.cs index 9d07587..91e0031 100644 --- a/src/EventStore.Plugins/InflectorExtensions.cs +++ b/src/EventStore.Plugins/InflectorExtensions.cs @@ -26,20 +26,20 @@ namespace EventStore.Plugins; static class InflectorExtensions { - /// - /// Separates the input words with underscore - /// - public static string Underscore(this string input) => - Regex.Replace(Regex.Replace(Regex.Replace(input, @"([\p{Lu}]+)([\p{Lu}][\p{Ll}])", "$1_$2"), @"([\p{Ll}\d])([\p{Lu}])", "$1_$2"), @"[-\s]", "_") - .ToLowerInvariant(); - - /// - /// Replaces underscores with dashes in the string - /// - public static string Dasherize(this string underscoredWord) => underscoredWord.Replace('_', '-'); - - /// - /// Separates the input words with hyphens and all the words are converted to lowercase - /// - public static string Kebaberize(this string input) => Underscore(input).Dasherize(); + /// + /// Separates the input words with underscore + /// + public static string Underscore(this string input) => + Regex.Replace(Regex.Replace(Regex.Replace(input, @"([\p{Lu}]+)([\p{Lu}][\p{Ll}])", "$1_$2"), @"([\p{Ll}\d])([\p{Lu}])", "$1_$2"), @"[-\s]", "_") + .ToLowerInvariant(); + + /// + /// Replaces underscores with dashes in the string + /// + public static string Dasherize(this string underscoredWord) => underscoredWord.Replace('_', '-'); + + /// + /// Separates the input words with hyphens and all the words are converted to lowercase + /// + public static string Kebaberize(this string input) => Underscore(input).Dasherize(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Licensing/License.cs b/src/EventStore.Plugins/Licensing/License.cs index eaaa475..fbef7cf 100644 --- a/src/EventStore.Plugins/Licensing/License.cs +++ b/src/EventStore.Plugins/Licensing/License.cs @@ -10,15 +10,14 @@ public async Task IsValidAsync(string publicKey) { var result = await ValidateTokenAsync(publicKey, Token.EncodedToken); return result.IsValid; } - - public bool IsValid(string publicKey) => - IsValidAsync(publicKey).GetAwaiter().GetResult(); + + public bool IsValid(string publicKey) => + IsValidAsync(publicKey).GetAwaiter().GetResult(); 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(); @@ -27,7 +26,7 @@ public static async Task CreateAsync( Issuer = "esdb", Expires = DateTime.UtcNow + TimeSpan.FromHours(1), Claims = claims, - SigningCredentials = new(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256), + SigningCredentials = new(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256) }); var result = await ValidateTokenAsync(publicKey, token); @@ -41,13 +40,13 @@ public static async Task CreateAsync( 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) { + 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; @@ -55,16 +54,16 @@ static async Task ValidateTokenAsync(string publicKey, st rsa.ImportRSAPublicKey(FromBase64String(publicKey), out _); var result = await new JsonWebTokenHandler().ValidateTokenAsync( token, - new() - { + new() { ValidIssuer = "esdb", ValidAudience = "esdb", IssuerSigningKey = new RsaSecurityKey(rsa), ValidateAudience = true, ValidateIssuerSigningKey = true, ValidateIssuer = true, - ValidateLifetime = true, + ValidateLifetime = true }); + return result; } -} +} \ No newline at end of file diff --git a/src/EventStore.Plugins/MD5/IMD5Plugin.cs b/src/EventStore.Plugins/MD5/IMD5Plugin.cs index fe4e571..955d1c3 100644 --- a/src/EventStore.Plugins/MD5/IMD5Plugin.cs +++ b/src/EventStore.Plugins/MD5/IMD5Plugin.cs @@ -1,12 +1,12 @@ namespace EventStore.Plugins.MD5; public interface IMD5Plugin { - string Name { get; } - string Version { get; } - string CommandLineName { get; } + string Name { get; } + string Version { get; } + string CommandLineName { get; } - /// - /// Creates an MD5 provider factory for the MD5 plugin - /// - IMD5ProviderFactory GetMD5ProviderFactory(); + /// + /// Creates an MD5 provider factory for the MD5 plugin + /// + IMD5ProviderFactory GetMD5ProviderFactory(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/MD5/IMD5Provider.cs b/src/EventStore.Plugins/MD5/IMD5Provider.cs index 562a33c..507d6ca 100644 --- a/src/EventStore.Plugins/MD5/IMD5Provider.cs +++ b/src/EventStore.Plugins/MD5/IMD5Provider.cs @@ -3,8 +3,8 @@ namespace EventStore.Plugins.MD5; public interface IMD5Provider : IPlugableComponent { - /// - /// Creates an instance of the MD5 hash algorithm implementation - /// - HashAlgorithm Create(); + /// + /// Creates an instance of the MD5 hash algorithm implementation + /// + HashAlgorithm Create(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/MD5/IMD5ProviderFactory.cs b/src/EventStore.Plugins/MD5/IMD5ProviderFactory.cs index ae33426..1919355 100644 --- a/src/EventStore.Plugins/MD5/IMD5ProviderFactory.cs +++ b/src/EventStore.Plugins/MD5/IMD5ProviderFactory.cs @@ -1,8 +1,8 @@ namespace EventStore.Plugins.MD5; public interface IMD5ProviderFactory { - /// - /// Builds an MD5 provider for the MD5 plugin - /// - IMD5Provider Build(); + /// + /// Builds an MD5 provider for the MD5 plugin + /// + IMD5Provider Build(); } \ No newline at end of file diff --git a/src/EventStore.Plugins/Plugin.cs b/src/EventStore.Plugins/Plugin.cs index bc83d84..f3dab70 100644 --- a/src/EventStore.Plugins/Plugin.cs +++ b/src/EventStore.Plugins/Plugin.cs @@ -10,137 +10,137 @@ namespace EventStore.Plugins; public record PluginOptions { - public string? Name { get; init; } - public string? Version { get; init; } - public string? LicensePublicKey { get; init; } - public string? DiagnosticsName { get; init; } - public KeyValuePair[] DiagnosticsTags { get; init; } = []; + public string? Name { get; init; } + public string? Version { get; init; } + public string? LicensePublicKey { get; init; } + public string? DiagnosticsName { get; init; } + public KeyValuePair[] DiagnosticsTags { get; init; } = []; } [PublicAPI] public abstract class Plugin : IPlugableComponent, IDisposable { - protected Plugin( - string? name = null, - string? version = null, - string? licensePublicKey = null, - string? diagnosticsName = null, - params KeyValuePair[] diagnosticsTags) { - var pluginType = GetType(); - - Name = name ?? pluginType.Name - .Replace("Plugin", "", OrdinalIgnoreCase) - .Replace("Component", "", OrdinalIgnoreCase) - .Replace("Subsystems", "", OrdinalIgnoreCase) - .Replace("Subsystem", "", OrdinalIgnoreCase); - - Version = version - ?? pluginType.Assembly.GetName().Version?.ToString() - ?? "1.0.0.0-preview"; - - LicensePublicKey = licensePublicKey; - - DiagnosticsName = diagnosticsName ?? Name; - DiagnosticsTags = diagnosticsTags; - - DiagnosticListener = new(DiagnosticsName); - - IsEnabledResult = (false, ""); - Configuration = null!; - } - - protected Plugin(PluginOptions options) : this( - options.Name, - options.Version, - options.LicensePublicKey, - options.DiagnosticsName, - options.DiagnosticsTags) { } - - string? LicensePublicKey { get; } - - DiagnosticListener DiagnosticListener { get; } - - (bool Enabled, string EnableInstructions) IsEnabledResult { get; set; } - - IConfiguration Configuration { get; set; } - - /// - public string Name { get; } - - /// - public string Version { get; } - - /// - public string DiagnosticsName { get; } - - /// - public KeyValuePair[] DiagnosticsTags { get; } - - /// - public bool Enabled => IsEnabledResult.Enabled; - - protected virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration) { } - - protected virtual void ConfigureApplication(IApplicationBuilder app, IConfiguration configuration) { } - - protected virtual (bool Enabled, string EnableInstructions) IsEnabled(IConfiguration configuration) => (true, ""); - - IServiceCollection IPlugableComponent.ConfigureServices(IServiceCollection services, IConfiguration configuration) { - Configuration = configuration; - IsEnabledResult = IsEnabled(configuration); - - if (Enabled) - ConfigureServices(services, configuration); - - return services; - } - - IApplicationBuilder IPlugableComponent.Configure(IApplicationBuilder app) { - PublishDiagnostics(new() { ["enabled"] = Enabled }); - - var logger = app.ApplicationServices.GetRequiredService().CreateLogger(GetType()); - - var license = app.ApplicationServices.GetService(); - if (Enabled && LicensePublicKey is not null && (license is null || !license.IsValid(LicensePublicKey))) - throw new PluginLicenseException(Name); - - if (!Enabled) { - logger.LogInformation( - "{Version} plugin disabled. {EnableInstructions}", - Version, IsEnabledResult.EnableInstructions - ); - - return app; - } - - logger.LogInformation("{Version} plugin enabled.", Version); - - ConfigureApplication(app, Configuration); - - PublishDiagnostics(new() { ["enabled"] = Enabled }); - - return app; - } - - protected internal void PublishDiagnostics(string eventName, Dictionary eventData) { - DiagnosticListener.Write( - nameof(PluginDiagnosticsData), - new PluginDiagnosticsData( - DiagnosticsName, - eventName, - eventData, - DateTimeOffset.UtcNow - ) - ); - } - - protected internal void PublishDiagnostics(Dictionary eventData) => - PublishDiagnostics(nameof(PluginDiagnosticsData), eventData); - - protected internal void PublishDiagnosticsEvent(T pluginEvent) => - DiagnosticListener.Write(typeof(T).Name, pluginEvent); - - /// - public void Dispose() { - DiagnosticListener.Dispose(); - } -} + protected Plugin( + string? name = null, + string? version = null, + string? licensePublicKey = null, + string? diagnosticsName = null, + params KeyValuePair[] diagnosticsTags) { + var pluginType = GetType(); + + Name = name ?? pluginType.Name + .Replace("Plugin", "", OrdinalIgnoreCase) + .Replace("Component", "", OrdinalIgnoreCase) + .Replace("Subsystems", "", OrdinalIgnoreCase) + .Replace("Subsystem", "", OrdinalIgnoreCase); + + Version = version + ?? pluginType.Assembly.GetName().Version?.ToString() + ?? "1.0.0.0-preview"; + + LicensePublicKey = licensePublicKey; + + DiagnosticsName = diagnosticsName ?? Name; + DiagnosticsTags = diagnosticsTags; + + DiagnosticListener = new(DiagnosticsName); + + IsEnabledResult = (false, ""); + Configuration = null!; + } + + protected Plugin(PluginOptions options) : this( + options.Name, + options.Version, + options.LicensePublicKey, + options.DiagnosticsName, + options.DiagnosticsTags) { } + + string? LicensePublicKey { get; } + + DiagnosticListener DiagnosticListener { get; } + + (bool Enabled, string EnableInstructions) IsEnabledResult { get; set; } + + IConfiguration Configuration { get; set; } + + /// + public string Name { get; } + + /// + public string Version { get; } + + /// + public string DiagnosticsName { get; } + + /// + public KeyValuePair[] DiagnosticsTags { get; } + + /// + public bool Enabled => IsEnabledResult.Enabled; + + protected virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration) { } + + protected virtual void ConfigureApplication(IApplicationBuilder app, IConfiguration configuration) { } + + protected virtual (bool Enabled, string EnableInstructions) IsEnabled(IConfiguration configuration) => (true, ""); + + IServiceCollection IPlugableComponent.ConfigureServices(IServiceCollection services, IConfiguration configuration) { + Configuration = configuration; + IsEnabledResult = IsEnabled(configuration); + + if (Enabled) + ConfigureServices(services, configuration); + + return services; + } + + IApplicationBuilder IPlugableComponent.Configure(IApplicationBuilder app) { + PublishDiagnostics(new() { ["enabled"] = Enabled }); + + var logger = app.ApplicationServices.GetRequiredService().CreateLogger(GetType()); + + var license = app.ApplicationServices.GetService(); + if (Enabled && LicensePublicKey is not null && (license is null || !license.IsValid(LicensePublicKey))) + throw new PluginLicenseException(Name); + + if (!Enabled) { + logger.LogInformation( + "{Version} plugin disabled. {EnableInstructions}", + Version, IsEnabledResult.EnableInstructions + ); + + return app; + } + + logger.LogInformation("{Version} plugin enabled.", Version); + + ConfigureApplication(app, Configuration); + + PublishDiagnostics(new() { ["enabled"] = Enabled }); + + return app; + } + + protected internal void PublishDiagnostics(string eventName, Dictionary eventData) { + DiagnosticListener.Write( + nameof(PluginDiagnosticsData), + new PluginDiagnosticsData( + DiagnosticsName, + eventName, + eventData, + DateTimeOffset.UtcNow + ) + ); + } + + protected internal void PublishDiagnostics(Dictionary eventData) => + PublishDiagnostics(nameof(PluginDiagnosticsData), eventData); + + protected internal void PublishDiagnosticsEvent(T pluginEvent) => + DiagnosticListener.Write(typeof(T).Name, pluginEvent); + + /// + public void Dispose() { + DiagnosticListener.Dispose(); + } +} \ No newline at end of file diff --git a/src/EventStore.Plugins/PluginLicenseException.cs b/src/EventStore.Plugins/PluginLicenseException.cs index d5de2ac..b59b40e 100644 --- a/src/EventStore.Plugins/PluginLicenseException.cs +++ b/src/EventStore.Plugins/PluginLicenseException.cs @@ -1,8 +1,8 @@ namespace EventStore.Plugins; public class PluginLicenseException(string pluginName) : Exception( - $"A license is required to use the {pluginName} plugin, but was not found. " + - "Please obtain a license or disable the plugin." + $"A license is required to use the {pluginName} plugin, but was not found. " + + "Please obtain a license or disable the plugin." ) { - public string PluginName { get; } = pluginName; + public string PluginName { get; } = pluginName; } \ No newline at end of file diff --git a/src/EventStore.Plugins/Subsystems/ISubsystem.cs b/src/EventStore.Plugins/Subsystems/ISubsystem.cs index c4bb626..06d405f 100644 --- a/src/EventStore.Plugins/Subsystems/ISubsystem.cs +++ b/src/EventStore.Plugins/Subsystems/ISubsystem.cs @@ -3,4 +3,4 @@ public interface ISubsystem : IPlugableComponent { Task Start(); Task Stop(); -} +} \ No newline at end of file diff --git a/src/EventStore.Plugins/Subsystems/ISubsystemsPlugin.cs b/src/EventStore.Plugins/Subsystems/ISubsystemsPlugin.cs index e476620..022536f 100644 --- a/src/EventStore.Plugins/Subsystems/ISubsystemsPlugin.cs +++ b/src/EventStore.Plugins/Subsystems/ISubsystemsPlugin.cs @@ -1,12 +1,12 @@ namespace EventStore.Plugins.Subsystems; /// -/// A plugin that can create multiple subsystems. +/// A plugin that can create multiple subsystems. /// public interface ISubsystemsPlugin { string Name { get; } string Version { get; } string CommandLineName { get; } - - IReadOnlyList GetSubsystems(); -} + + IReadOnlyList GetSubsystems(); +} \ No newline at end of file diff --git a/src/EventStore.Plugins/SubsystemsPlugin.cs b/src/EventStore.Plugins/SubsystemsPlugin.cs index 038eacd..1fdf2c5 100644 --- a/src/EventStore.Plugins/SubsystemsPlugin.cs +++ b/src/EventStore.Plugins/SubsystemsPlugin.cs @@ -4,40 +4,40 @@ namespace EventStore.Plugins; public record SubsystemsPluginOptions : PluginOptions { - public string? CommandLineName { get; init; } + public string? CommandLineName { get; init; } } [PublicAPI] public abstract class SubsystemsPlugin : Plugin, ISubsystem, ISubsystemsPlugin { - protected SubsystemsPlugin(SubsystemsPluginOptions options) : base(options) { - CommandLineName = options.CommandLineName ?? options.Name ?? GetType().Name - .Replace("Plugin", "", OrdinalIgnoreCase) - .Replace("Component", "", OrdinalIgnoreCase) - .Replace("Subsystems", "", OrdinalIgnoreCase) - .Replace("Subsystem", "", OrdinalIgnoreCase) - .Kebaberize(); - } - - protected SubsystemsPlugin( - string? name = null, string? version = null, - string? licensePublicKey = null, - string? commandLineName = null, - string? diagnosticsName = null, - params KeyValuePair[] diagnosticsTags - ) : this(new() { - Name = name, - Version = version, - LicensePublicKey = licensePublicKey, - DiagnosticsName = diagnosticsName, - DiagnosticsTags = diagnosticsTags, - CommandLineName = commandLineName - }) { } - - public string CommandLineName { get; } - - public virtual Task Start() => Task.CompletedTask; - - public virtual Task Stop() => Task.CompletedTask; - - public virtual IReadOnlyList GetSubsystems() => [this]; + protected SubsystemsPlugin(SubsystemsPluginOptions options) : base(options) { + CommandLineName = options.CommandLineName ?? options.Name ?? GetType().Name + .Replace("Plugin", "", OrdinalIgnoreCase) + .Replace("Component", "", OrdinalIgnoreCase) + .Replace("Subsystems", "", OrdinalIgnoreCase) + .Replace("Subsystem", "", OrdinalIgnoreCase) + .Kebaberize(); + } + + protected SubsystemsPlugin( + string? name = null, string? version = null, + string? licensePublicKey = null, + string? commandLineName = null, + string? diagnosticsName = null, + params KeyValuePair[] diagnosticsTags + ) : this(new() { + Name = name, + Version = version, + LicensePublicKey = licensePublicKey, + DiagnosticsName = diagnosticsName, + DiagnosticsTags = diagnosticsTags, + CommandLineName = commandLineName + }) { } + + public string CommandLineName { get; } + + public virtual Task Start() => Task.CompletedTask; + + public virtual Task Stop() => Task.CompletedTask; + + public virtual IReadOnlyList GetSubsystems() => [this]; } \ No newline at end of file diff --git a/test/EventStore.Plugins.Tests/ConfigurationReaderTests/LdapsSettings.cs b/test/EventStore.Plugins.Tests/ConfigurationReaderTests/LdapsSettings.cs index 8fd68f9..d2489cc 100644 --- a/test/EventStore.Plugins.Tests/ConfigurationReaderTests/LdapsSettings.cs +++ b/test/EventStore.Plugins.Tests/ConfigurationReaderTests/LdapsSettings.cs @@ -1,24 +1,24 @@ namespace EventStore.Plugins.Tests.ConfigurationReaderTests; public class LdapsSettings { - public string Host { get; set; } = null!; - public int Port { get; set; } = 636; - public bool ValidateServerCertificate { get; set; } - public bool UseSSL { get; set; } = true; + public string Host { get; set; } = null!; + public int Port { get; set; } = 636; + public bool ValidateServerCertificate { get; set; } + public bool UseSSL { get; set; } = true; - public bool AnonymousBind { get; set; } - public string BindUser { get; set; } = null!; - public string BindPassword { get; set; } = null!; + public bool AnonymousBind { get; set; } + public string BindUser { get; set; } = null!; + public string BindPassword { get; set; } = null!; - public string BaseDn { get; set; } = null!; - public string ObjectClass { get; set; } = "organizationalPerson"; - public string Filter { get; set; } = "sAMAccountName"; - public string GroupMembershipAttribute { get; set; } = "memberOf"; + public string BaseDn { get; set; } = null!; + public string ObjectClass { get; set; } = "organizationalPerson"; + public string Filter { get; set; } = "sAMAccountName"; + public string GroupMembershipAttribute { get; set; } = "memberOf"; - public bool RequireGroupMembership { get; set; } - public string RequiredGroupDn { get; set; } = null!; + public bool RequireGroupMembership { get; set; } + public string RequiredGroupDn { get; set; } = null!; - public int PrincipalCacheDurationSec { get; set; } = 60; + public int PrincipalCacheDurationSec { get; set; } = 60; - public Dictionary LdapGroupRoles { get; set; } = null!; + public Dictionary LdapGroupRoles { get; set; } = null!; } \ No newline at end of file diff --git a/test/EventStore.Plugins.Tests/ConfigurationReaderTests/when_reading_valid_configuration.cs b/test/EventStore.Plugins.Tests/ConfigurationReaderTests/when_reading_valid_configuration.cs index 4e42b3f..b31e60d 100644 --- a/test/EventStore.Plugins.Tests/ConfigurationReaderTests/when_reading_valid_configuration.cs +++ b/test/EventStore.Plugins.Tests/ConfigurationReaderTests/when_reading_valid_configuration.cs @@ -1,30 +1,30 @@ namespace EventStore.Plugins.Tests.ConfigurationReaderTests; public class when_reading_valid_configuration { - [Fact] - public void should_return_correct_options() { - var settings = ConfigParser.ReadConfiguration( - Path.Combine("ConfigurationReaderTests", "valid_node_config.yaml"), - "LdapsAuth" - ); + [Fact] + public void should_return_correct_options() { + var settings = ConfigParser.ReadConfiguration( + Path.Combine("ConfigurationReaderTests", "valid_node_config.yaml"), + "LdapsAuth" + ); - settings!.Host.Should().Be("13.64.104.29"); - settings.Port.Should().Be(389); - settings.ValidateServerCertificate.Should().BeFalse(); - settings.UseSSL.Should().BeFalse(); - settings.AnonymousBind.Should().BeFalse(); - settings.BindUser.Should().Be("mycompany\\binder"); - settings.BindPassword.Should().Be("p@ssw0rd!"); - settings.BaseDn.Should().Be("ou=Lab,dc=mycompany,dc=local"); - settings.ObjectClass.Should().Be("organizationalPerson"); - settings.GroupMembershipAttribute.Should().Be("memberOf"); - settings.RequireGroupMembership.Should().BeFalse(); - settings.RequiredGroupDn.Should().Be("RequiredGroupDn"); - settings.PrincipalCacheDurationSec.Should().Be(120); - settings.LdapGroupRoles.Should().BeEquivalentTo(new Dictionary { - { "CN=ES-Accounting,CN=Users,DC=mycompany,DC=local", "accounting" }, - { "CN=ES-Operations,CN=Users,DC=mycompany,DC=local", "it" }, - { "CN=ES-Admins,CN=Users,DC=mycompany,DC=local", "$admins" } - }); - } + settings!.Host.Should().Be("13.64.104.29"); + settings.Port.Should().Be(389); + settings.ValidateServerCertificate.Should().BeFalse(); + settings.UseSSL.Should().BeFalse(); + settings.AnonymousBind.Should().BeFalse(); + settings.BindUser.Should().Be("mycompany\\binder"); + settings.BindPassword.Should().Be("p@ssw0rd!"); + settings.BaseDn.Should().Be("ou=Lab,dc=mycompany,dc=local"); + settings.ObjectClass.Should().Be("organizationalPerson"); + settings.GroupMembershipAttribute.Should().Be("memberOf"); + settings.RequireGroupMembership.Should().BeFalse(); + settings.RequiredGroupDn.Should().Be("RequiredGroupDn"); + settings.PrincipalCacheDurationSec.Should().Be(120); + settings.LdapGroupRoles.Should().BeEquivalentTo(new Dictionary { + { "CN=ES-Accounting,CN=Users,DC=mycompany,DC=local", "accounting" }, + { "CN=ES-Operations,CN=Users,DC=mycompany,DC=local", "it" }, + { "CN=ES-Admins,CN=Users,DC=mycompany,DC=local", "$admins" } + }); + } } \ No newline at end of file diff --git a/test/EventStore.Plugins.Tests/Diagnostics/PluginDiagnosticsDataCollectorTests.cs b/test/EventStore.Plugins.Tests/Diagnostics/PluginDiagnosticsDataCollectorTests.cs index 63f3acc..5af6565 100644 --- a/test/EventStore.Plugins.Tests/Diagnostics/PluginDiagnosticsDataCollectorTests.cs +++ b/test/EventStore.Plugins.Tests/Diagnostics/PluginDiagnosticsDataCollectorTests.cs @@ -3,32 +3,31 @@ namespace EventStore.Plugins.Tests.Diagnostics; public class PluginDiagnosticsDataCollectorTests { - [Fact] - public void can_collect_diagnostics_data_from_plugin() { - using var plugin = new TestPlugin(pluginName: Guid.NewGuid().ToString()); - - using var sut = PluginDiagnosticsDataCollector.Start(plugin.DiagnosticsName); + [Fact] + public void can_collect_diagnostics_data_from_plugin() { + using var plugin = new TestPlugin(pluginName: Guid.NewGuid().ToString()); - plugin.PublishDiagnostics(new() { ["enabled"] = plugin.Enabled }); + using var sut = PluginDiagnosticsDataCollector.Start(plugin.DiagnosticsName); - sut.CollectedEvents.Should().ContainSingle().Which - .Data["enabled"].Should().Be(plugin.Enabled); - } + plugin.PublishDiagnostics(new() { ["enabled"] = plugin.Enabled }); - [Fact] - public void can_collect_diagnostics_data_from_subsystems_plugin() { - using var plugin = new TestSubsystemsPlugin(pluginName: Guid.NewGuid().ToString()); + sut.CollectedEvents.Should().ContainSingle().Which + .Data["enabled"].Should().Be(plugin.Enabled); + } - using var sut = PluginDiagnosticsDataCollector.Start(plugin.DiagnosticsName); + [Fact] + public void can_collect_diagnostics_data_from_subsystems_plugin() { + using var plugin = new TestSubsystemsPlugin(pluginName: Guid.NewGuid().ToString()); - plugin.PublishDiagnostics(new() { ["enabled"] = plugin.Enabled }); + using var sut = PluginDiagnosticsDataCollector.Start(plugin.DiagnosticsName); - sut.CollectedEvents.Should().ContainSingle().Which - .Data["enabled"].Should().Be(plugin.Enabled); - } + plugin.PublishDiagnostics(new() { ["enabled"] = plugin.Enabled }); - class TestPlugin(string? pluginName = null) : Plugin(pluginName); + sut.CollectedEvents.Should().ContainSingle().Which + .Data["enabled"].Should().Be(plugin.Enabled); + } - class TestSubsystemsPlugin(string? pluginName = null) : SubsystemsPlugin(pluginName); -} + class TestPlugin(string? pluginName = null) : Plugin(pluginName); + class TestSubsystemsPlugin(string? pluginName = null) : SubsystemsPlugin(pluginName); +} \ No newline at end of file diff --git a/test/EventStore.Plugins.Tests/Diagnostics/PluginMetricsTests.cs b/test/EventStore.Plugins.Tests/Diagnostics/PluginMetricsTests.cs index 56af130..b3c7288 100644 --- a/test/EventStore.Plugins.Tests/Diagnostics/PluginMetricsTests.cs +++ b/test/EventStore.Plugins.Tests/Diagnostics/PluginMetricsTests.cs @@ -7,50 +7,50 @@ namespace EventStore.Plugins.Tests.Diagnostics; public class PluginMetricsTests { - [Fact] - public void can_receive_metrics_from_plugin() { - // Arrange - IPlugableComponent plugin = new AdamSmasherPlugin(diagnosticsTags: new KeyValuePair("test_name", "can_receive_metrics_from_plugin")); - - var builder = WebApplication.CreateBuilder(); - - plugin.ConfigureServices(builder.Services, builder.Configuration); - - using var app = builder.Build(); - - plugin.Configure(app); - - using var collector = new MetricCollector( - app.Services.GetRequiredService(), - plugin.DiagnosticsName, - ((AdamSmasherPlugin)plugin).TestCounter.Name - ); - - // Act - ((AdamSmasherPlugin)plugin).TestCounter.Add(1, plugin.DiagnosticsTags); // we also need to add then here? ffs... they should propagate from the meter... - - // Assert - var collectedMeasurement = collector.GetMeasurementSnapshot().Should().ContainSingle().Which; - - collectedMeasurement.Value.Should().Be(1); - - collectedMeasurement.Tags.Should().BeEquivalentTo(plugin.DiagnosticsTags); - } - - class AdamSmasherPlugin(params KeyValuePair[] diagnosticsTags) : Plugin(diagnosticsTags: diagnosticsTags) { - public Counter TestCounter { get; private set; } = null!; - - protected override void ConfigureApplication(IApplicationBuilder app, IConfiguration configuration) { - var meterFactory = app.ApplicationServices.GetRequiredService(); - - var meter = meterFactory.Create(DiagnosticsName, Version, DiagnosticsTags); - - TestCounter = meter.CreateCounter( - name: "plugin_test_calls", - unit: "int", - description: "just to test the counter", - tags: DiagnosticsTags - ); - } - } + [Fact] + public void can_receive_metrics_from_plugin() { + // Arrange + IPlugableComponent plugin = new AdamSmasherPlugin(diagnosticsTags: new KeyValuePair("test_name", "can_receive_metrics_from_plugin")); + + var builder = WebApplication.CreateBuilder(); + + plugin.ConfigureServices(builder.Services, builder.Configuration); + + using var app = builder.Build(); + + plugin.Configure(app); + + using var collector = new MetricCollector( + app.Services.GetRequiredService(), + plugin.DiagnosticsName, + ((AdamSmasherPlugin)plugin).TestCounter.Name + ); + + // Act + ((AdamSmasherPlugin)plugin).TestCounter.Add(1, plugin.DiagnosticsTags); // we also need to add then here? ffs... they should propagate from the meter... + + // Assert + var collectedMeasurement = collector.GetMeasurementSnapshot().Should().ContainSingle().Which; + + collectedMeasurement.Value.Should().Be(1); + + collectedMeasurement.Tags.Should().BeEquivalentTo(plugin.DiagnosticsTags); + } + + class AdamSmasherPlugin(params KeyValuePair[] diagnosticsTags) : Plugin(diagnosticsTags: diagnosticsTags) { + public Counter TestCounter { get; private set; } = null!; + + protected override void ConfigureApplication(IApplicationBuilder app, IConfiguration configuration) { + var meterFactory = app.ApplicationServices.GetRequiredService(); + + var meter = meterFactory.Create(DiagnosticsName, Version, DiagnosticsTags); + + TestCounter = meter.CreateCounter( + "plugin_test_calls", + "int", + "just to test the counter", + DiagnosticsTags + ); + } + } } \ No newline at end of file diff --git a/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs b/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs index 2b91c02..34321f8 100644 --- a/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs +++ b/test/EventStore.Plugins.Tests/Licensing/LicenseTests.cs @@ -4,50 +4,50 @@ 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); - } + 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(); + [Fact] + public async Task can_create_and_validate_license() { + var (publicKey, privateKey) = CreateKeyPair(); - var license = await License.CreateAsync(publicKey, privateKey, new Dictionary { - { "foo", "bar" } - }); + var license = await License.CreateAsync(publicKey, privateKey, new Dictionary { + { "foo", "bar" } + }); // check repeatedly because of https://github.com/dotnet/runtime/issues/43087 (await license.IsValidAsync(publicKey)).Should().BeTrue(); (await license.IsValidAsync(publicKey)).Should().BeTrue(); (await license.IsValidAsync(publicKey)).Should().BeTrue(); - license.Token.Claims.First(c => c.Type == "foo").Value.Should().Be("bar"); - } + license.Token.Claims.First(c => c.Type == "foo").Value.Should().Be("bar"); + } - [Fact] - public async Task detects_incorrect_public_key() { - var (publicKey, privateKey) = CreateKeyPair(); - var (publicKey2, _) = CreateKeyPair(); + [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" } - }); + var license = await License.CreateAsync(publicKey, privateKey, new Dictionary { + { "foo", "bar" } + }); (await license.IsValidAsync(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"); - } + } + + [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"); + } } \ No newline at end of file diff --git a/test/EventStore.Plugins.Tests/PluginBaseTests.cs b/test/EventStore.Plugins.Tests/PluginBaseTests.cs index 6bd739f..375d179 100644 --- a/test/EventStore.Plugins.Tests/PluginBaseTests.cs +++ b/test/EventStore.Plugins.Tests/PluginBaseTests.cs @@ -10,138 +10,138 @@ namespace EventStore.Plugins.Tests; public class PluginBaseTests { - [Fact] - public void plugin_base_sets_defaults_automatically() { - var expectedOptions = new PluginOptions { - Name = "NightCity", - Version = "1.0.0.0", - DiagnosticsName = "NightCity" - }; - - using var plugin = new NightCityPlugin(); - - plugin.Options.Should().BeEquivalentTo(expectedOptions); - } - - [Fact] - public void subsystems_plugin_base_sets_defaults_automatically() { - var expectedOptions = new SubsystemsPluginOptions { - Name = "PhantomLiberty", - Version = "1.0.0.0", - DiagnosticsName = "PhantomLiberty", - CommandLineName = "phantom-liberty" - }; - - using var plugin = new PhantomLibertySubsystemsPlugin(); - - plugin.Options.Should().BeEquivalentTo(expectedOptions); - } - - [Fact] - public void comercial_plugin_is_disabled_when_licence_is_missing() { - // Arrange - IPlugableComponent plugin = new NightCityPlugin(new() { - LicensePublicKey = "valid-public-key" - }); - - var builder = WebApplication.CreateBuilder(); - - plugin.ConfigureServices(builder.Services, EmptyConfiguration); - - using var app = builder.Build(); - - Action configure = () => plugin.Configure(app); - - // Act & Assert - configure.Should().Throw().Which - .PluginName.Should().Be(plugin.Name); - } - - [Fact] - public void comercial_plugin_is_disabled_when_licence_is_invalid() { - // Arrange - var (license, _) = CreateLicense(); - var (_, invalidPublicKey) = CreateLicense(); - - IPlugableComponent plugin = new NightCityPlugin(new() { - LicensePublicKey = invalidPublicKey - }); - - var builder = WebApplication.CreateBuilder(); - - builder.Services.AddSingleton(license); - - plugin.ConfigureServices(builder.Services, EmptyConfiguration); - - using var app = builder.Build(); - - Action configure = () => plugin.Configure(app); - - // Act & Assert - configure.Should().Throw().Which - .PluginName.Should().Be(plugin.Name); - } - - [Fact] - public void comercial_plugin_is_enabled_when_licence_is_present() { - // Arrange - var (license, publicKey) = CreateLicense(); - - IPlugableComponent plugin = new NightCityPlugin(new() { - LicensePublicKey = publicKey - }); - - var builder = WebApplication.CreateBuilder(); - - builder.Services.AddSingleton(license); - - plugin.ConfigureServices(builder.Services, builder.Configuration); - - using var app = builder.Build(); - - Action configure = () => plugin.Configure(app); - - // Act & Assert - configure.Should().NotThrow(); - } - - static (License License, string PublicKey) CreateLicense(Dictionary? claims = null) { - using var rsa = RSA.Create(1024); - - var publicKey = ToBase64String(rsa.ExportRSAPublicKey()); - var privateKey = ToBase64String(rsa.ExportRSAPrivateKey()); - - return (License.Create(publicKey, privateKey, claims), publicKey); - } - - static readonly IConfiguration EmptyConfiguration = new ConfigurationBuilder().AddInMemoryCollection().Build(); - - class NightCityPlugin : Plugin { - public NightCityPlugin(PluginOptions options) : base(options) { - Options = options with { - Name = Name, - Version = Version, - DiagnosticsName = DiagnosticsName, - }; - } - - public NightCityPlugin() : this(new()) { } - - public PluginOptions Options { get; } - } - - class PhantomLibertySubsystemsPlugin : SubsystemsPlugin { - public PhantomLibertySubsystemsPlugin(SubsystemsPluginOptions options) : base(options) { - Options = options with { - Name = Name, - Version = Version, - DiagnosticsName = DiagnosticsName, - CommandLineName = CommandLineName - }; - } - - public PhantomLibertySubsystemsPlugin() : this(new()) { } - - public SubsystemsPluginOptions Options { get; } - } + [Fact] + public void plugin_base_sets_defaults_automatically() { + var expectedOptions = new PluginOptions { + Name = "NightCity", + Version = "1.0.0.0", + DiagnosticsName = "NightCity" + }; + + using var plugin = new NightCityPlugin(); + + plugin.Options.Should().BeEquivalentTo(expectedOptions); + } + + [Fact] + public void subsystems_plugin_base_sets_defaults_automatically() { + var expectedOptions = new SubsystemsPluginOptions { + Name = "PhantomLiberty", + Version = "1.0.0.0", + DiagnosticsName = "PhantomLiberty", + CommandLineName = "phantom-liberty" + }; + + using var plugin = new PhantomLibertySubsystemsPlugin(); + + plugin.Options.Should().BeEquivalentTo(expectedOptions); + } + + [Fact] + public void comercial_plugin_is_disabled_when_licence_is_missing() { + // Arrange + IPlugableComponent plugin = new NightCityPlugin(new() { + LicensePublicKey = "valid-public-key" + }); + + var builder = WebApplication.CreateBuilder(); + + plugin.ConfigureServices(builder.Services, EmptyConfiguration); + + using var app = builder.Build(); + + Action configure = () => plugin.Configure(app); + + // Act & Assert + configure.Should().Throw().Which + .PluginName.Should().Be(plugin.Name); + } + + [Fact] + public void comercial_plugin_is_disabled_when_licence_is_invalid() { + // Arrange + var (license, _) = CreateLicense(); + var (_, invalidPublicKey) = CreateLicense(); + + IPlugableComponent plugin = new NightCityPlugin(new() { + LicensePublicKey = invalidPublicKey + }); + + var builder = WebApplication.CreateBuilder(); + + builder.Services.AddSingleton(license); + + plugin.ConfigureServices(builder.Services, EmptyConfiguration); + + using var app = builder.Build(); + + Action configure = () => plugin.Configure(app); + + // Act & Assert + configure.Should().Throw().Which + .PluginName.Should().Be(plugin.Name); + } + + [Fact] + public void comercial_plugin_is_enabled_when_licence_is_present() { + // Arrange + var (license, publicKey) = CreateLicense(); + + IPlugableComponent plugin = new NightCityPlugin(new() { + LicensePublicKey = publicKey + }); + + var builder = WebApplication.CreateBuilder(); + + builder.Services.AddSingleton(license); + + plugin.ConfigureServices(builder.Services, builder.Configuration); + + using var app = builder.Build(); + + Action configure = () => plugin.Configure(app); + + // Act & Assert + configure.Should().NotThrow(); + } + + static (License License, string PublicKey) CreateLicense(Dictionary? claims = null) { + using var rsa = RSA.Create(1024); + + var publicKey = ToBase64String(rsa.ExportRSAPublicKey()); + var privateKey = ToBase64String(rsa.ExportRSAPrivateKey()); + + return (License.Create(publicKey, privateKey, claims), publicKey); + } + + static readonly IConfiguration EmptyConfiguration = new ConfigurationBuilder().AddInMemoryCollection().Build(); + + class NightCityPlugin : Plugin { + public NightCityPlugin(PluginOptions options) : base(options) { + Options = options with { + Name = Name, + Version = Version, + DiagnosticsName = DiagnosticsName + }; + } + + public NightCityPlugin() : this(new()) { } + + public PluginOptions Options { get; } + } + + class PhantomLibertySubsystemsPlugin : SubsystemsPlugin { + public PhantomLibertySubsystemsPlugin(SubsystemsPluginOptions options) : base(options) { + Options = options with { + Name = Name, + Version = Version, + DiagnosticsName = DiagnosticsName, + CommandLineName = CommandLineName + }; + } + + public PhantomLibertySubsystemsPlugin() : this(new()) { } + + public SubsystemsPluginOptions Options { get; } + } } \ No newline at end of file