Previously we've used one semaphore per all ongoing authentication attempts, which is suboptimal given the existence of a lot of consumers, including ongoing (D)DoS or distributed bruteforce attack. ASF should be as resistant to that as possible, therefore it makes sense to replace the global semaphore with per-IP semaphore (actually task), that can control the access just as well, without stopping other consumers from accessing the same authentication process concurrently.
We can favour bruteforcers by checking first if the client is even eligible for talking with us, this will (in a very negligible way) improve defense against common DoS.
Also rewrite Timer initialization while at it. This is internal class and we don't expect this middleware to be initialized more than once anyway.
> This call site is reachable on: 'FreeBSD', 'Linux', 'MacOS'. 'OS.UnixSetFileAccess(string, OS.EUnixPermission)' is only supported on: 'Linux', 'FreeBSD', 'OSX'.
Might result in something along:
2021-07-30 16:39:43|ArchiSteamFarm-6766|ERROR|Microsoft.AspNetCore.Server.Kestrel|Connection id "0HMAJF2E5IVHB", Request id "0HMAJF2E5IVHB:00000005": An unhandled exception was thrown by the application. System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.Flush()
at Microsoft.AspNetCore.ResponseCaching.ResponseCachingStream.Flush()
at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionBody.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.StreamWriter.Close()
at Newtonsoft.Json.JsonTextWriter.CloseBufferAndWriter()
at Newtonsoft.Json.JsonTextWriter.Close()
at Newtonsoft.Json.JsonWriter.Dispose(Boolean disposing)
at Newtonsoft.Json.JsonWriter.System.IDisposable.Dispose()
at ArchiSteamFarm.IPC.WebUtilities.WriteJsonAsync[TValue](HttpResponse response, TValue value, JsonSerializerSettings jsonSerializerSettings)
at ArchiSteamFarm.IPC.WebUtilities.WriteJsonAsync[TValue](HttpResponse response, TValue value, JsonSerializerSettings jsonSerializerSettings)
at ArchiSteamFarm.IPC.Integration.ApiAuthenticationMiddleware.InvokeAsync(HttpContext context, IOptions`1 jsonOptions)
at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
While AutoRestart property in the config is a hint for ASF what it should be doing, --no-restart cmd-line argument is used in scripts and environments that must directly monitor the process, e.g. Docker. In such environments, we should refuse a call to Restart() action, as it's never feasible.