diff --git a/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs index ffcb1372b..2294ab425 100644 --- a/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs +++ b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs @@ -19,6 +19,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#if NETFRAMEWORK +using JustArchiNET.Madness; +#endif using System; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; @@ -45,7 +48,7 @@ namespace ArchiSteamFarm.IPC.Integration { private const byte FailedAuthorizationsCooldownInHours = 1; private const byte MaxFailedAuthorizationAttempts = 5; - private static readonly SemaphoreSlim AuthorizationSemaphore = new(1, 1); + private static readonly ConcurrentDictionary AuthorizationTasks = new(); private static readonly Timer ClearFailedAuthorizationsTimer = new(ClearFailedAuthorizations); private static readonly ConcurrentDictionary FailedAuthorizations = new(); @@ -150,23 +153,37 @@ namespace ArchiSteamFarm.IPC.Integration { bool authorized = ipcPassword == inputHash; - await AuthorizationSemaphore.WaitAsync().ConfigureAwait(false); + while (true) { + if (AuthorizationTasks.TryGetValue(clientIP, out Task? task)) { + await task.ConfigureAwait(false); - try { - bool hasFailedAuthorizations = FailedAuthorizations.TryGetValue(clientIP, out attempts); - - if (hasFailedAuthorizations && (attempts >= MaxFailedAuthorizationAttempts)) { - return (HttpStatusCode.Forbidden, false); + continue; } - if (!authorized) { - FailedAuthorizations[clientIP] = hasFailedAuthorizations ? ++attempts : (byte) 1; + TaskCompletionSource taskCompletionSource = new(); + + if (!AuthorizationTasks.TryAdd(clientIP, taskCompletionSource.Task)) { + continue; } - } finally { - AuthorizationSemaphore.Release(); + + try { + bool hasFailedAuthorizations = FailedAuthorizations.TryGetValue(clientIP, out attempts); + + if (hasFailedAuthorizations && (attempts >= MaxFailedAuthorizationAttempts)) { + return (HttpStatusCode.Forbidden, false); + } + + if (!authorized) { + FailedAuthorizations[clientIP] = hasFailedAuthorizations ? ++attempts : (byte) 1; + } + } finally { + AuthorizationTasks.TryRemove(clientIP, out _); + + taskCompletionSource.SetResult(); + } + + return (authorized ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, true); } - - return (authorized ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, true); } } } diff --git a/Directory.Packages.props b/Directory.Packages.props index 7e367c219..fae34d307 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -29,7 +29,7 @@ - +