diff --git a/src/GZCTF/Controllers/AccountController.cs b/src/GZCTF/Controllers/AccountController.cs index e45d5d386..1cb963a4b 100644 --- a/src/GZCTF/Controllers/AccountController.cs +++ b/src/GZCTF/Controllers/AccountController.cs @@ -87,14 +87,14 @@ public async Task Register([FromBody] RegisterModel model, Cancel await signInManager.SignInAsync(user, true); logger.Log("用户成功注册", user, TaskStatus.Success); - return Ok(new RequestResponse("注册成功", RegisterStatus.LoggedIn, 200)); + return Ok(new RequestResponse("注册成功", RegisterStatus.LoggedIn, StatusCodes.Status200OK)); } if (!accountPolicy.Value.EmailConfirmationRequired) { logger.Log("用户成功注册,待审核", user, TaskStatus.Success); return Ok(new RequestResponse("注册成功,等待管理员审核", - RegisterStatus.AdminConfirmationRequired, 200)); + RegisterStatus.AdminConfirmationRequired, StatusCodes.Status200OK)); } logger.Log("发送用户邮箱验证邮件", user, TaskStatus.Pending); @@ -112,7 +112,7 @@ public async Task Register([FromBody] RegisterModel model, Cancel } return Ok(new RequestResponse("注册成功,等待邮箱验证", - RegisterStatus.EmailConfirmationRequired, 200)); + RegisterStatus.EmailConfirmationRequired, StatusCodes.Status200OK)); } /// @@ -138,10 +138,10 @@ public async Task Recovery([FromBody] RecoveryModel model, Cancel var user = await userManager.FindByEmailAsync(model.Email!); if (user is null) - return NotFound(new RequestResponse("用户不存在", 404)); + return NotFound(new RequestResponse("用户不存在", StatusCodes.Status404NotFound)); if (!user.EmailConfirmed) - return NotFound(new RequestResponse("账户未激活,请重新注册", 404)); + return NotFound(new RequestResponse("账户未激活,请重新注册", StatusCodes.Status404NotFound)); if (!accountPolicy.Value.EmailConfirmationRequired) return BadRequest(new RequestResponse("请联系管理员重置密码")); @@ -161,7 +161,7 @@ public async Task Recovery([FromBody] RecoveryModel model, Cancel return BadRequest(new RequestResponse("邮件无法发送,请联系管理员")); } - return Ok(new RequestResponse("邮件发送成功", 200)); + return Ok(new RequestResponse("邮件发送成功", StatusCodes.Status200OK)); } /// @@ -219,7 +219,7 @@ public async Task Verify([FromBody] AccountVerifyModel model) var result = await userManager.ConfirmEmailAsync(user, Codec.Base64.Decode(model.Token)); if (!result.Succeeded) - return Unauthorized(new RequestResponse("邮箱验证失败", 401)); + return Unauthorized(new RequestResponse("邮箱验证失败", StatusCodes.Status401Unauthorized)); logger.Log("通过邮箱验证", user, TaskStatus.Success); await signInManager.SignInAsync(user, true); @@ -260,10 +260,10 @@ public async Task LogIn([FromBody] LoginModel model, Cancellation user ??= await userManager.FindByEmailAsync(model.UserName); if (user is null) - return Unauthorized(new RequestResponse("用户名或密码错误", 401)); + return Unauthorized(new RequestResponse("用户名或密码错误", StatusCodes.Status401Unauthorized)); if (user.Role == Role.Banned) - return Unauthorized(new RequestResponse("用户已被禁用", 401)); + return Unauthorized(new RequestResponse("用户已被禁用", StatusCodes.Status401Unauthorized)); user.LastSignedInUTC = DateTimeOffset.UtcNow; user.UpdateByHttpContext(HttpContext); @@ -273,7 +273,7 @@ public async Task LogIn([FromBody] LoginModel model, Cancellation var result = await signInManager.PasswordSignInAsync(user, model.Password, true, false); if (!result.Succeeded) - return Unauthorized(new RequestResponse("用户名或密码错误", 401)); + return Unauthorized(new RequestResponse("用户名或密码错误", StatusCodes.Status401Unauthorized)); logger.Log("用户成功登录", user, TaskStatus.Success); @@ -397,7 +397,7 @@ public async Task ChangeEmail([FromBody] MailChangeModel model) return BadRequest(new RequestResponse("邮件无法发送,请联系管理员")); } - return Ok(new RequestResponse("邮箱待验证", true, 200)); + return Ok(new RequestResponse("邮箱待验证", true, StatusCodes.Status200OK)); } /// diff --git a/src/GZCTF/Controllers/AdminController.cs b/src/GZCTF/Controllers/AdminController.cs index 0328c0661..27246d86a 100644 --- a/src/GZCTF/Controllers/AdminController.cs +++ b/src/GZCTF/Controllers/AdminController.cs @@ -293,7 +293,7 @@ public async Task UpdateUserInfo(string userid, [FromBody] AdminU var user = await userManager.FindByIdAsync(userid); if (user is null) - return NotFound(new RequestResponse("用户未找到", 404)); + return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); user.UpdateUserInfo(model); await userManager.UpdateAsync(user); @@ -314,12 +314,12 @@ public async Task UpdateUserInfo(string userid, [FromBody] AdminU [HttpDelete("Users/{userid}/Password")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)] - public async Task ResetPassword(string userid, CancellationToken token = default) + public async Task ResetPassword(string userid) { var user = await userManager.FindByIdAsync(userid); if (user is null) - return NotFound(new RequestResponse("用户未找到", 404)); + return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); var pwd = Codec.RandomPassword(16); var code = await userManager.GeneratePasswordResetTokenAsync(user); @@ -351,7 +351,7 @@ public async Task DeleteUser(string userid, CancellationToken tok user = await userManager.FindByIdAsync(userid); if (user is null) - return NotFound(new RequestResponse("用户未找到", 404)); + return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); if (await teamRepository.CheckIsCaptain(user, token)) return BadRequest(new RequestResponse("不可以删除队长")); @@ -379,7 +379,7 @@ public async Task DeleteTeam(int id, CancellationToken token = de var team = await teamRepository.GetTeamById(id, token); if (team is null) - return NotFound(new RequestResponse("队伍未找到", 404)); + return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); await teamRepository.DeleteTeam(team, token); @@ -403,7 +403,7 @@ public async Task UserInfo(string userid) var user = await userManager.FindByIdAsync(userid); if (user is null) - return NotFound(new RequestResponse("用户未找到", 404)); + return NotFound(new RequestResponse("用户未找到", StatusCodes.Status404NotFound)); return Ok(ProfileUserInfoModel.FromUserInfo(user)); } @@ -440,7 +440,7 @@ public async Task Participation(int id, ParticipationStatus statu var participation = await participationRepository.GetParticipationById(id, token); if (participation is null) - return NotFound(new RequestResponse("参与状态未找到", 404)); + return NotFound(new RequestResponse("参与状态未找到", StatusCodes.Status404NotFound)); await participationRepository.UpdateParticipationStatus(participation, status, token); @@ -465,7 +465,7 @@ public async Task Writeups(int id, CancellationToken token = defa var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); return Ok(await participationRepository.GetWriteups(game, token)); } @@ -488,7 +488,7 @@ public async Task DownloadAllWriteups(int id, CancellationToken t var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var wps = await participationRepository.GetWriteups(game, token); var filename = $"Writeups-{game.Title}-{DateTimeOffset.UtcNow:yyyyMMdd-HH.mm.ssZ}"; @@ -532,12 +532,12 @@ public async Task DestroyInstance(string id, CancellationToken to var container = await containerRepository.GetContainerById(id, token); if (container is null) - return NotFound(new RequestResponse("容器实例未找到", 404)); + return NotFound(new RequestResponse("容器实例未找到", StatusCodes.Status404NotFound)); if (await instanceRepository.DestroyContainer(container, token)) return Ok(); else - return BadRequest(new RequestResponse("容器实例销毁失败", 404)); + return BadRequest(new RequestResponse("容器实例销毁失败")); } /// diff --git a/src/GZCTF/Controllers/AssetsController.cs b/src/GZCTF/Controllers/AssetsController.cs index 35ed7941a..247ebdb39 100644 --- a/src/GZCTF/Controllers/AssetsController.cs +++ b/src/GZCTF/Controllers/AssetsController.cs @@ -38,16 +38,19 @@ public IActionResult GetFile([RegularExpression("[0-9a-f]{64}")] string hash, st if (!System.IO.File.Exists(path)) { - logger.Log($"尝试获取不存在的文件 [{hash[..8]}] {filename}", HttpContext.Connection?.RemoteIpAddress?.ToString() ?? "0.0.0.0", TaskStatus.NotFound, LogLevel.Warning); - return NotFound(new RequestResponse("文件不存在", 404)); + var ip = HttpContext.Connection?.RemoteIpAddress?.ToString() ?? "0.0.0.0"; + logger.Log($"尝试获取不存在的文件 [{hash[..8]}] {filename}", ip, TaskStatus.NotFound, LogLevel.Warning); + return NotFound(new RequestResponse("文件不存在", StatusCodes.Status404NotFound)); } if (!_extProvider.TryGetContentType(filename, out string? contentType)) contentType = MediaTypeNames.Application.Octet; + HttpContext.Response.Headers.CacheControl = $"public, max-age={60 * 60 * 24 * 7}"; + return new PhysicalFileResult(path, contentType) { - FileDownloadName = filename + FileDownloadName = filename, }; } diff --git a/src/GZCTF/Controllers/EditController.cs b/src/GZCTF/Controllers/EditController.cs index 930999b0c..0740e427b 100644 --- a/src/GZCTF/Controllers/EditController.cs +++ b/src/GZCTF/Controllers/EditController.cs @@ -71,7 +71,7 @@ public async Task UpdatePost(string id, [FromBody] PostEditModel var post = await postRepository.GetPostById(id, token); if (post is null) - return NotFound(new RequestResponse("文章未找到", 404)); + return NotFound(new RequestResponse("文章未找到", StatusCodes.Status404NotFound)); var user = await userManager.GetUserAsync(User); @@ -98,7 +98,7 @@ public async Task DeletePost(string id, CancellationToken token) var post = await postRepository.GetPostById(id, token); if (post is null) - return NotFound(new RequestResponse("文章未找到", 404)); + return NotFound(new RequestResponse("文章未找到", StatusCodes.Status404NotFound)); await postRepository.RemovePost(post, token); @@ -122,7 +122,7 @@ public async Task AddGame([FromBody] GameInfoModel model, Cancell var game = await gameRepository.CreateGame(new Game().Update(model), token); if (game is null) - return BadRequest(new RequestResponse("比赛创建失败", 400)); + return BadRequest(new RequestResponse("比赛创建失败")); gameRepository.FlushGameInfoCache(); @@ -163,7 +163,7 @@ public async Task GetGame([FromRoute] int id, CancellationToken t var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); return Ok(GameInfoModel.FromGame(game)); } @@ -185,7 +185,7 @@ public async Task GetTeamHashSalt([FromRoute] int id, Cancellatio var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); // ref: TeamToken => // Codec.StrSHA256($"{part.Token}::{part.Game.TeamHashSalt}::{Id}"); @@ -210,7 +210,7 @@ public async Task UpdateGame([FromRoute] int id, [FromBody] GameI var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); game.Update(model); await gameRepository.SaveAsync(token); @@ -238,7 +238,7 @@ public async Task DeleteGame([FromRoute] int id, CancellationToke var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); return await gameRepository.DeleteGame(game, token) switch { @@ -265,7 +265,7 @@ public async Task DeleteGameWriteUps([FromRoute] int id, Cancella var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); await gameRepository.DeleteAllWriteUps(game, token); @@ -296,7 +296,7 @@ public async Task UpdateGamePoster([FromRoute] int id, IFormFile var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var poster = await fileService.CreateOrUpdateImage(file, "poster", 0, token); @@ -328,7 +328,7 @@ public async Task AddGameNotice([FromRoute] int id, [FromBody] Ga var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var res = await gameNoticeRepository.AddNotice(new() { @@ -358,7 +358,7 @@ public async Task GetGameNotices([FromRoute] int id, Cancellation var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); return Ok(await gameNoticeRepository.GetNormalNotices(id, token)); } @@ -382,7 +382,7 @@ public async Task UpdateGameNotice([FromRoute] int id, [FromRoute var notice = await gameNoticeRepository.GetNoticeById(id, noticeId, token); if (notice is null) - return NotFound(new RequestResponse("通知未找到", 404)); + return NotFound(new RequestResponse("通知未找到", StatusCodes.Status404NotFound)); if (notice.Type != NoticeType.Normal) return BadRequest(new RequestResponse("不能更改系统通知")); @@ -410,7 +410,7 @@ public async Task DeleteGameNotice([FromRoute] int id, [FromRoute var notice = await gameNoticeRepository.GetNoticeById(id, noticeId, token); if (notice is null) - return NotFound(new RequestResponse("通知未找到", 404)); + return NotFound(new RequestResponse("通知未找到", StatusCodes.Status404NotFound)); if (notice.Type != NoticeType.Normal) return BadRequest(new RequestResponse("不能删除系统通知")); @@ -438,7 +438,7 @@ public async Task AddGameChallenge([FromRoute] int id, [FromBody] var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var res = await challengeRepository.CreateChallenge(game, new Challenge() { @@ -482,12 +482,12 @@ public async Task GetGameChallenge([FromRoute] int id, [FromRoute var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var res = await challengeRepository.GetChallenge(id, cId, true, token); if (res is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); return Ok(ChallengeEditDetailModel.FromChallenge(res)); } @@ -511,12 +511,12 @@ public async Task UpdateGameChallenge([FromRoute] int id, [FromRo var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var res = await challengeRepository.GetChallenge(id, cId, true, token); if (res is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); // NOTE: IsEnabled can only be updated outside of the edit page if (model.IsEnabled == true && !res.Flags.Any() && res.Type != ChallengeType.DynamicContainer) @@ -587,12 +587,12 @@ public async Task CreateTestContainer([FromRoute] int id, [FromRo var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); if (!challenge.Type.IsContainer()) return BadRequest(new RequestResponse("题目类型不可创建容器")); @@ -643,12 +643,12 @@ public async Task DestroyTestContainer([FromRoute] int id, [FromR var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); if (challenge.TestContainer is null) return Ok(); @@ -677,12 +677,12 @@ public async Task RemoveGameChallenge([FromRoute] int id, [FromRo var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var res = await challengeRepository.GetChallenge(id, cId, true, token); if (res is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); await challengeRepository.RemoveChallenge(res, token); @@ -711,12 +711,12 @@ public async Task UpdateAttachment([FromRoute] int id, [FromRoute var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); if (challenge.Type == ChallengeType.DynamicAttachment) return BadRequest(new RequestResponse("动态附件题目请使用 assets API 上传附件")); @@ -745,12 +745,12 @@ public async Task AddFlags([FromRoute] int id, [FromRoute] int cI var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); await challengeRepository.AddFlags(challenge, models, token); @@ -776,12 +776,12 @@ public async Task RemoveFlag([FromRoute] int id, [FromRoute] int var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var challenge = await challengeRepository.GetChallenge(id, cId, true, token); if (challenge is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); return Ok(await challengeRepository.RemoveFlag(challenge, fId, token)); } diff --git a/src/GZCTF/Controllers/GameController.cs b/src/GZCTF/Controllers/GameController.cs index 72945d11b..a0a6e2309 100644 --- a/src/GZCTF/Controllers/GameController.cs +++ b/src/GZCTF/Controllers/GameController.cs @@ -70,7 +70,7 @@ public async Task Games(int id, CancellationToken token) var context = await GetContextInfo(id, token: token); if (context.Game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var count = await participationRepository.GetParticipationCount(context.Game, token); @@ -100,7 +100,7 @@ public async Task JoinGame(int id, [FromBody] GameJoinModel model var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); if (!game.PracticeMode && game.EndTimeUTC < DateTimeOffset.UtcNow) return BadRequest(new RequestResponse("比赛已结束")); @@ -115,7 +115,7 @@ public async Task JoinGame(int id, [FromBody] GameJoinModel model var team = await teamRepository.GetTeamById(model.TeamId, token); if (team is null) - return NotFound(new RequestResponse("队伍未找到", 404)); + return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); if (team.Members.All(u => u.Id != user!.Id)) return BadRequest(new RequestResponse("您不是此队伍的队员")); @@ -187,7 +187,7 @@ public async Task LeaveGame(int id, CancellationToken token) var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); var user = await userManager.GetUserAsync(User); @@ -229,7 +229,7 @@ public async Task Scoreboard([FromRoute] int id, CancellationToke var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); if (DateTimeOffset.UtcNow < game.StartTimeUTC) return BadRequest(new RequestResponse("比赛未开始")); @@ -257,7 +257,7 @@ public async Task Notices([FromRoute] int id, [FromQuery] int cou var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); if (DateTimeOffset.UtcNow < game.StartTimeUTC) return BadRequest(new RequestResponse("比赛未开始")); @@ -287,7 +287,7 @@ public async Task Events([FromRoute] int id, [FromQuery] bool hid var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); if (DateTimeOffset.UtcNow < game.StartTimeUTC) return BadRequest(new RequestResponse("比赛未开始")); @@ -317,7 +317,7 @@ public async Task Submissions([FromRoute] int id, [FromQuery] Ans var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); if (DateTimeOffset.UtcNow < game.StartTimeUTC) return BadRequest(new RequestResponse("比赛未开始")); @@ -344,7 +344,7 @@ public async Task CheatInfo([FromRoute] int id, CancellationToken var game = await gameRepository.GetGameById(id, token); if (game is null) - return NotFound(new RequestResponse("比赛未找到", 404)); + return NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound)); if (DateTimeOffset.UtcNow < game.StartTimeUTC) return BadRequest(new RequestResponse("比赛未开始")); @@ -389,12 +389,12 @@ public async Task GetChallengeTraffic([FromRoute] int challengeId var filePath = $"{FilePath.Capture}/{challengeId}"; if (!Path.Exists(filePath)) - return NotFound(new RequestResponse("未找到相关捕获信息", 404)); + return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); var participationIds = await GetDirNamesAsInt(filePath); if (participationIds.Count == 0) - return NotFound(new RequestResponse("未找到相关捕获信息", 404)); + return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); var participations = await participationRepository.GetParticipationsByIds(participationIds, token); @@ -420,7 +420,7 @@ public IActionResult GetTeamTraffic([FromRoute] int challengeId, [FromRoute] int var filePath = $"{FilePath.Capture}/{challengeId}/{partId}"; if (!Path.Exists(filePath)) - return NotFound(new RequestResponse("未找到相关捕获信息", 404)); + return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); return Ok(FilePath.GetFileRecords(filePath, out long _)); } @@ -445,7 +445,7 @@ public async Task GetTeamTrafficZip([FromRoute] int challengeId, var filePath = $"{FilePath.Capture}/{challengeId}/{partId}"; if (!Path.Exists(filePath)) - return NotFound(new RequestResponse("未找到相关捕获信息", 404)); + return NotFound(new RequestResponse("未找到相关捕获信息", StatusCodes.Status404NotFound)); var filename = $"Capture-{challengeId}-{partId}-{DateTimeOffset.UtcNow:yyyyMMdd-HH.mm.ssZ}"; var stream = await Codec.ZipFilesAsync(filePath, filename, token); @@ -663,7 +663,7 @@ public async Task SubmissionSheet([FromRoute] int id, Cancellatio public async Task GetChallenge([FromRoute] int id, [FromRoute] int challengeId, CancellationToken token) { if (id <= 0 || challengeId <= 0) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); var context = await GetContextInfo(id, token: token); @@ -673,7 +673,7 @@ public async Task GetChallenge([FromRoute] int id, [FromRoute] in var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) - return NotFound(new RequestResponse("题目未找到或动态附件分配失败", 404)); + return NotFound(new RequestResponse("题目未找到或动态附件分配失败", StatusCodes.Status404NotFound)); return Ok(ChallengeDetailModel.FromInstance(instance)); } @@ -747,7 +747,7 @@ public async Task Status([FromRoute] int id, [FromRoute] int chal var submission = await submissionRepository.GetSubmission(id, challengeId, userId!, submitId, token); if (submission is null) - return NotFound(new RequestResponse("提交未找到", 404)); + return NotFound(new RequestResponse("提交未找到", StatusCodes.Status404NotFound)); return Ok(submission.Status switch { @@ -870,15 +870,15 @@ public async Task CreateContainer([FromRoute] int id, [FromRoute] var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); if (!instance.Challenge.Type.IsContainer()) return BadRequest(new RequestResponse("题目不可创建容器")); if (DateTimeOffset.UtcNow - instance.LastContainerOperation < TimeSpan.FromSeconds(10)) - return new JsonResult(new RequestResponse("容器操作过于频繁", 429)) + return new JsonResult(new RequestResponse("容器操作过于频繁", StatusCodes.Status429TooManyRequests)) { - StatusCode = 429 + StatusCode = StatusCodes.Status429TooManyRequests }; if (instance.Container is not null) @@ -926,7 +926,7 @@ public async Task ProlongContainer([FromRoute] int id, [FromRoute var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); if (!instance.Challenge.Type.IsContainer()) return BadRequest(new RequestResponse("题目不可创建容器")); @@ -971,7 +971,7 @@ public async Task DeleteContainer([FromRoute] int id, [FromRoute] var instance = await instanceRepository.GetInstance(context.Participation!, challengeId, token); if (instance is null) - return NotFound(new RequestResponse("题目未找到", 404)); + return NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound)); if (!instance.Challenge.Type.IsContainer()) return BadRequest(new RequestResponse("题目不可创建容器")); @@ -980,9 +980,9 @@ public async Task DeleteContainer([FromRoute] int id, [FromRoute] return BadRequest(new RequestResponse("题目未创建容器")); if (DateTimeOffset.UtcNow - instance.LastContainerOperation < TimeSpan.FromSeconds(10)) - return new JsonResult(new RequestResponse("容器操作过于频繁", 429)) + return new JsonResult(new RequestResponse("容器操作过于频繁", StatusCodes.Status429TooManyRequests)) { - StatusCode = 429 + StatusCode = StatusCodes.Status429TooManyRequests }; var destroyId = instance.Container.ContainerId; @@ -1030,7 +1030,7 @@ private async Task GetContextInfo(int id, int challengeId = 0, bool }; if (res.Game is null) - return res.WithResult(NotFound(new RequestResponse("比赛未找到", 404))); + return res.WithResult(NotFound(new RequestResponse("比赛未找到", StatusCodes.Status404NotFound))); var part = await participationRepository.GetParticipation(res.User!, res.Game, token); @@ -1053,7 +1053,7 @@ private async Task GetContextInfo(int id, int challengeId = 0, bool var challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token); if (challenge is null) - return res.WithResult(NotFound(new RequestResponse("题目未找到", 404))); + return res.WithResult(NotFound(new RequestResponse("题目未找到", StatusCodes.Status404NotFound))); res.Challenge = challenge; } diff --git a/src/GZCTF/Controllers/InfoController.cs b/src/GZCTF/Controllers/InfoController.cs index 7672dbf3f..5e60fbfc8 100644 --- a/src/GZCTF/Controllers/InfoController.cs +++ b/src/GZCTF/Controllers/InfoController.cs @@ -63,7 +63,7 @@ public async Task GetPost(string id, CancellationToken token) var post = await postRepository.GetPostByIdFromCache(id, token); if (post is null) - return NotFound(new RequestResponse("文章未找到", 404)); + return NotFound(new RequestResponse("文章不存在", StatusCodes.Status404NotFound)); return Ok(PostDetailModel.FromPost(post)); } diff --git a/src/GZCTF/Controllers/ProxyController.cs b/src/GZCTF/Controllers/ProxyController.cs index ad555334c..1a52b59c2 100644 --- a/src/GZCTF/Controllers/ProxyController.cs +++ b/src/GZCTF/Controllers/ProxyController.cs @@ -46,7 +46,7 @@ public async Task ProxyForInstance(string id, CancellationToken t return BadRequest(new RequestResponse("TCP 代理已禁用")); if (!await ValidateContainer(id, token)) - return NotFound(new RequestResponse("不存在的容器")); + return NotFound(new RequestResponse("不存在的容器", StatusCodes.Status404NotFound)); if (!HttpContext.WebSockets.IsWebSocketRequest) return NoContent(); @@ -57,7 +57,7 @@ public async Task ProxyForInstance(string id, CancellationToken t var container = await containerRepository.GetContainerWithInstanceById(id, token); if (container is null || container.Instance is null || !container.IsProxy) - return NotFound(new RequestResponse("不存在的容器")); + return NotFound(new RequestResponse("不存在的容器", StatusCodes.Status404NotFound)); var ipAddress = (await Dns.GetHostAddressesAsync(container.IP, token)).FirstOrDefault(); @@ -117,7 +117,7 @@ public async Task ProxyForNoInstance(string id, CancellationToken return BadRequest(new RequestResponse("TCP 代理已禁用")); if (!await ValidateContainer(id, token)) - return NotFound(new RequestResponse("不存在的容器")); + return NotFound(new RequestResponse("不存在的容器", StatusCodes.Status404NotFound)); if (!HttpContext.WebSockets.IsWebSocketRequest) return NoContent(); @@ -125,7 +125,7 @@ public async Task ProxyForNoInstance(string id, CancellationToken var container = await containerRepository.GetContainerById(id, token); if (container is null || container.InstanceId != 0 || !container.IsProxy) - return NotFound(new RequestResponse("不存在的容器")); + return NotFound(new RequestResponse("不存在的容器", StatusCodes.Status404NotFound)); var ipAddress = (await Dns.GetHostAddressesAsync(container.IP, token)).FirstOrDefault(); @@ -161,8 +161,11 @@ internal async Task DoContainerProxy(string id, IPEndPoint client } catch (SocketException e) { - logger.SystemLog($"容器连接失败({e.SocketErrorCode}),可能正在启动中或请检查网络配置 -> {target.Address}:{target.Port}", TaskStatus.Failed, LogLevel.Warning); - return new JsonResult(new RequestResponse($"容器连接失败({e.SocketErrorCode})", 418)) { StatusCode = 418 }; + logger.SystemLog($"容器连接失败({e.SocketErrorCode}),可能正在启动中或请检查网络配置 -> {target.Address}:{target.Port}", TaskStatus.Failed, LogLevel.Debug); + return new JsonResult(new RequestResponse($"容器连接失败({e.SocketErrorCode})", StatusCodes.Status418ImATeapot)) + { + StatusCode = StatusCodes.Status418ImATeapot + }; } using var ws = await HttpContext.WebSockets.AcceptWebSocketAsync(); diff --git a/src/GZCTF/Controllers/TeamController.cs b/src/GZCTF/Controllers/TeamController.cs index 4e7757171..fffd8ed30 100644 --- a/src/GZCTF/Controllers/TeamController.cs +++ b/src/GZCTF/Controllers/TeamController.cs @@ -41,7 +41,7 @@ public async Task GetBasicInfo(int id, CancellationToken token) var team = await teamRepository.GetTeamById(id, token); if (team is null) - return NotFound(new RequestResponse("队伍不存在", 404)); + return NotFound(new RequestResponse("队伍不存在", StatusCodes.Status404NotFound)); return Ok(TeamInfoModel.FromTeam(team)); } @@ -135,7 +135,10 @@ public async Task UpdateTeam([FromRoute] int id, [FromBody] TeamU return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; team.UpdateInfo(model); @@ -172,12 +175,15 @@ public async Task Transfer([FromRoute] int id, [FromBody] TeamTra return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; if (team.Locked && await teamRepository.AnyActiveGame(team, token)) return BadRequest(new RequestResponse("队伍已锁定")); - var newCaptain = await userManager.Users.SingleOrDefaultAsync(u => u.Id == model.NewCaptainId); + var newCaptain = await userManager.Users.SingleOrDefaultAsync(u => u.Id == model.NewCaptainId, cancellationToken: token); if (newCaptain is null) return BadRequest(new RequestResponse("移交的用户不存在")); @@ -219,7 +225,10 @@ public async Task InviteCode([FromRoute] int id, CancellationToke return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; return Ok(team.InviteCode); } @@ -251,7 +260,10 @@ public async Task UpdateInviteToken([FromRoute] int id, Cancellat return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; team.UpdateInviteToken(); @@ -288,7 +300,10 @@ public async Task KickUser([FromRoute] int id, [FromRoute] string return BadRequest(new RequestResponse("队伍未找到")); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; var trans = await teamRepository.BeginTransactionAsync(token); @@ -411,7 +426,7 @@ public async Task Leave([FromRoute] int id, CancellationToken tok var team = await teamRepository.GetTeamById(id, token); if (team is null) - return BadRequest(new RequestResponse("队伍未找到")); + return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); var user = await userManager.GetUserAsync(User); @@ -457,10 +472,13 @@ public async Task Avatar([FromRoute] int id, IFormFile file, Canc var team = await teamRepository.GetTeamById(id, token); if (team is null) - return BadRequest(new RequestResponse("队伍未找到")); + return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; if (file.Length == 0) return BadRequest(new RequestResponse("文件非法")); @@ -506,10 +524,13 @@ public async Task DeleteTeam(int id, CancellationToken token) var team = await teamRepository.GetTeamById(id, token); if (team is null) - return BadRequest(new RequestResponse("队伍未找到")); + return NotFound(new RequestResponse("队伍未找到", StatusCodes.Status404NotFound)); if (team.CaptainId != user!.Id) - return new JsonResult(new RequestResponse("无权访问", 403)) { StatusCode = 403 }; + return new JsonResult(new RequestResponse("无权访问", StatusCodes.Status403Forbidden)) + { + StatusCode = StatusCodes.Status403Forbidden + }; if (team.Locked && await teamRepository.AnyActiveGame(team, token)) return BadRequest(new RequestResponse("队伍已锁定")); diff --git a/src/GZCTF/Middlewares/PrivilegeAuthentication.cs b/src/GZCTF/Middlewares/PrivilegeAuthentication.cs index 34b1b5124..1f212c913 100644 --- a/src/GZCTF/Middlewares/PrivilegeAuthentication.cs +++ b/src/GZCTF/Middlewares/PrivilegeAuthentication.cs @@ -1,6 +1,5 @@ using System.Security.Claims; using GZCTF.Utils; -using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.EntityFrameworkCore; diff --git a/src/GZCTF/Middlewares/RateLimiter.cs b/src/GZCTF/Middlewares/RateLimiter.cs index ed9b014cc..1b4539398 100644 --- a/src/GZCTF/Middlewares/RateLimiter.cs +++ b/src/GZCTF/Middlewares/RateLimiter.cs @@ -1,6 +1,6 @@ -using System; -using System.Globalization; +using System.Globalization; using System.Net; +using System.Net.Mime; using System.Security.Claims; using System.Threading.RateLimiting; using GZCTF.Utils; @@ -70,21 +70,21 @@ public static RateLimiterOptions GetRateLimiterOptions() SegmentsPerWindow = 6, }); }), - OnRejected = (context, cancellationToken) => + OnRejected = async (context, cancellationToken) => { - if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) - { - context.HttpContext.Response.Headers.RetryAfter = - ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); - } + context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; + context.HttpContext.Response.ContentType = MediaTypeNames.Application.Json; - context?.HttpContext?.RequestServices? - .GetService()? - .CreateLogger() - .Log($"请求过于频繁:{context.HttpContext.Request.Path}", - context.HttpContext, TaskStatus.Denied, LogLevel.Warning); + var afterSec = (int)TimeSpan.FromMinutes(1).TotalSeconds; + + if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) + afterSec = (int)retryAfter.TotalSeconds; - return new ValueTask(); + context.HttpContext.Response.Headers.RetryAfter = afterSec.ToString(NumberFormatInfo.InvariantInfo); + await context.HttpContext.Response.WriteAsJsonAsync( + new RequestResponse($"Too many requests, retry after {afterSec} seconds.", + StatusCodes.Status429TooManyRequests + ), cancellationToken); } } .AddConcurrencyLimiter(nameof(LimitPolicy.Concurrency), options => diff --git a/src/GZCTF/Program.cs b/src/GZCTF/Program.cs index 0787e664f..71495883b 100644 --- a/src/GZCTF/Program.cs +++ b/src/GZCTF/Program.cs @@ -142,11 +142,11 @@ o.DefaultSignInScheme = IdentityConstants.ExternalScheme; }).AddIdentityCookies(options => { - options.ApplicationCookie?.Configure(cookie => + options.ApplicationCookie?.Configure(auth => { - cookie.Cookie.Name = "GZCTF_Token"; - cookie.SlidingExpiration = true; - cookie.ExpireTimeSpan = TimeSpan.FromDays(7); + auth.Cookie.Name = "GZCTF_Token"; + auth.SlidingExpiration = true; + auth.ExpireTimeSpan = TimeSpan.FromDays(7); }); }); @@ -247,8 +247,7 @@ { OnPrepareResponse = ctx => { - ctx.Context.Response.Headers.Append( - "Cache-Control", $"public, max-age={60 * 60 * 24 * 7}"); + ctx.Context.Response.Headers.CacheControl = $"public, max-age={60 * 60 * 24 * 7}"; } }); diff --git a/src/GZCTF/Utils/LogHelper.cs b/src/GZCTF/Utils/LogHelper.cs index 860ad600e..3d98aa9ff 100644 --- a/src/GZCTF/Utils/LogHelper.cs +++ b/src/GZCTF/Utils/LogHelper.cs @@ -130,7 +130,9 @@ public static Serilog.ILogger GetLogger(IConfiguration configuration, IServicePr .Enrich.FromLogContext() .Filter.ByExcluding( Matching.WithProperty("RequestPath", v => - "/healthz".Equals(v, StringComparison.OrdinalIgnoreCase)) + "/healthz".Equals(v, StringComparison.OrdinalIgnoreCase) || + v.StartsWith("/assets", StringComparison.OrdinalIgnoreCase) + ) ) .MinimumLevel.Debug() .Filter.ByExcluding(logEvent => diff --git a/src/GZCTF/Utils/Shared.cs b/src/GZCTF/Utils/Shared.cs index 83cd83962..c95c56052 100644 --- a/src/GZCTF/Utils/Shared.cs +++ b/src/GZCTF/Utils/Shared.cs @@ -30,7 +30,7 @@ public record TaskResult(TaskStatus Status, TResult? Result = default); /// /// 响应信息 /// 状态码 -public record RequestResponse(string Title, int Status = 400); +public record RequestResponse(string Title, int Status = StatusCodes.Status400BadRequest); /// /// 请求响应 @@ -38,7 +38,7 @@ public record RequestResponse(string Title, int Status = 400); /// 响应信息 /// 数据 /// 状态码 -public record RequestResponse(string Title, T Data, int Status = 400); +public record RequestResponse(string Title, T Data, int Status = StatusCodes.Status400BadRequest); /// /// 答案校验结果