Achievement race condition fix (#28)

This commit is contained in:
rpaciorek 2023-08-28 06:35:05 +00:00 committed by GitHub
parent e564a44b13
commit d0eacb75b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 60 deletions

View File

@ -0,0 +1,41 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using sodoff.Model;
using sodoff.Controllers.Common;
namespace sodoff.Attributes;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class VikingSession : Attribute, IAsyncActionFilter {
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {
DBContext ctx = ((AchievementController)context.Controller).ctx;
foreach (var a in context.ActionArguments.Keys) {
Console.WriteLine(a);
}
if (!context.HttpContext.Request.Form.ContainsKey("apiToken")) {
context.Result = new UnauthorizedObjectResult("Unauthorized") { StatusCode = 403 };
return;
}
Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == context.HttpContext.Request.Form["apiToken"].ToString());
if (session?.VikingId is null) {
context.Result = new UnauthorizedObjectResult("Unauthorized") { StatusCode = 403 };
return;
}
// NOTE: we can't refer to session.Viking here, because it may cause to ignore modifications from the threads we are waiting for
// we can use session.Viking only after vikingMutex.WaitOne()
Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + session.VikingId);
try {
vikingMutex.WaitOne();
context.ActionArguments["viking"] = session.Viking;
await next();
} finally {
vikingMutex.ReleaseMutex();
}
}
}

View File

@ -10,7 +10,7 @@ using sodoff.Util;
namespace sodoff.Controllers.Common; namespace sodoff.Controllers.Common;
public class AchievementController : Controller { public class AchievementController : Controller {
private readonly DBContext ctx; public readonly DBContext ctx;
private AchievementService achievementService; private AchievementService achievementService;
public AchievementController(DBContext ctx, AchievementService achievementService) { public AchievementController(DBContext ctx, AchievementService achievementService) {
this.ctx = ctx; this.ctx = ctx;
@ -138,14 +138,10 @@ public class AchievementController : Controller {
[Produces("application/xml")] [Produces("application/xml")]
[Route("AchievementWebService.asmx/SetAchievementAndGetReward")] [Route("AchievementWebService.asmx/SetAchievementAndGetReward")]
[Route("AchievementWebService.asmx/SetUserAchievementAndGetReward")] [Route("AchievementWebService.asmx/SetUserAchievementAndGetReward")]
public IActionResult SetAchievementAndGetReward([FromForm] string apiToken, [FromForm] int achievementID) { [VikingSession()]
Viking? viking = ctx.Sessions.FirstOrDefault(x => x.ApiToken == apiToken).Viking; public IActionResult SetAchievementAndGetReward(Viking viking, [FromForm] int achievementID) {
if (viking is null) {
return Unauthorized();
}
var rewards = achievementService.ApplyAchievementRewardsByID(viking, achievementID); var rewards = achievementService.ApplyAchievementRewardsByID(viking, achievementID);
ctx.SaveChanges(); ctx.SaveChanges();
return Ok(rewards); return Ok(rewards);
@ -155,13 +151,8 @@ public class AchievementController : Controller {
[Produces("application/xml")] [Produces("application/xml")]
[Route("V2/AchievementWebService.asmx/SetUserAchievementTask")] [Route("V2/AchievementWebService.asmx/SetUserAchievementTask")]
[DecryptRequest("achievementTaskSetRequest")] [DecryptRequest("achievementTaskSetRequest")]
public IActionResult SetUserAchievementTask([FromForm] string apiToken) { [VikingSession()]
Viking? viking = ctx.Sessions.FirstOrDefault(x => x.ApiToken == apiToken).Viking; public IActionResult SetUserAchievementTask(Viking viking) {
if (viking is null) {
return Unauthorized();
}
AchievementTaskSetRequest request = XmlUtil.DeserializeXml<AchievementTaskSetRequest>(Request.Form["achievementTaskSetRequest"]); AchievementTaskSetRequest request = XmlUtil.DeserializeXml<AchievementTaskSetRequest>(Request.Form["achievementTaskSetRequest"]);
var response = new List<AchievementTaskSetResponse>(); var response = new List<AchievementTaskSetResponse>();

View File

@ -51,51 +51,6 @@
<ii>0</ii> <ii>0</ii>
</AR> </AR>
</AchievementsIdInfo> </AchievementsIdInfo>
<AchievementsIdInfo>
<AID>201323</AID>
<AR>
<p>2</p>
<a>25</a>
<t>1</t>
<r>21</r>
<ii>0</ii>
</AR>
<AR>
<p>1</p>
<a>50</a>
<t>1</t>
<r>32</r>
<ii>0</ii>
</AR>
<AR>
<p>12</p>
<a>100</a>
<t>1</t>
<r>913</r>
<ii>0</ii>
</AR>
<AR>
<p>12</p>
<a>10</a>
<t>1</t>
<r>920</r>
<ii>0</ii>
</AR>
<AR>
<p>8</p>
<a>200</a>
<t>3</t>
<r>611</r>
<ii>0</ii>
</AR>
<AR>
<p>12</p>
<a>10</a>
<t>3</t>
<r>920</r>
<ii>0</ii>
</AR>
</AchievementsIdInfo>
<AchievementsIdInfo> <AchievementsIdInfo>
<AID>201323</AID> <AID>201323</AID>
<AR> <AR>