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 @@