Skip to content

Commit

Permalink
fix: check isEnabled when creating the container
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Apr 29, 2024
1 parent b454437 commit de747ea
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 56 deletions.
10 changes: 7 additions & 3 deletions src/GZCTF/Controllers/EditController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class EditController(
IPostRepository postRepository,
IContainerRepository containerRepository,
IGameChallengeRepository challengeRepository,
IGameInstanceRepository instanceRepository,
IGameNoticeRepository gameNoticeRepository,
IGameRepository gameRepository,
IContainerManager containerService,
Expand Down Expand Up @@ -540,8 +541,8 @@ public async Task<IActionResult> GetGameChallenge([FromRoute] int id, [FromRoute
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

// NOTE: IsEnabled can only be updated outside of the edit page
if (model.IsEnabled == true && !res.Flags.Any() && res.Type != ChallengeType.DynamicContainer)
// NOTE: IsEnabled can only be updated outside the edit page
if (model.IsEnabled == true && res.Flags.Count == 0 && res.Type != ChallengeType.DynamicContainer)
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NoFlag)]));

if (model.EnableTrafficCapture is true && !res.Type.IsContainer())
Expand Down Expand Up @@ -570,6 +571,9 @@ public async Task<IActionResult> GetGameChallenge([FromRoute] int id, [FromRoute
}
else
{
if (!res.Type.IsContainer())
await instanceRepository.DestroyAllInstances(res, token);

await challengeRepository.SaveAsync(token);
}

Expand Down Expand Up @@ -824,4 +828,4 @@ public async Task<IActionResult> GetGameChallenge([FromRoute] int id, [FromRoute

return Ok(await challengeRepository.RemoveFlag(challenge, fId, token));
}
}
}
34 changes: 15 additions & 19 deletions src/GZCTF/Controllers/GameController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ public async Task<IActionResult> ChallengesWithTeamInfo([FromRoute] int id, Canc

ScoreboardModel scoreboard = await gameRepository.GetScoreboard(context.Game!, token);

ScoreboardItem boardItem = scoreboard.Items.TryGetValue(context.Participation!.TeamId, out var item)
ScoreboardItem boardItem = scoreboard.Items.TryGetValue(context.Participation!.TeamId, out ScoreboardItem? item)
? item
: new()
{
Expand Down Expand Up @@ -983,7 +983,7 @@ public async Task<IActionResult> SubmitWriteup([FromRoute] int id, IFormFile fil

GameInstance? instance = await gameInstanceRepository.GetInstance(context.Participation!, challengeId, token);

if (instance is null)
if (instance is null || !instance.Challenge.IsEnabled)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

Expand Down Expand Up @@ -1046,7 +1046,7 @@ public async Task<IActionResult> SubmitWriteup([FromRoute] int id, IFormFile fil

GameInstance? instance = await gameInstanceRepository.GetInstance(context.Participation!, challengeId, token);

if (instance is null)
if (instance is null || !instance.Challenge.IsEnabled)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

Expand Down Expand Up @@ -1097,7 +1097,7 @@ public async Task<IActionResult> SubmitWriteup([FromRoute] int id, IFormFile fil

GameInstance? instance = await gameInstanceRepository.GetInstance(context.Participation!, challengeId, token);

if (instance is null)
if (instance is null || !instance.Challenge.IsEnabled)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

Expand Down Expand Up @@ -1169,23 +1169,19 @@ public async Task<IActionResult> SubmitWriteup([FromRoute] int id, IFormFile fil
BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Game_NotStarted)])));

if (denyAfterEnded && !res.Game.PracticeMode && res.Game.EndTimeUtc < DateTimeOffset.UtcNow)
return res.WithResult(new JsonResult(new RequestResponse(localizer[nameof(Resources.Program.Game_End)]))
{
// for client to handle this properly
StatusCode = StatusCodes.Status410Gone
});
return res.WithResult(new JsonResult(new RequestResponse(localizer[nameof(Resources.Program.Game_End)])));

if (challengeId > 0)
{
GameChallenge? challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token);
if (challengeId <= 0)
return res;

if (challenge is null)
return res.WithResult(NotFound(new RequestResponse(
localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound)));
GameChallenge? challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token);

res.Challenge = challenge;
}
if (challenge is null)
return res.WithResult(NotFound(new RequestResponse(
localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound)));

res.Challenge = challenge;

return res;
}
Expand Down Expand Up @@ -1216,4 +1212,4 @@ public ContextInfo WithResult(IActionResult res)
return this;
}
}
}
}
68 changes: 43 additions & 25 deletions src/GZCTF/Repositories/GameInstanceRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,39 +52,42 @@ public class GameInstanceRepository(

try
{
// dynamic flag dispatch
switch (instance.Challenge.Type)
{
// dynamic flag dispatch
case ChallengeType.DynamicContainer:
instance.FlagContext = new()
{
Challenge = challenge,
// tiny probability will produce the same FLAG,
// but this will not affect the correctness of the answer
Flag = challenge.GenerateDynamicFlag(part),
Flag
// tiny probability will produce the same FLAG,
// but this will not affect the correctness of the answer
= challenge.GenerateDynamicFlag(part),
IsOccupied = true
};
break;
case ChallengeType.DynamicAttachment:
List<FlagContext> flags = await Context.FlagContexts
.Where(e => e.Challenge == challenge && !e.IsOccupied)
.ToListAsync(token);

if (flags.Count == 0)
{
logger.SystemLog(
Program.StaticLocalizer[nameof(Resources.Program.InstanceRepository_DynamicFlagsNotEnough),
challenge.Title,
challenge.Id], TaskStatus.Failed,
LogLevel.Warning);
return null;
List<FlagContext> flags = await Context.FlagContexts
.Where(e => e.Challenge == challenge && !e.IsOccupied)
.ToListAsync(token);

if (flags.Count == 0)
{
logger.SystemLog(
Program.StaticLocalizer[nameof(Resources.Program.InstanceRepository_DynamicFlagsNotEnough),
challenge.Title,
challenge.Id], TaskStatus.Failed,
LogLevel.Warning);
return null;
}

var pos = Random.Shared.Next(flags.Count);
flags[pos].IsOccupied = true;

instance.FlagId = flags[pos].Id;
break;
}

var pos = Random.Shared.Next(flags.Count);
flags[pos].IsOccupied = true;

instance.FlagId = flags[pos].Id;
break;
}

// instance.FlagContext is null by default
Expand Down Expand Up @@ -206,9 +209,20 @@ public class GameInstanceRepository(
return new TaskResult<Container>(TaskStatus.Success, gameInstance.Container);
}

public Task<GameInstance[]> GetInstances(GameChallenge challenge, CancellationToken token = default) =>
Context.GameInstances.Where(i => i.Challenge == challenge).OrderBy(i => i.ParticipationId)
.Include(i => i.Participation).ThenInclude(i => i.Team).ToArrayAsync(token);
public async Task DestroyAllInstances(GameChallenge challenge, CancellationToken token = default)
{
foreach (Container? container in await Context.GameInstances
.Include(i => i.Container)
.Where(i => i.Challenge == challenge && i.ContainerId != null)
.Select(i => i.Container)
.ToArrayAsync(token))
{
if (container is null)
continue;

await containerRepository.DestroyContainer(container, token);
}
}

public async Task<CheatCheckInfo> CheckCheat(Submission submission, CancellationToken token = default)
{
Expand Down Expand Up @@ -308,4 +322,8 @@ public async Task<VerifyResult> VerifyAnswer(Submission submission, Cancellation
throw;
}
}
}

public Task<GameInstance[]> GetInstances(GameChallenge challenge, CancellationToken token = default) =>
Context.GameInstances.Where(i => i.Challenge == challenge).OrderBy(i => i.ParticipationId)
.Include(i => i.Participation).ThenInclude(i => i.Team).ToArrayAsync(token);
}
18 changes: 9 additions & 9 deletions src/GZCTF/Repositories/Interface/IGameInstanceRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ public interface IGameInstanceRepository : IRepository
/// <returns></returns>
public Task<VerifyResult> VerifyAnswer(Submission submission, CancellationToken token = default);

/// <summary>
/// 获取题目实例
/// </summary>
/// <param name="challenge">当前题目</param>
/// <param name="token"></param>
/// <returns></returns>
public Task<GameInstance[]> GetInstances(GameChallenge challenge, CancellationToken token = default);

/// <summary>
/// 检查抄袭行为
/// </summary>
Expand All @@ -48,4 +40,12 @@ public interface IGameInstanceRepository : IRepository
/// <returns></returns>
public Task<TaskResult<Container>> CreateContainer(GameInstance gameInstance, Team team, UserInfo user,
int containerLimit = 3, CancellationToken token = default);
}

/// <summary>
/// 销毁全部题目实例
/// </summary>
/// <param name="challenge">当前题目</param>
/// <param name="token"></param>
/// <returns></returns>
public Task DestroyAllInstances(GameChallenge challenge, CancellationToken token = default);
}

0 comments on commit de747ea

Please sign in to comment.