diff --git a/WowsKarma.Api.Minimap.Client/WowsKarma.Api.Minimap.Client.csproj b/WowsKarma.Api.Minimap.Client/WowsKarma.Api.Minimap.Client.csproj index a5956b94..2b27fde3 100644 --- a/WowsKarma.Api.Minimap.Client/WowsKarma.Api.Minimap.Client.csproj +++ b/WowsKarma.Api.Minimap.Client/WowsKarma.Api.Minimap.Client.csproj @@ -18,7 +18,7 @@ - + diff --git a/WowsKarma.Api/Controllers/PostController.cs b/WowsKarma.Api/Controllers/PostController.cs index a2e601f2..6132962a 100644 --- a/WowsKarma.Api/Controllers/PostController.cs +++ b/WowsKarma.Api/Controllers/PostController.cs @@ -196,7 +196,7 @@ public IActionResult GetLatestPosts( /// Attached replay is invalid. /// Restrictions are in effect for one of the targeted accounts. /// One of the targeted accounts was not found. - [HttpPost, Authorize(RequireNoPlatformBans)] + [HttpPost, Authorize(RequireNoPlatformBans), UserAtomicLock] [ProducesResponseType(201), ProducesResponseType(400), ProducesResponseType(422), ProducesResponseType(typeof(string), 403), ProducesResponseType(typeof(string), 404)] public async Task CreatePost( [FromForm] string postDto, diff --git a/WowsKarma.Api/Infrastructure/Attributes/UserAtomicLockAttribute.cs b/WowsKarma.Api/Infrastructure/Attributes/UserAtomicLockAttribute.cs new file mode 100644 index 00000000..0d3a9147 --- /dev/null +++ b/WowsKarma.Api/Infrastructure/Attributes/UserAtomicLockAttribute.cs @@ -0,0 +1,10 @@ +namespace WowsKarma.Api.Infrastructure.Attributes; + +/// +/// Provides an attribute to lock concurrency on a given action to a given user. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] +public class UserAtomicLockAttribute : Attribute +{ + public UserAtomicLockAttribute() { } +} \ No newline at end of file diff --git a/WowsKarma.Api/Middlewares/UserAtomicLockMiddleware.cs b/WowsKarma.Api/Middlewares/UserAtomicLockMiddleware.cs new file mode 100644 index 00000000..0ccbd714 --- /dev/null +++ b/WowsKarma.Api/Middlewares/UserAtomicLockMiddleware.cs @@ -0,0 +1,64 @@ +using System.Collections.Concurrent; +using WowsKarma.Api.Infrastructure.Attributes; +using WowsKarma.Common; + +namespace WowsKarma.Api.Middlewares; + +/// +/// Provides a middleware to lock a given action to a given user. +/// +public class UserAtomicLockMiddleware : IMiddleware +{ + private static readonly ConcurrentDictionary, object> Locks = new(); + private static object ConcurrencyLock = new(); + + /// + public async Task InvokeAsync(HttpContext ctx, RequestDelegate next) + { + // Get the current user and endpoint + uint? uid = ctx.User.ToAccountListing()?.Id; + PathString path = ctx.Request.Path; + + if (uid is null) + { + // Pass through. + await next(ctx); + return; + } + + if (ctx.GetEndpoint()?.Metadata.GetMetadata() is null) + { + // Pass through. + await next(ctx); + return; + } + + bool lockExists; + // lock (ConcurrencyLock) + // { + lockExists = Locks.TryGetValue(new(path, uid.Value), out _) || !Locks.TryAdd(new(path, uid.Value), new()); + // } + + // Get or try to add the lock object. + if (lockExists) + { + // Lock is already taken. + ctx.Response.StatusCode = StatusCodes.Status429TooManyRequests; + return; + } + + // Hold the lock for the request's duration. + try + { + await next(ctx); + } + finally + { + // lock (ConcurrencyLock) + // { + // Release the lock. + Locks.TryRemove(new(path, uid.Value), out _); + // } + } + } +} \ No newline at end of file diff --git a/WowsKarma.Api/Startup.cs b/WowsKarma.Api/Startup.cs index 9046b89b..d240c8fa 100644 --- a/WowsKarma.Api/Startup.cs +++ b/WowsKarma.Api/Startup.cs @@ -10,7 +10,7 @@ using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Reflection; -using System.Text; +using System.Text; using Hangfire; using Hangfire.PostgreSql; using Hangfire.Tags.PostgreSql; @@ -280,6 +280,8 @@ public void ConfigureServices(IServiceCollection services) services.AddResiliencePolicies(); services.AddSystemd(); + + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -334,7 +336,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseAuthorization(); app.UseMiddleware(); - + app.UseMiddleware(); + app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); diff --git a/WowsKarma.Api/WowsKarma.Api.csproj b/WowsKarma.Api/WowsKarma.Api.csproj index 34295116..47d4d74f 100644 --- a/WowsKarma.Api/WowsKarma.Api.csproj +++ b/WowsKarma.Api/WowsKarma.Api.csproj @@ -6,7 +6,7 @@ enable enable - 0.17.4 + 0.17.4.1 Sakura Akeno Isayeki Nodsoft Systems WOWS Karma (API) @@ -28,32 +28,32 @@ - - + + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + diff --git a/WowsKarma.Api/appsettings.Development.json b/WowsKarma.Api/appsettings.Development.json index 847fdeef..47065016 100644 --- a/WowsKarma.Api/appsettings.Development.json +++ b/WowsKarma.Api/appsettings.Development.json @@ -12,22 +12,22 @@ "EU": { "CookieName": "Auth_EU", "CookieDomain": "localhost", - "WgAuthCallback": "http://localhost:5010/api/auth/wg-callback" + "WgAuthCallback": "https://localhost:5010/api/auth/wg-callback" }, "NA": { "CookieName": "Auth_NA", "CookieDomain": "localhost", - "WgAuthCallback": "http://localhost:5010/api/auth/wg-callback" + "WgAuthCallback": "https://localhost:5010/api/auth/wg-callback" }, "CIS": { "CookieName": "Auth_CIS", "CookieDomain": "localhost", - "WgAuthCallback": "http://localhost:5010/api/auth/wg-callback" + "WgAuthCallback": "https://localhost:5010/api/auth/wg-callback" }, "SEA": { "CookieName": "Auth_SEA", "CookieDomain": "localhost", - "WgAuthCallback": "http://localhost:5010/api/auth/wg-callback" + "WgAuthCallback": "https://localhost:5010/api/auth/wg-callback" } }, "Discord": { diff --git a/wowskarma.app/src/app/shared/layout/navbar/nav-auth/nav-auth.component.html b/wowskarma.app/src/app/shared/layout/navbar/nav-auth/nav-auth.component.html index dd5d2fbb..f64f27a6 100644 --- a/wowskarma.app/src/app/shared/layout/navbar/nav-auth/nav-auth.component.html +++ b/wowskarma.app/src/app/shared/layout/navbar/nav-auth/nav-auth.component.html @@ -1,18 +1,16 @@ diff --git a/wowskarma.app/src/app/shared/layout/navbar/navbar.component.html b/wowskarma.app/src/app/shared/layout/navbar/navbar.component.html index 77febda1..3d74f906 100644 --- a/wowskarma.app/src/app/shared/layout/navbar/navbar.component.html +++ b/wowskarma.app/src/app/shared/layout/navbar/navbar.component.html @@ -22,10 +22,10 @@