From 6b5ca9e49e33eb3e03d6f7333661da7e6d0546fa Mon Sep 17 00:00:00 2001 From: vnugent Date: Sat, 25 Mar 2023 14:25:14 -0400 Subject: Defer cors to host/middleware/user code --- .../src/Accounts/AccountUtils.cs | 47 +++++++++-- .../src/Endpoints/ProtectionSettings.cs | 43 +--------- .../src/Endpoints/ResourceEndpointBase.cs | 15 ---- lib/Plugins.Essentials/src/EventProcessor.cs | 2 +- lib/Plugins.Essentials/src/FileProcessArgs.cs | 80 +++--------------- lib/Plugins.Essentials/src/TimestampedCounter.cs | 95 ++++++++++------------ 6 files changed, 96 insertions(+), 186 deletions(-) (limited to 'lib/Plugins.Essentials') diff --git a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs index 75c3388..13cff7b 100644 --- a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs +++ b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs @@ -308,7 +308,7 @@ namespace VNLib.Plugins.Essentials.Accounts IClientAuthorization auth = provider.AuthorizeClient(entity, secInfo, user); //Clear flags - user.FailedLoginCount(0); + user.ClearFailedLoginCount(); //Store variables entity.Session.UserID = user.UserID; @@ -526,20 +526,42 @@ namespace VNLib.Plugins.Essentials.Accounts public static TimestampedCounter FailedLoginCount(this IUser user) { ulong value = user.GetValueType(FAILED_LOGIN_ENTRY); - return (TimestampedCounter)value; + return TimestampedCounter.FromUInt64(value); } + + /// + /// Clears any pending flc count. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ClearFailedLoginCount(this IUser user) + { + //Cast the counter to a ulong and store as a ulong + user.SetValueType(FAILED_LOGIN_ENTRY, (ulong)0); + } + /// /// Sets the number of failed login attempts for the current session /// /// + /// Explicitly sets the time of the internal counter /// The value to set the failed login attempt count [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void FailedLoginCount(this IUser user, uint value) + public static void FailedLoginCount(this IUser user, uint value, DateTimeOffset time) { - TimestampedCounter counter = new(value); + TimestampedCounter counter = TimestampedCounter.FromValues(value, time); //Cast the counter to a ulong and store as a ulong - user.SetValueType(FAILED_LOGIN_ENTRY, (ulong)counter); + user.SetValueType(FAILED_LOGIN_ENTRY, counter.ToUInt64()); } + + /// + /// Sets the number of failed login attempts for the current session + /// + /// + /// The value to set the failed login attempt count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FailedLoginCount(this IUser user, uint value) => FailedLoginCount(user, value, DateTimeOffset.UtcNow); + /// /// Sets the number of failed login attempts for the current session /// @@ -549,17 +571,26 @@ namespace VNLib.Plugins.Essentials.Accounts public static void FailedLoginCount(this IUser user, TimestampedCounter value) { //Cast the counter to a ulong and store as a ulong - user.SetValueType(FAILED_LOGIN_ENTRY, (ulong)value); + user.SetValueType(FAILED_LOGIN_ENTRY, value.ToUInt64()); } + + /// + /// Increments the failed login attempt count + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FailedLoginIncrement(this IUser user) => FailedLoginIncrement(user, DateTimeOffset.UtcNow); + /// /// Increments the failed login attempt count /// /// + /// Explicitly set the time of the counter [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void FailedLoginIncrement(this IUser user) + public static void FailedLoginIncrement(this IUser user, DateTimeOffset time) { TimestampedCounter current = user.FailedLoginCount(); - user.FailedLoginCount(current.Count + 1); + user.FailedLoginCount(current.Count + 1, time); } #endregion diff --git a/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs b/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs index 77620ac..7e1e394 100644 --- a/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs +++ b/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -31,7 +31,7 @@ namespace VNLib.Plugins.Essentials.Endpoints /// for connection pre-checks. Settings are the most /// strict by default /// - public readonly struct ProtectionSettings : IEquatable + public readonly record struct ProtectionSettings { /// /// Requires TLS be enabled for all incomming requets (or loopback adapter) @@ -44,12 +44,6 @@ namespace VNLib.Plugins.Essentials.Endpoints /// public readonly bool DisableSessionsRequired { get; init; } - /// - /// Allows connections that define cross-site sec headers - /// to be processed or denied (denied by default) - /// - public readonly bool DisableCrossSiteDenied { get; init; } - /// /// Enables referr match protection. Requires that if a referer header is /// set that it matches the current origin @@ -63,41 +57,10 @@ namespace VNLib.Plugins.Essentials.Endpoints /// public readonly bool DisableBrowsersOnly { get; init; } - /// - /// If the connection has a valid session, verifies that the - /// stored session origin matches the client's origin header. - /// (confirms the session is coming from the same origin it - /// was created on) - /// - public readonly bool DisableVerifySessionCors { get; init; } - /// /// Disables response caching, by setting the cache control headers appropriatly. /// Default is disabled /// - public readonly bool EnableCaching { get; init; } - - - /// - public override bool Equals(object obj) => obj is ProtectionSettings settings && Equals(settings); - /// - public override int GetHashCode() => base.GetHashCode(); - - /// - public static bool operator ==(ProtectionSettings left, ProtectionSettings right) => left.Equals(right); - /// - public static bool operator !=(ProtectionSettings left, ProtectionSettings right) => !(left == right); - - /// - public bool Equals(ProtectionSettings other) - { - return DisabledTlsRequired == other.DisabledTlsRequired && - DisableSessionsRequired == other.DisableSessionsRequired && - DisableCrossSiteDenied == other.DisableCrossSiteDenied && - DisableRefererMatch == other.DisableRefererMatch && - DisableBrowsersOnly == other.DisableBrowsersOnly && - DisableVerifySessionCors == other.DisableVerifySessionCors && - EnableCaching == other.EnableCaching; - } + public readonly bool EnableCaching { get; init; } } } diff --git a/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs b/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs index 4af3c30..7411789 100644 --- a/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs +++ b/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs @@ -174,21 +174,6 @@ namespace VNLib.Plugins.Essentials.Endpoints return false; } - /* - * If sessions are required, verify cors is set, and the client supplied an origin header, - * verify that it matches the origin that was specified during session initialization - */ - if ((!EndpointProtectionSettings.DisableSessionsRequired & !EndpointProtectionSettings.DisableVerifySessionCors) && entity.Server.Origin != null && !entity.Session.CrossOriginMatch) - { - return false; - } - - //Enforce cross-site - if (!EndpointProtectionSettings.DisableCrossSiteDenied && entity.Server.IsCrossSite()) - { - return false; - } - return true; } diff --git a/lib/Plugins.Essentials/src/EventProcessor.cs b/lib/Plugins.Essentials/src/EventProcessor.cs index ccaa1a1..820af30 100644 --- a/lib/Plugins.Essentials/src/EventProcessor.cs +++ b/lib/Plugins.Essentials/src/EventProcessor.cs @@ -513,7 +513,7 @@ namespace VNLib.Plugins.Essentials //See if the last modifed header was set DateTimeOffset? ifModifedSince = entity.Server.LastModified(); //If the header was set, check the date, if the file has been modified since, continue sending the file - if (ifModifedSince != null && ifModifedSince.Value > fileLastModified) + if (ifModifedSince.HasValue && ifModifedSince.Value > fileLastModified) { //File has not been modified entity.CloseResponse(HttpStatusCode.NotModified); diff --git a/lib/Plugins.Essentials/src/FileProcessArgs.cs b/lib/Plugins.Essentials/src/FileProcessArgs.cs index dae695b..5ed4667 100644 --- a/lib/Plugins.Essentials/src/FileProcessArgs.cs +++ b/lib/Plugins.Essentials/src/FileProcessArgs.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -25,6 +25,8 @@ using System; using System.Net; +#nullable enable + namespace VNLib.Plugins.Essentials { /// @@ -69,7 +71,13 @@ namespace VNLib.Plugins.Essentials /// /// Specifies operations the file processor will follow during request handling /// - public readonly struct FileProcessArgs : IEquatable + /// + /// The routine the file processor should execute + /// + /// + /// An optional alternate path for the given routine + /// + public readonly record struct FileProcessArgs(FpRoutine Routine, string Alternate) { /// /// Signals the file processor should complete with a routine @@ -91,79 +99,15 @@ namespace VNLib.Plugins.Essentials /// Signals the file processor should not process the connection /// public static readonly FileProcessArgs VirtualSkip = new (FpRoutine.VirtualSkip); - /// - /// The routine the file processor should execute - /// - public readonly FpRoutine Routine { get; init; } - /// - /// An optional alternate path for the given routine - /// - public readonly string Alternate { get; init; } + /// /// Initializes a new with the specified routine /// and empty path /// /// The file processing routine to execute - public FileProcessArgs(FpRoutine routine) - { - this.Routine = routine; - this.Alternate = string.Empty; - } - /// - /// Initializes a new with the specified routine - /// and alternate path - /// - /// - /// - public FileProcessArgs(FpRoutine routine, string alternatePath) - { - this.Routine = routine; - this.Alternate = alternatePath; - } - /// - /// - /// - /// - /// - /// - public static bool operator == (FileProcessArgs arg1, FileProcessArgs arg2) - { - return arg1.Equals(arg2); - } - /// - /// - /// - /// - /// - /// - public static bool operator != (FileProcessArgs arg1, FileProcessArgs arg2) - { - return !arg1.Equals(arg2); - } - /// - public bool Equals(FileProcessArgs other) - { - //make sure the routine types match - if (Routine != other.Routine) - { - return false; - } - //Next make sure the hashcodes of the alternate paths match - return (Alternate?.GetHashCode(StringComparison.OrdinalIgnoreCase)) == (other.Alternate?.GetHashCode(StringComparison.OrdinalIgnoreCase)); - } - /// - public override bool Equals(object obj) - { - return obj is FileProcessArgs args && Equals(args); - } - /// - /// - /// - /// - public override int GetHashCode() + public FileProcessArgs(FpRoutine routine):this(routine, string.Empty) { - return base.GetHashCode(); } } } \ No newline at end of file diff --git a/lib/Plugins.Essentials/src/TimestampedCounter.cs b/lib/Plugins.Essentials/src/TimestampedCounter.cs index 19cb8ec..b2ad70c 100644 --- a/lib/Plugins.Essentials/src/TimestampedCounter.cs +++ b/lib/Plugins.Essentials/src/TimestampedCounter.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -24,78 +24,36 @@ using System; - -#nullable enable - namespace VNLib.Plugins.Essentials { + /// /// Stucture that allows for convient storage of a counter value /// and a second precision timestamp into a 64-bit unsigned integer /// - public readonly struct TimestampedCounter : IEquatable + public readonly record struct TimestampedCounter(uint Count, uint UnixMs) { /// /// The time the count was last modifed /// - public readonly DateTimeOffset LastModified; - /// - /// The last failed login attempt count value - /// - public readonly uint Count; - - /// - /// Initalizes a new flc structure with the current UTC date - /// and the specified count value - /// - /// FLC current count - public TimestampedCounter(uint count) : this(DateTimeOffset.UtcNow, count) - { } - - private TimestampedCounter(DateTimeOffset dto, uint count) - { - Count = count; - LastModified = dto; - } - - /// - /// Compacts and converts the counter value and timestamp into - /// a 64bit unsigned integer - /// - /// The counter to convert - public static explicit operator ulong(TimestampedCounter count) => count.ToUInt64(); + public readonly DateTimeOffset LastModified => DateTimeOffset.FromUnixTimeSeconds(UnixMs); /// /// Compacts and converts the counter value and timestamp into /// a 64bit unsigned integer /// /// The uint64 compacted value - public ulong ToUInt64() + public readonly ulong ToUInt64() { //Upper 32 bits time, lower 32 bits count - ulong value = (ulong)LastModified.ToUnixTimeSeconds() << 32; + ulong value = UnixMs; + //Lshift to upper32 + value <<= 32; + //Set count as lower32 value |= Count; return value; } - /// - /// The previously compacted - /// value to cast back to a counter - /// - /// - public static explicit operator TimestampedCounter(ulong value) => FromUInt64(value); - - /// - public override bool Equals(object? obj) => obj is TimestampedCounter counter && Equals(counter); - /// - public override int GetHashCode() => this.ToUInt64().GetHashCode(); - /// - public static bool operator ==(TimestampedCounter left, TimestampedCounter right) => left.Equals(right); - /// - public static bool operator !=(TimestampedCounter left, TimestampedCounter right) => !(left == right); - /// - public bool Equals(TimestampedCounter other) => ToUInt64() == other.ToUInt64(); - /// /// The previously compacted /// value to cast back to a counter @@ -108,10 +66,39 @@ namespace VNLib.Plugins.Essentials public static TimestampedCounter FromUInt64(ulong value) { //Upper 32 bits time, lower 32 bits count - long time = (long)(value >> 32); + uint time = (uint)(value >> 32); uint count = (uint)(value & uint.MaxValue); - //Init dto struct - return new(DateTimeOffset.FromUnixTimeSeconds(time), count); + + return new TimestampedCounter(count, time); } + + /// + /// Creates a new from the given counter + /// value and the unix ms value + /// + /// + /// The internal time to store in the counter + /// An initialized + /// + public static TimestampedCounter FromValues(uint count, DateTimeOffset time) + { + //The time in seconds truncated to a uint32 + uint sec = Convert.ToUInt32(time.ToUnixTimeSeconds()); + return new TimestampedCounter(count, sec); + } + + /// + /// The previously compacted + /// value to cast back to a counter + /// + /// + public static explicit operator TimestampedCounter(ulong value) => FromUInt64(value); + + /// + /// Compacts and converts the counter value and timestamp into + /// a 64bit unsigned integer + /// + /// The counter to convert + public static explicit operator ulong(TimestampedCounter count) => count.ToUInt64(); } } \ No newline at end of file -- cgit