diff --git a/src/GZCTF/Controllers/EditController.cs b/src/GZCTF/Controllers/EditController.cs index a8d8da172..337710136 100644 --- a/src/GZCTF/Controllers/EditController.cs +++ b/src/GZCTF/Controllers/EditController.cs @@ -297,11 +297,13 @@ public async Task DeleteGameWriteUps([FromRoute] int id, Cancella [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] public async Task UpdateGamePoster([FromRoute] int id, IFormFile file, CancellationToken token) { - if (file.Length == 0) - return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeZero)])); - - if (file.Length > 3 * 1024 * 1024) - return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeTooLarge)])); + switch (file.Length) + { + case 0: + return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeZero)])); + case > 3 * 1024 * 1024: + return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeTooLarge)])); + } Game? game = await gameRepository.GetGameById(id, token); @@ -529,16 +531,17 @@ public async Task GetGameChallenge([FromRoute] int id, [FromRoute return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? res = await challengeRepository.GetChallenge(id, cId, false, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token); - if (res is null) + if (challenge is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], StatusCodes.Status404NotFound)); - if (res.Type != ChallengeType.DynamicContainer) - res.Flags = (await challengeRepository.GetFlags(res.Id, token)).ToList(); + // do not load flags for dynamic containers + if (challenge.Type != ChallengeType.DynamicContainer) + await challengeRepository.LoadFlags(challenge, token); - return Ok(ChallengeEditDetailModel.FromChallenge(res)); + return Ok(ChallengeEditDetailModel.FromChallenge(challenge)); } /// @@ -564,15 +567,20 @@ public async Task UpdateGameChallenge([FromRoute] int id, [FromRo return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? res = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? res = await challengeRepository.GetChallenge(id, cId, token); if (res is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], StatusCodes.Status404NotFound)); // 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.IsEnabled is true && !res.IsEnabled && res.Type != ChallengeType.DynamicContainer) + { + await challengeRepository.LoadFlags(res, token); + + if (res.Flags.Count == 0) + return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NoFlag)])); + } if (model.EnableTrafficCapture is true && !res.Type.IsContainer()) return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Challenge_CaptureNotAllowed)])); @@ -639,7 +647,7 @@ public async Task CreateTestContainer([FromRoute] int id, [FromRo return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token); if (challenge is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], @@ -705,7 +713,7 @@ public async Task DestroyTestContainer([FromRoute] int id, [FromR return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token); if (challenge is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], @@ -741,7 +749,7 @@ public async Task RemoveGameChallenge([FromRoute] int id, [FromRo return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? res = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? res = await challengeRepository.GetChallenge(id, cId, token); if (res is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], @@ -778,7 +786,7 @@ public async Task UpdateAttachment([FromRoute] int id, [FromRoute return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token); if (challenge is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], @@ -816,12 +824,13 @@ public async Task AddFlags([FromRoute] int id, [FromRoute] int cI return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token); if (challenge is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], StatusCodes.Status404NotFound)); + await challengeRepository.LoadFlags(challenge, token); await challengeRepository.AddFlags(challenge, models, token); return Ok(); @@ -850,12 +859,13 @@ public async Task RemoveFlag([FromRoute] int id, [FromRoute] int return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)], StatusCodes.Status404NotFound)); - GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token); if (challenge is null) return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)], StatusCodes.Status404NotFound)); + await challengeRepository.LoadFlags(challenge, token); return Ok(await challengeRepository.RemoveFlag(challenge, fId, token)); } } diff --git a/src/GZCTF/Controllers/GameController.cs b/src/GZCTF/Controllers/GameController.cs index 9251f3f8f..d6aa82774 100644 --- a/src/GZCTF/Controllers/GameController.cs +++ b/src/GZCTF/Controllers/GameController.cs @@ -1190,13 +1190,16 @@ async Task GetContextInfo(int id, int challengeId = 0, bool withFla if (challengeId <= 0) return res; - GameChallenge? challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token); + GameChallenge? challenge = await challengeRepository.GetChallenge(id, challengeId, token); if (challenge is null) return res.WithResult(NotFound(new RequestResponse( localizer[nameof(Resources.Program.Challenge_NotFound)], StatusCodes.Status404NotFound))); + if (withFlag) + await challengeRepository.LoadFlags(challenge, token); + res.Challenge = challenge; return res; diff --git a/src/GZCTF/Controllers/ProxyController.cs b/src/GZCTF/Controllers/ProxyController.cs index ea2e41e21..afd684ec3 100644 --- a/src/GZCTF/Controllers/ProxyController.cs +++ b/src/GZCTF/Controllers/ProxyController.cs @@ -276,7 +276,8 @@ void LogProxyResult(Guid id, IPEndPoint client, IPEndPoint target, ulong tx, ulo } rx += (ulong)count; - await ws.SendAsync(buffer.AsMemory(0, count), WebSocketMessageType.Binary, true, ct); + await ws.SendAsync( + buffer.AsMemory(0, count), WebSocketMessageType.Binary, true, ct); } } catch (TaskCanceledException) { } diff --git a/src/GZCTF/Repositories/GameChallengeRepository.cs b/src/GZCTF/Repositories/GameChallengeRepository.cs index fa627dcc9..c42d63227 100644 --- a/src/GZCTF/Repositories/GameChallengeRepository.cs +++ b/src/GZCTF/Repositories/GameChallengeRepository.cs @@ -47,22 +47,12 @@ public async Task EnsureInstances(GameChallenge challenge, Game game, Canc return update; } - public Task GetChallenge(int gameId, int id, bool withFlag = false, - CancellationToken token = default) - { - IQueryable challenges = Context.GameChallenges - .Where(c => c.Id == id && c.GameId == gameId); - - if (withFlag) - challenges = challenges.Include(e => e.Flags); + public Task GetChallenge(int gameId, int id, CancellationToken token = default) + => Context.GameChallenges + .Where(c => c.Id == id && c.GameId == gameId).FirstOrDefaultAsync(token); - return challenges.FirstOrDefaultAsync(token); - } - - public Task GetFlags(int challengeId, CancellationToken token = default) => - Context.FlagContexts - .Where(c => c.Id == challengeId) - .ToArrayAsync(token); + public Task LoadFlags(GameChallenge challenge, CancellationToken token = default) => + Context.Entry(challenge).Collection(c => c.Flags).LoadAsync(token); public Task GetChallenges(int gameId, CancellationToken token = default) => Context.GameChallenges.Where(c => c.GameId == gameId).OrderBy(c => c.Id).ToArrayAsync(token); @@ -116,10 +106,11 @@ public async Task RecalculateAcceptedCount(Game game, CancellationToken to await Context.GameChallenges.IgnoreAutoIncludes() .Where(c => query.Any(r => r.ChallengeId == c.Id)) - .ExecuteUpdateAsync(setter => - setter.SetProperty( - c => c.AcceptedCount, - c => query.First(r => r.ChallengeId == c.Id).Count), + .ExecuteUpdateAsync( + setter => + setter.SetProperty( + c => c.AcceptedCount, + c => query.First(r => r.ChallengeId == c.Id).Count), token); await cacheHelper.FlushScoreboardCache(game.Id, token); diff --git a/src/GZCTF/Repositories/Interface/IGameChallengeRepository.cs b/src/GZCTF/Repositories/Interface/IGameChallengeRepository.cs index 5e049fb49..33882af3b 100644 --- a/src/GZCTF/Repositories/Interface/IGameChallengeRepository.cs +++ b/src/GZCTF/Repositories/Interface/IGameChallengeRepository.cs @@ -31,23 +31,22 @@ public interface IGameChallengeRepository : IRepository public Task GetChallenges(int gameId, CancellationToken token = default); /// - /// 获取题目 + /// 获取题目信息,不包含 Flag /// /// 比赛Id /// 题目Id - /// 是否加载Flag /// /// - public Task GetChallenge(int gameId, int id, bool withFlag = false, - CancellationToken token = default); + public Task GetChallenge(int gameId, int id, CancellationToken token = default); /// - /// 获取 Flags + /// 加载 Flags /// - /// 题目Id + /// 题目 /// /// - public Task GetFlags(int challengeId, CancellationToken token = default); + public Task LoadFlags(GameChallenge challenge, CancellationToken token = default); + /// /// 获取全部需要捕获流量的题目 /// @@ -81,8 +80,7 @@ public interface IGameChallengeRepository : IRepository /// 附件信息 /// /// - public Task UpdateAttachment(GameChallenge challenge, AttachmentCreateModel model, - CancellationToken token = default); + public Task UpdateAttachment(GameChallenge challenge, AttachmentCreateModel model, CancellationToken token = default); /// /// 删除 Flag,确保 Flags 字段已加载