diff options
author | vnugent <public@vaughnnugent.com> | 2023-03-25 14:25:14 -0400 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-03-25 14:25:14 -0400 |
commit | 6b5ca9e49e33eb3e03d6f7333661da7e6d0546fa (patch) | |
tree | 8a389e9097c256b28cac8f268b93b2101d6a4cba /lib/Plugins.Essentials | |
parent | d066a3d7ec26fd6919c514aeaccc4d6b086dc9c7 (diff) |
Defer cors to host/middleware/user code
Diffstat (limited to 'lib/Plugins.Essentials')
6 files changed, 96 insertions, 186 deletions
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<string, ulong>(FAILED_LOGIN_ENTRY); - return (TimestampedCounter)value; + return TimestampedCounter.FromUInt64(value); } + + /// <summary> + /// Clears any pending flc count. + /// </summary> + /// <param name="user"></param> + [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); + } + /// <summary> /// Sets the number of failed login attempts for the current session /// </summary> /// <param name="user"></param> + /// <param name="time">Explicitly sets the time of the internal counter</param> /// <param name="value">The value to set the failed login attempt count</param> [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()); } + + /// <summary> + /// Sets the number of failed login attempts for the current session + /// </summary> + /// <param name="user"></param> + /// <param name="value">The value to set the failed login attempt count</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FailedLoginCount(this IUser user, uint value) => FailedLoginCount(user, value, DateTimeOffset.UtcNow); + /// <summary> /// Sets the number of failed login attempts for the current session /// </summary> @@ -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()); } + + /// <summary> + /// Increments the failed login attempt count + /// </summary> + /// <param name="user"></param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FailedLoginIncrement(this IUser user) => FailedLoginIncrement(user, DateTimeOffset.UtcNow); + /// <summary> /// Increments the failed login attempt count /// </summary> /// <param name="user"></param> + /// <param name="time">Explicitly set the time of the counter</param> [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 /// </summary> - public readonly struct ProtectionSettings : IEquatable<ProtectionSettings> + public readonly record struct ProtectionSettings { /// <summary> /// Requires TLS be enabled for all incomming requets (or loopback adapter) @@ -45,12 +45,6 @@ namespace VNLib.Plugins.Essentials.Endpoints public readonly bool DisableSessionsRequired { get; init; } /// <summary> - /// Allows connections that define cross-site sec headers - /// to be processed or denied (denied by default) - /// </summary> - public readonly bool DisableCrossSiteDenied { get; init; } - - /// <summary> /// Enables referr match protection. Requires that if a referer header is /// set that it matches the current origin /// </summary> @@ -64,40 +58,9 @@ namespace VNLib.Plugins.Essentials.Endpoints public readonly bool DisableBrowsersOnly { get; init; } /// <summary> - /// 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) - /// </summary> - public readonly bool DisableVerifySessionCors { get; init; } - - /// <summary> /// Disables response caching, by setting the cache control headers appropriatly. /// Default is disabled /// </summary> - public readonly bool EnableCaching { get; init; } - - - ///<inheritdoc/> - public override bool Equals(object obj) => obj is ProtectionSettings settings && Equals(settings); - ///<inheritdoc/> - public override int GetHashCode() => base.GetHashCode(); - - ///<inheritdoc/> - public static bool operator ==(ProtectionSettings left, ProtectionSettings right) => left.Equals(right); - ///<inheritdoc/> - public static bool operator !=(ProtectionSettings left, ProtectionSettings right) => !(left == right); - - ///<inheritdoc/> - 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 { /// <summary> @@ -69,7 +71,13 @@ namespace VNLib.Plugins.Essentials /// <summary> /// Specifies operations the file processor will follow during request handling /// </summary> - public readonly struct FileProcessArgs : IEquatable<FileProcessArgs> + /// <param name="Alternate"> + /// The routine the file processor should execute + /// </param> + /// <param name="Routine"> + /// An optional alternate path for the given routine + /// </param> + public readonly record struct FileProcessArgs(FpRoutine Routine, string Alternate) { /// <summary> /// Signals the file processor should complete with a <see cref="FpRoutine.Deny"/> routine @@ -91,79 +99,15 @@ namespace VNLib.Plugins.Essentials /// Signals the file processor should not process the connection /// </summary> public static readonly FileProcessArgs VirtualSkip = new (FpRoutine.VirtualSkip); - /// <summary> - /// The routine the file processor should execute - /// </summary> - public readonly FpRoutine Routine { get; init; } - /// <summary> - /// An optional alternate path for the given routine - /// </summary> - public readonly string Alternate { get; init; } + /// <summary> /// Initializes a new <see cref="FileProcessArgs"/> with the specified routine /// and empty <see cref="Alternate"/> path /// </summary> /// <param name="routine">The file processing routine to execute</param> - public FileProcessArgs(FpRoutine routine) - { - this.Routine = routine; - this.Alternate = string.Empty; - } - /// <summary> - /// Initializes a new <see cref="FileProcessArgs"/> with the specified routine - /// and alternate path - /// </summary> - /// <param name="routine"></param> - /// <param name="alternatePath"></param> - public FileProcessArgs(FpRoutine routine, string alternatePath) - { - this.Routine = routine; - this.Alternate = alternatePath; - } - /// <summary> - /// - /// </summary> - /// <param name="arg1"></param> - /// <param name="arg2"></param> - /// <returns></returns> - public static bool operator == (FileProcessArgs arg1, FileProcessArgs arg2) - { - return arg1.Equals(arg2); - } - /// <summary> - /// - /// </summary> - /// <param name="arg1"></param> - /// <param name="arg2"></param> - /// <returns></returns> - public static bool operator != (FileProcessArgs arg1, FileProcessArgs arg2) - { - return !arg1.Equals(arg2); - } - ///<inheritdoc/> - 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)); - } - ///<inheritdoc/> - public override bool Equals(object obj) - { - return obj is FileProcessArgs args && Equals(args); - } - /// <summary> - /// <inheritdoc/> - /// </summary> - /// <returns></returns> - 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,56 +24,32 @@ using System; - -#nullable enable - namespace VNLib.Plugins.Essentials { + /// <summary> /// Stucture that allows for convient storage of a counter value /// and a second precision timestamp into a 64-bit unsigned integer /// </summary> - public readonly struct TimestampedCounter : IEquatable<TimestampedCounter> + public readonly record struct TimestampedCounter(uint Count, uint UnixMs) { /// <summary> /// The time the count was last modifed /// </summary> - public readonly DateTimeOffset LastModified; - /// <summary> - /// The last failed login attempt count value - /// </summary> - public readonly uint Count; - - /// <summary> - /// Initalizes a new flc structure with the current UTC date - /// and the specified count value - /// </summary> - /// <param name="count">FLC current count</param> - public TimestampedCounter(uint count) : this(DateTimeOffset.UtcNow, count) - { } - - private TimestampedCounter(DateTimeOffset dto, uint count) - { - Count = count; - LastModified = dto; - } - - /// <summary> - /// Compacts and converts the counter value and timestamp into - /// a 64bit unsigned integer - /// </summary> - /// <param name="count">The counter to convert</param> - public static explicit operator ulong(TimestampedCounter count) => count.ToUInt64(); + public readonly DateTimeOffset LastModified => DateTimeOffset.FromUnixTimeSeconds(UnixMs); /// <summary> /// Compacts and converts the counter value and timestamp into /// a 64bit unsigned integer /// </summary> /// <returns>The uint64 compacted value</returns> - 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; } @@ -82,24 +58,6 @@ namespace VNLib.Plugins.Essentials /// The previously compacted <see cref="TimestampedCounter"/> /// value to cast back to a counter /// </summary> - /// <param name="value"></param> - public static explicit operator TimestampedCounter(ulong value) => FromUInt64(value); - - ///<inheritdoc/> - public override bool Equals(object? obj) => obj is TimestampedCounter counter && Equals(counter); - ///<inheritdoc/> - public override int GetHashCode() => this.ToUInt64().GetHashCode(); - ///<inheritdoc/> - public static bool operator ==(TimestampedCounter left, TimestampedCounter right) => left.Equals(right); - ///<inheritdoc/> - public static bool operator !=(TimestampedCounter left, TimestampedCounter right) => !(left == right); - ///<inheritdoc/> - public bool Equals(TimestampedCounter other) => ToUInt64() == other.ToUInt64(); - - /// <summary> - /// The previously compacted <see cref="TimestampedCounter"/> - /// value to cast back to a counter - /// </summary> /// <param name="value">The uint64 encoded <see cref="TimestampedCounter"/></param> /// <returns> /// The decoded <see cref="TimestampedCounter"/> from its @@ -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); } + + /// <summary> + /// Creates a new <see cref="TimestampedCounter"/> from the given counter + /// value and the <see cref="DateTimeOffset"/> unix ms value + /// </summary> + /// <param name="count"></param> + /// <param name="time">The internal time to store in the counter</param> + /// <returns>An initialized <see cref="TimestampedCounter"/></returns> + /// <exception cref="StackOverflowException"></exception> + 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); + } + + /// <summary> + /// The previously compacted <see cref="TimestampedCounter"/> + /// value to cast back to a counter + /// </summary> + /// <param name="value"></param> + public static explicit operator TimestampedCounter(ulong value) => FromUInt64(value); + + /// <summary> + /// Compacts and converts the counter value and timestamp into + /// a 64bit unsigned integer + /// </summary> + /// <param name="count">The counter to convert</param> + public static explicit operator ulong(TimestampedCounter count) => count.ToUInt64(); } }
\ No newline at end of file |