├── .deepsource.toml ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ └── codeql.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.txt ├── LICENSE_ADDENDUM.txt ├── Migration ├── README.md ├── migrate-back.sql └── migrate-from.sql ├── README.ja.md ├── README.md ├── README.zh.md ├── assets ├── banner.dark.svg ├── banner.light.svg └── images │ ├── admin.challenge.flags.webp │ ├── admin.challenge.info.webp │ ├── admin.challenges.webp │ ├── admin.game.info.webp │ ├── admin.game.review.webp │ ├── admin.instances.webp │ ├── admin.settings.webp │ ├── admin.teams.webp │ ├── game.challenges.webp │ ├── game.scoreboard.webp │ ├── grafana.webp │ ├── index.webp │ ├── monitor.game.events.webp │ └── monitor.game.submissions.webp ├── cliff.toml ├── crowdin.yml └── src ├── .dockerignore ├── .editorconfig ├── .idea └── .idea.GZCTF │ └── .idea │ ├── .gitignore │ └── .name ├── Directory.Packages.props ├── Dockerfile ├── GZCTF.Test ├── AccountTest.cs ├── ConfigServiceTest.cs ├── GZCTF.Test.csproj ├── SignatureTest.cs └── TestWebAppFactory.cs ├── GZCTF.sln ├── GZCTF.sln.DotSettings ├── GZCTF ├── ClientApp │ ├── .editorconfig │ ├── .env │ ├── .gitignore │ ├── .prettierignore │ ├── .vscode │ │ ├── extensions.json │ │ └── settings.json │ ├── eslint.config.mjs │ ├── index.html │ ├── package.json │ ├── pnpm-lock.yaml │ ├── postcss.config.mjs │ ├── prettier.config.mjs │ ├── src │ │ ├── Api.ts │ │ ├── App.tsx │ │ ├── components │ │ │ ├── AccountView.tsx │ │ │ ├── ActionIconWithConfirm.tsx │ │ │ ├── AppFooter.tsx │ │ │ ├── AppHeader.tsx │ │ │ ├── AppNavbar.tsx │ │ │ ├── Captcha.tsx │ │ │ ├── ChallengeCard.tsx │ │ │ ├── ChallengeModal.tsx │ │ │ ├── ChallengePanel.tsx │ │ │ ├── ColorPreview.tsx │ │ │ ├── CustomColorModal.tsx │ │ │ ├── Empty.tsx │ │ │ ├── ErrorFallback.tsx │ │ │ ├── FooterRender.tsx │ │ │ ├── GameCard.tsx │ │ │ ├── GameChallengeModal.tsx │ │ │ ├── GameJoinModal.tsx │ │ │ ├── GameNoticePanel.tsx │ │ │ ├── GameProgress.tsx │ │ │ ├── HintList.tsx │ │ │ ├── IconHeader.tsx │ │ │ ├── IconTabs.tsx │ │ │ ├── InstanceEntry.tsx │ │ │ ├── LogoBox.tsx │ │ │ ├── LogoHeader.tsx │ │ │ ├── MarkdownRenderer.tsx │ │ │ ├── MobileChallengeCard.tsx │ │ │ ├── MobileChallengePanel.tsx │ │ │ ├── MobilePostCard.tsx │ │ │ ├── MobileScoreboardItemModal.tsx │ │ │ ├── MobileScoreboardTable.tsx │ │ │ ├── PasswordChangeModal.tsx │ │ │ ├── PostCard.tsx │ │ │ ├── RecentGame.tsx │ │ │ ├── RecentGameCarousel.tsx │ │ │ ├── RecentGameSlide.tsx │ │ │ ├── ScoreboardItemModal.tsx │ │ │ ├── ScoreboardTable.tsx │ │ │ ├── ScrollSelect.tsx │ │ │ ├── StrengthPasswordInput.tsx │ │ │ ├── TeamCard.tsx │ │ │ ├── TeamCreateModal.tsx │ │ │ ├── TeamEditModal.tsx │ │ │ ├── TeamRadarMap.tsx │ │ │ ├── TeamRank.tsx │ │ │ ├── TimeLine.tsx │ │ │ ├── TrafficItems.tsx │ │ │ ├── Watermark.tsx │ │ │ ├── WithGameMonitor.tsx │ │ │ ├── WithGameTab.tsx │ │ │ ├── WithNavbar.tsx │ │ │ ├── WithRole.tsx │ │ │ ├── WithWiderScreen.tsx │ │ │ ├── WriteupSubmitModal.tsx │ │ │ ├── admin │ │ │ │ ├── AdminPage.tsx │ │ │ │ ├── AttachmentRemoteEditModal.tsx │ │ │ │ ├── AttachmentUploadModal.tsx │ │ │ │ ├── BloodBonusModel.tsx │ │ │ │ ├── ChallengeCreateModal.tsx │ │ │ │ ├── ChallengeEditCard.tsx │ │ │ │ ├── ChallengePreviewModal.tsx │ │ │ │ ├── FlagCreateModal.tsx │ │ │ │ ├── FlagEditPanel.tsx │ │ │ │ ├── GameCreateModal.tsx │ │ │ │ ├── GameNoticeEditCard.tsx │ │ │ │ ├── GameNoticeEditModal.tsx │ │ │ │ ├── OrganizationTable.tsx │ │ │ │ ├── PDFViewer.tsx │ │ │ │ ├── ParticipationStatusControl.tsx │ │ │ │ ├── PostEditCard.tsx │ │ │ │ ├── ScoreFunc.tsx │ │ │ │ ├── SwitchLabel.tsx │ │ │ │ ├── TeamEditModal.tsx │ │ │ │ ├── TeamWriteupCard.tsx │ │ │ │ ├── UserEditModal.tsx │ │ │ │ ├── WithAdminTab.tsx │ │ │ │ ├── WithChallengeEdit.tsx │ │ │ │ └── WithGameEditTab.tsx │ │ │ └── icon │ │ │ │ ├── 404Icon.tsx │ │ │ │ ├── MainIcon.tsx │ │ │ │ └── WiderScreenRequiredIcon.tsx │ │ ├── emotion.d.ts │ │ ├── locales │ │ │ ├── de-DE │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── en-US │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── es-ES │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── fr-FR │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── id-ID │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── ja-JP │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── ko-KR │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── ru-RU │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ ├── zh-CN │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ │ └── zh-TW │ │ │ │ ├── account.json │ │ │ │ ├── admin.json │ │ │ │ ├── challenge.json │ │ │ │ ├── common.json │ │ │ │ ├── game.json │ │ │ │ ├── post.json │ │ │ │ └── team.json │ │ ├── main.tsx │ │ ├── mantine.d.ts │ │ ├── pages │ │ │ ├── About.tsx │ │ │ ├── Index.tsx │ │ │ ├── Teams.tsx │ │ │ ├── [...all].tsx │ │ │ ├── account │ │ │ │ ├── Confirm.tsx │ │ │ │ ├── Login.tsx │ │ │ │ ├── Profile.tsx │ │ │ │ ├── Recovery.tsx │ │ │ │ ├── Register.tsx │ │ │ │ ├── Reset.tsx │ │ │ │ └── Verify.tsx │ │ │ ├── admin │ │ │ │ ├── Instances.tsx │ │ │ │ ├── Logs.tsx │ │ │ │ ├── Settings.tsx │ │ │ │ ├── Teams.tsx │ │ │ │ ├── Users.tsx │ │ │ │ └── games │ │ │ │ │ ├── Index.tsx │ │ │ │ │ └── [id] │ │ │ │ │ ├── Info.tsx │ │ │ │ │ ├── Notices.tsx │ │ │ │ │ ├── Review.tsx │ │ │ │ │ ├── Writeups.tsx │ │ │ │ │ └── challenges │ │ │ │ │ ├── Index.tsx │ │ │ │ │ └── [chalId] │ │ │ │ │ ├── Flags.tsx │ │ │ │ │ └── Index.tsx │ │ │ ├── games │ │ │ │ ├── Index.tsx │ │ │ │ └── [id] │ │ │ │ │ ├── Challenges.tsx │ │ │ │ │ ├── Index.tsx │ │ │ │ │ ├── Notice.tsx │ │ │ │ │ ├── Scoreboard.tsx │ │ │ │ │ └── monitor │ │ │ │ │ ├── CheatInfo.tsx │ │ │ │ │ ├── Events.tsx │ │ │ │ │ ├── Submissions.tsx │ │ │ │ │ └── Traffic.tsx │ │ │ └── posts │ │ │ │ ├── Index.tsx │ │ │ │ └── [postId] │ │ │ │ ├── Edit.tsx │ │ │ │ └── Index.tsx │ │ ├── styles │ │ │ ├── App.css │ │ │ ├── components │ │ │ │ ├── AppFooter.module.css │ │ │ │ ├── AppHeader.module.css │ │ │ │ ├── AppNavBar.module.css │ │ │ │ ├── ChallengeCard.module.css │ │ │ │ ├── ChallengeModal.module.css │ │ │ │ ├── ChallengePanel.module.css │ │ │ │ ├── ColorPreview.module.css │ │ │ │ ├── Empty.module.css │ │ │ │ ├── FooterRender.module.css │ │ │ │ ├── GameProgress.module.css │ │ │ │ ├── IconHeader.module.css │ │ │ │ ├── IconTabs.module.css │ │ │ │ ├── LogoHeader.module.css │ │ │ │ ├── MobileChallengeCard.module.css │ │ │ │ ├── PDFViewer.module.css │ │ │ │ ├── Placeholder.module.css │ │ │ │ ├── RecentGameSlide.module.css │ │ │ │ ├── ScoreboardTable.module.css │ │ │ │ └── ScrollSelect.module.css │ │ │ ├── pages │ │ │ │ ├── About.module.css │ │ │ │ ├── Index.module.css │ │ │ │ └── Review.module.css │ │ │ └── shared │ │ │ │ ├── Accordion.module.css │ │ │ │ ├── Banner.module.css │ │ │ │ ├── FixedButton.module.css │ │ │ │ ├── HoverCard.module.css │ │ │ │ ├── Icon.module.css │ │ │ │ ├── Input.module.css │ │ │ │ ├── Table.module.css │ │ │ │ ├── Tooltip.module.css │ │ │ │ ├── Typography.module.css │ │ │ │ └── Upload.module.css │ │ ├── utils │ │ │ ├── ApiHelper.tsx │ │ │ ├── I18n.tsx │ │ │ ├── KatexExtension.ts │ │ │ ├── Shared.tsx │ │ │ ├── ThemeOverride.ts │ │ │ ├── useArrayResponse.ts │ │ │ ├── useConfig.ts │ │ │ ├── useEdit.ts │ │ │ ├── useGame.ts │ │ │ ├── usePageTitle.ts │ │ │ └── useUser.tsx │ │ └── vite-env.d.ts │ ├── template │ │ ├── api.eta │ │ ├── http-client.eta │ │ ├── procedure-call.eta │ │ └── route-types.eta │ ├── tsconfig.json │ └── vite.config.mts ├── Controllers │ ├── AccountController.cs │ ├── AdminController.cs │ ├── AssetsController.cs │ ├── EditController.cs │ ├── ErrorController.cs │ ├── ExerciseController.cs │ ├── GameController.cs │ ├── InfoController.cs │ ├── ProxyController.cs │ └── TeamController.cs ├── Dockerfile ├── Extensions │ ├── CacheExtension.cs │ ├── CaptchaExtension.cs │ ├── ConfigurationExtension.cs │ ├── DatabaseSinkExtension.cs │ ├── OtherExtensions.cs │ ├── SignalRSinkExtension.cs │ ├── StorageExtension.cs │ └── TelemetryExtension.cs ├── GZCTF.csproj ├── Hubs │ ├── AdminHub.cs │ ├── Clients │ │ ├── IAdminClient.cs │ │ ├── IMonitorClient.cs │ │ └── IUserClient.cs │ ├── MonitorHub.cs │ └── UserHub.cs ├── Middlewares │ ├── PrivilegeAuthentication.cs │ └── RateLimiter.cs ├── Migrations │ ├── 20240202021414_Initialize.Designer.cs │ ├── 20240202021414_Initialize.cs │ ├── 20240208144221_FormatableData.Designer.cs │ ├── 20240208144221_FormatableData.cs │ ├── 20240424194046_UpdateModelLimits.Designer.cs │ ├── 20240424194046_UpdateModelLimits.cs │ ├── 20240502062801_UpdateLogModel.Designer.cs │ ├── 20240502062801_UpdateLogModel.cs │ ├── 20240726155408_Add_Challenge_CanSubmit.Designer.cs │ ├── 20240726155408_Add_Challenge_CanSubmit.cs │ ├── 20240731082848_AddOrganizationsVerifyCode.Designer.cs │ ├── 20240731082848_AddOrganizationsVerifyCode.cs │ ├── 20240825191922_AddChallengeTime.Designer.cs │ ├── 20240825191922_AddChallengeTime.cs │ ├── 20240913074608_RenameTagToCategory.Designer.cs │ └── 20240913074608_RenameTagToCategory.cs ├── Models │ ├── AppDbContext.cs │ ├── Data │ │ ├── Attachment.cs │ │ ├── Challenge.cs │ │ ├── CheatInfo.cs │ │ ├── Config.cs │ │ ├── Container.cs │ │ ├── Dependency.cs │ │ ├── ExerciseChallenge.cs │ │ ├── ExerciseInstance.cs │ │ ├── FlagContext.cs │ │ ├── Game.cs │ │ ├── GameChallenge.cs │ │ ├── GameEvent.cs │ │ ├── GameInstance.cs │ │ ├── GameNotice.cs │ │ ├── Instance.cs │ │ ├── LocalFile.cs │ │ ├── LogModel.cs │ │ ├── Participation.cs │ │ ├── Post.cs │ │ ├── Submission.cs │ │ ├── Team.cs │ │ ├── UserInfo.cs │ │ └── UserParticipation.cs │ ├── Internal │ │ ├── CaptchaModel.cs │ │ ├── CheatCheckInfo.cs │ │ ├── Configs.cs │ │ ├── ContainerConfig.cs │ │ ├── ContainerInfo.cs │ │ ├── FormattableData.cs │ │ └── TelemetryMeters.cs │ ├── Limits.cs │ └── Request │ │ ├── Account │ │ ├── AccountVerifyModel.cs │ │ ├── LoginModel.cs │ │ ├── MailChangeModel.cs │ │ ├── PasswordChangeModel.cs │ │ ├── PasswordResetModel.cs │ │ ├── ProfileUpdateModel.cs │ │ ├── ProfileUserInfoModel.cs │ │ ├── RecoveryModel.cs │ │ └── RegisterModel.cs │ │ ├── Admin │ │ ├── AdminTeamModel.cs │ │ ├── AdminUserInfoModel.cs │ │ ├── ConfigEditModel.cs │ │ ├── ContainerInstanceModel.cs │ │ ├── LogMessageModel.cs │ │ ├── ParticipationInfoModel.cs │ │ ├── TeamWithDetailedUserInfo.cs │ │ ├── UserCreateModel.cs │ │ ├── UserInfoModel.cs │ │ └── WriteupInfoModel.cs │ │ ├── Edit │ │ ├── AttachmentCreateModel.cs │ │ ├── ChallengeEditDetailModel.cs │ │ ├── ChallengeInfoModel.cs │ │ ├── ChallengeUpdateModel.cs │ │ ├── FlagCreateModel.cs │ │ ├── FlagInfoModel.cs │ │ ├── GameInfoModel.cs │ │ ├── GameNoticeModel.cs │ │ └── PostEditModel.cs │ │ ├── Exercise │ │ ├── ExerciseDetailModel.cs │ │ └── ExerciseInfoModel.cs │ │ ├── Game │ │ ├── BasicGameInfoModel.cs │ │ ├── BasicWriteupInfoModel.cs │ │ ├── ChallengeDetailModel.cs │ │ ├── ChallengeTrafficModel.cs │ │ ├── CheatInfoModel.cs │ │ ├── ContainerInfoModel.cs │ │ ├── DetailedGameInfoModel.cs │ │ ├── FlagSubmitModel.cs │ │ ├── GameDetailModel.cs │ │ ├── GameJoinModel.cs │ │ ├── ScoreboardModel.cs │ │ └── TeamTrafficModel.cs │ │ ├── Info │ │ ├── ClientCaptchaInfoModel.cs │ │ ├── PostDetailModel.cs │ │ ├── PostInfoModel.cs │ │ ├── SignatureVerifyModel.cs │ │ ├── TeamInfoModel.cs │ │ ├── TeamTransferModel.cs │ │ ├── TeamUpdateModel.cs │ │ └── TeamUserInfoModel.cs │ │ └── Shared │ │ └── ClientFlagContext.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Providers │ ├── EntityConfigurationProvider.cs │ └── EntityConfigurationSource.cs ├── Repositories │ ├── BlobRepository.cs │ ├── CheatInfoRepository.cs │ ├── ContainerRepository.cs │ ├── ExerciseChallengeRepository.cs │ ├── ExerciseInstanceRepository.cs │ ├── GameChallengeRepository.cs │ ├── GameEventRepository.cs │ ├── GameInstanceRepository.cs │ ├── GameNoticeRepository.cs │ ├── GameRepository.cs │ ├── Interface │ │ ├── IBlobRepository.cs │ │ ├── ICheatInfoRepository.cs │ │ ├── IContainerRepository.cs │ │ ├── IExerciseChallengeRepository.cs │ │ ├── IExerciseInstanceRepository.cs │ │ ├── IGameChallengeRepository.cs │ │ ├── IGameEventRepository.cs │ │ ├── IGameInstanceRepository.cs │ │ ├── IGameNoticeRepository.cs │ │ ├── IGameRepository.cs │ │ ├── ILogRepository.cs │ │ ├── IParticipationRepository.cs │ │ ├── IPostRepository.cs │ │ ├── IRepository.cs │ │ ├── ISubmissionRepository.cs │ │ ├── ITeamRepository.cs │ │ └── IUserRepository.cs │ ├── LogRepository.cs │ ├── ParticipationRepository.cs │ ├── PostRepository.cs │ ├── RepositoryBase.cs │ ├── SubmissionRepository.cs │ └── TeamRepository.cs ├── Resources │ ├── Program.de-DE.resx │ ├── Program.es-ES.resx │ ├── Program.fr-FR.resx │ ├── Program.id-ID.resx │ ├── Program.ja-JP.resx │ ├── Program.ko-KR.resx │ ├── Program.resx │ ├── Program.ru-RU.resx │ ├── Program.zh-CN.resx │ ├── Program.zh-TW.resx │ └── favicon.webp ├── Services │ ├── Cache │ │ ├── CacheHelper.cs │ │ └── CacheMaker.cs │ ├── Config │ │ ├── ConfigService.cs │ │ └── IConfigService.cs │ ├── Container │ │ ├── ContainerServiceExtension.cs │ │ ├── Manager │ │ │ ├── DockerManager.cs │ │ │ ├── IContainerManager.cs │ │ │ ├── KubernetesManager.cs │ │ │ └── SwarmManager.cs │ │ └── Provider │ │ │ ├── DockerProvider.cs │ │ │ ├── IContainerProvider.cs │ │ │ └── KubernetesProvider.cs │ ├── CronJobService.cs │ ├── FlagChecker.cs │ ├── Mail │ │ ├── IMailSender.cs │ │ └── MailSender.cs │ └── Telemetry │ │ └── ContainerTelemetryService.cs ├── Utils │ ├── AsyncManualResetEvent.cs │ ├── Codec.cs │ ├── CulturedLocalizer.cs │ ├── DigitalSignature.cs │ ├── Enums.cs │ ├── ExcelHelper.cs │ ├── HubHelper.cs │ ├── LogHelper.cs │ ├── PathHelper.cs │ ├── PrelaunchHelper.cs │ ├── RecordableNetworkStream.cs │ ├── Shared.cs │ ├── TarHelper.cs │ ├── TranslatedIdentityErrorDescriber.cs │ └── ZStandardCompressionProvider.cs └── wwwroot │ └── .keep └── global.json /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "csharp" 5 | enabled = true 6 | 7 | [[analyzers]] 8 | name = "shell" 9 | enabled = true 10 | 11 | [[analyzers]] 12 | name = "javascript" 13 | enabled = true 14 | 15 | [analyzers.meta] 16 | plugins = ["react"] 17 | 18 | [[transformers]] 19 | name = "prettier" 20 | enabled = true 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: [ 4 | 'https://blog.gzti.me/thanks/' 5 | ] 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Read the docs 阅读文档 4 | url: https://gzctf.gzti.me/ 5 | about: If you haven't read the docs yet, please check it out first. 如果你还没有阅读过文档,请先查阅。 6 | - name: Community support 社区支持 7 | url: https://github.com/GZTimeWalker/GZCTF/discussions 8 | about: Please ask and answer questions in the user group or GitHub Discussions. 请在用户群或 GitHub Discussions 中提问交流。 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Basic dependabot.yml file with 2 | # minimum configuration for two package managers 3 | 4 | version: 2 5 | updates: 6 | # Check for updates to NPM packages daily 7 | - package-ecosystem: "npm" 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | open-pull-requests-limit: 1 12 | ignore: 13 | - dependency-name: "pdfjs-dist" 14 | - dependency-name: "@types/*" 15 | 16 | # Check for updates to NuGet packages daily 17 | - package-ecosystem: "nuget" 18 | directory: "/" 19 | schedule: 20 | interval: "daily" 21 | open-pull-requests-limit: 1 22 | ignore: 23 | - dependency-name: "MailKit" 24 | 25 | # Check for updates to GitHub Actions workflows weekly 26 | - package-ecosystem: "github-actions" 27 | directory: "/" 28 | schedule: 29 | interval: "weekly" 30 | open-pull-requests-limit: 1 31 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: ["main"] 9 | schedule: 10 | - cron: "21 15 * * 3" 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | defaults: 21 | run: 22 | working-directory: src/GZCTF 23 | 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | language: ["csharp", "javascript"] 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v4 32 | 33 | # Initializes the CodeQL tools for scanning. 34 | - name: Initialize CodeQL 35 | uses: github/codeql-action/init@v3 36 | with: 37 | languages: ${{ matrix.language }} 38 | 39 | - uses: actions/setup-dotnet@v4 40 | with: 41 | global-json-file: src/global.json 42 | 43 | - uses: actions/setup-node@v4 44 | with: 45 | node-version: 18 46 | 47 | - run: npm i -g pnpm 48 | 49 | - name: Build with dotnet 50 | run: | 51 | dotnet build "GZCTF.csproj" -c Release -o build 52 | 53 | - name: Perform CodeQL Analysis 54 | uses: github/codeql-action/analyze@v3 55 | with: 56 | category: "/language:${{matrix.language}}" 57 | -------------------------------------------------------------------------------- /LICENSE_ADDENDUM.txt: -------------------------------------------------------------------------------- 1 | License Addendum for GZ::CTF 2 | 3 | This addendum to the AGPLv3 license applies to the following specific files and 4 | the "GZCTF" string within this project. 5 | 6 | ### Restricted Files 7 | 8 | The following files may not be modified, redistributed, or used in derivative 9 | works without the express written permission of the original author or maintainers: 10 | 11 | - src/GZCTF/Services/Container/Manager/*.cs 12 | - src/GZCTF/ClientApp/src/utils/useConfig.ts 13 | 14 | ### Restricted String 15 | 16 | Any string or identifier related to the "GZCTF" name, including but not limited 17 | to variations, derivations, or similar constructs, is considered a protected 18 | identifier within this project. Modification, removal, or replacement of these 19 | identifiers in any part of the codebase is strictly prohibited without the express 20 | written permission of the original author or maintainers. 21 | 22 | **Examples of protected identifiers include, but are not limited to:** 23 | 24 | - GZCTF 25 | - GZ::CTF 26 | - GZCTF_FLAG 27 | - GZCTF_Token 28 | - ASCII art or logos containing the GZCTF name 29 | 30 | These restrictions are in addition to the terms of the AGPLv3 license. 31 | 32 | [2024-08-10] 33 | -------------------------------------------------------------------------------- /Migration/README.md: -------------------------------------------------------------------------------- 1 | # 迁移教程 2 | 3 | ## 从 `GZTimeWalker/GZCTF` 迁移 4 | 5 | 由于数据库变更, 需要手动迁移数据. 6 | 7 | 执行 SQL 文件 [migrate-from.sql](migrate-from.sql) 进行迁移. 8 | 9 | 你可以将此文件上传到服务器上 10 | 11 | 以下是你可能用得到的指令 12 | 13 | ```bash 14 | docker compose exec db psql -U postgres -d gzctf 15 | ``` 16 | 17 | 将 [migrate-from.sql](migrate-from.sql) 内容复制到其中执行. 18 | 19 | 20 | ## 迁移回 `GZTimeWalker/GZCTF` 21 | 22 | 由于数据库变更, 需要手动迁移数据. 23 | 24 | 执行 SQL 文件 [migrate-back.sql](migrate-back.sql) 进行迁移. -------------------------------------------------------------------------------- /Migration/migrate-back.sql: -------------------------------------------------------------------------------- 1 | START TRANSACTION; 2 | 3 | ALTER TABLE "GameChallenges" DROP COLUMN "EnableAt"; 4 | 5 | ALTER TABLE "GameChallenges" DROP COLUMN "EndAt"; 6 | 7 | DELETE FROM "__EFMigrationsHistory" 8 | WHERE "MigrationId" = '20240825191922_AddChallengeTime'; 9 | 10 | COMMIT; 11 | 12 | START TRANSACTION; 13 | 14 | ALTER TABLE "GameChallenges" DROP COLUMN "CanSubmit"; 15 | 16 | ALTER TABLE "ExerciseChallenges" DROP COLUMN "CanSubmit"; 17 | 18 | DELETE FROM "__EFMigrationsHistory" 19 | WHERE "MigrationId" = '20240726155408_Add_Challenge_CanSubmit'; 20 | 21 | COMMIT; 22 | 23 | -- Migrate Invitation Code 24 | 25 | START TRANSACTION; 26 | 27 | UPDATE "Games" SET "Organizations" = '[]'; 28 | 29 | COMMIT; 30 | 31 | -------------------------------------------------------------------------------- /Migration/migrate-from.sql: -------------------------------------------------------------------------------- 1 | START TRANSACTION; 2 | 3 | ALTER TABLE "GameChallenges" ADD "CanSubmit" boolean NOT NULL DEFAULT FALSE; 4 | 5 | ALTER TABLE "ExerciseChallenges" ADD "CanSubmit" boolean NOT NULL DEFAULT FALSE; 6 | 7 | INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") 8 | VALUES ('20240726155408_Add_Challenge_CanSubmit', '8.0.8'); 9 | 10 | COMMIT; 11 | 12 | START TRANSACTION; 13 | 14 | ALTER TABLE "GameChallenges" ADD "EnableAt" timestamp with time zone; 15 | 16 | ALTER TABLE "GameChallenges" ADD "EndAt" timestamp with time zone; 17 | 18 | INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") 19 | VALUES ('20240825191922_AddChallengeTime', '8.0.8'); 20 | 21 | COMMIT; 22 | 23 | -- Migrate Invitation Code 24 | 25 | START TRANSACTION; 26 | 27 | UPDATE "Games" SET "Organizations" = '{}'; 28 | 29 | COMMIT; 30 | 31 | -------------------------------------------------------------------------------- /assets/images/admin.challenge.flags.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.challenge.flags.webp -------------------------------------------------------------------------------- /assets/images/admin.challenge.info.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.challenge.info.webp -------------------------------------------------------------------------------- /assets/images/admin.challenges.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.challenges.webp -------------------------------------------------------------------------------- /assets/images/admin.game.info.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.game.info.webp -------------------------------------------------------------------------------- /assets/images/admin.game.review.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.game.review.webp -------------------------------------------------------------------------------- /assets/images/admin.instances.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.instances.webp -------------------------------------------------------------------------------- /assets/images/admin.settings.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.settings.webp -------------------------------------------------------------------------------- /assets/images/admin.teams.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/admin.teams.webp -------------------------------------------------------------------------------- /assets/images/game.challenges.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/game.challenges.webp -------------------------------------------------------------------------------- /assets/images/game.scoreboard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/game.scoreboard.webp -------------------------------------------------------------------------------- /assets/images/grafana.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/grafana.webp -------------------------------------------------------------------------------- /assets/images/index.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/index.webp -------------------------------------------------------------------------------- /assets/images/monitor.game.events.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/monitor.game.events.webp -------------------------------------------------------------------------------- /assets/images/monitor.game.submissions.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kengwang/GZCTF/26020c0ec869c13022004626f7bba5e0b13396e8/assets/images/monitor.game.submissions.webp -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /src/GZCTF/Resources/Program.resx 3 | translation: /src/GZCTF/Resources/Program.%locale%.resx 4 | - source: /src/GZCTF/ClientApp/src/locales/en-US/*.json 5 | translation: /src/GZCTF/ClientApp/src/locales/%locale%/%original_file_name% 6 | -------------------------------------------------------------------------------- /src/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /src/.idea/.idea.GZCTF/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /projectSettingsUpdater.xml 6 | /modules.xml 7 | /.idea.GZCTF.iml 8 | /contentModel.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | # GitHub Copilot persisted chat sessions 15 | /copilot/chatSessions 16 | -------------------------------------------------------------------------------- /src/.idea/.idea.GZCTF/.idea/.name: -------------------------------------------------------------------------------- 1 | GZCTF -------------------------------------------------------------------------------- /src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build 2 | 3 | ARG TIMESTAMP 4 | ARG GIT_SHA 5 | ARG GIT_NAME 6 | ENV VITE_APP_BUILD_TIMESTAMP=$TIMESTAMP \ 7 | VITE_APP_GIT_SHA=$GIT_SHA \ 8 | VITE_APP_GIT_NAME=$GIT_NAME 9 | 10 | RUN apt update && apt install -y wget gnupg2 libpcap0.8 && \ 11 | wget -qO- https://deb.nodesource.com/setup_20.x | bash - && \ 12 | apt install -y build-essential nodejs 13 | 14 | RUN npm i -g pnpm 15 | 16 | COPY [".", "/src"] 17 | 18 | WORKDIR "/src/GZCTF" 19 | RUN dotnet build "GZCTF.csproj" -c Release -o /app/build 20 | 21 | FROM build AS publish 22 | RUN dotnet publish "GZCTF.csproj" -c Release -o /app/publish -r linux-x64 --no-self-contained /p:PublishReadyToRun=true 23 | 24 | FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS final 25 | 26 | ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false \ 27 | LC_ALL=en_US.UTF-8 28 | 29 | WORKDIR /app 30 | EXPOSE 8080 31 | RUN apk add --update --no-cache wget libpcap icu-data-full icu-libs ca-certificates libgdiplus tzdata && \ 32 | update-ca-certificates 33 | 34 | COPY --from=publish /app/publish . 35 | 36 | HEALTHCHECK --interval=5m --timeout=3s --start-period=10s --retries=1 \ 37 | CMD wget --no-verbose --tries=1 --spider http://localhost:8080/healthz || exit 1 38 | 39 | ENTRYPOINT ["dotnet", "GZCTF.dll"] 40 | -------------------------------------------------------------------------------- /src/GZCTF.Test/AccountTest.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Net.Http.Json; 4 | using System.Threading.Tasks; 5 | using Xunit; 6 | 7 | namespace GZCTF.Test; 8 | 9 | public class AccountTest(TestWebAppFactory factory) : IClassFixture 10 | { 11 | [Fact] 12 | public async Task TestCreateUser() 13 | { 14 | using HttpClient client = factory.CreateClient(); 15 | HttpResponseMessage registerResult = await client.PostAsJsonAsync("/api/account/register", 16 | new { userName = "foo", password = "foo12345", email = "foo@example.com" }); 17 | Assert.Equal(HttpStatusCode.BadRequest, registerResult.StatusCode); 18 | 19 | registerResult = await client.PostAsJsonAsync("/api/account/register", 20 | new { userName = "foo", password = "foo12345##Foo", email = "foo@example.com" }); 21 | Assert.True(registerResult.IsSuccessStatusCode); 22 | 23 | HttpResponseMessage loginResult = 24 | await client.PostAsJsonAsync("/api/account/login", new { userName = "foo", password = "foo12345##" }); 25 | Assert.False(loginResult.IsSuccessStatusCode); 26 | 27 | loginResult = 28 | await client.PostAsJsonAsync("/api/account/login", new { userName = "foo", password = "foo12345##Foo" }); 29 | Assert.True(loginResult.IsSuccessStatusCode); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/GZCTF.Test/ConfigServiceTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GZCTF.Models.Data; 3 | using GZCTF.Models.Internal; 4 | using GZCTF.Services.Config; 5 | using Xunit; 6 | using Xunit.Abstractions; 7 | 8 | namespace GZCTF.Test; 9 | 10 | public class ConfigServiceTest(ITestOutputHelper output) 11 | { 12 | [Fact] 13 | public void TestGetConfigs() 14 | { 15 | HashSet? configs = ConfigService.GetConfigs(new TestConfig()); 16 | Assert.True(configs is not null); 17 | Assert.True(configs.Count > 0); 18 | 19 | foreach (Config config in configs) 20 | output.WriteLine($"{config.ConfigKey,-32}={config.Value}"); 21 | } 22 | } 23 | 24 | public class TestConfig 25 | { 26 | public AccountPolicy AccountPolicy { get; set; } = new(); 27 | public DockerConfig DockerConfig { get; set; } = new(); 28 | public EmailConfig EmailConfig { get; set; } = new(); 29 | } 30 | -------------------------------------------------------------------------------- /src/GZCTF.Test/GZCTF.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | false 7 | true 8 | Debug;Release;GenAPI 9 | 0.25.0 10 | True 11 | 4 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | all 25 | runtime; build; native; contentfiles; analyzers; buildtransitive 26 | 27 | 28 | runtime; build; native; contentfiles; analyzers; buildtransitive 29 | all 30 | 31 | 32 | runtime; build; native; contentfiles; analyzers; buildtransitive 33 | all 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/GZCTF.Test/TestWebAppFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Testing; 2 | 3 | namespace GZCTF.Test; 4 | 5 | public abstract class TestWebAppFactory : WebApplicationFactory 6 | { 7 | static TestWebAppFactory() 8 | { 9 | Program.IsTesting = true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | max_line_length = 120 12 | 13 | [*.md] 14 | max_line_length = off 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/.env: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URL="http://localhost:55000/" 2 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | *.pem 17 | 18 | # debug 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | .pnpm-debug.log* 23 | 24 | # local env files 25 | .env*.local 26 | 27 | # vercel 28 | .vercel 29 | 30 | # typescript 31 | *.tsbuildinfo 32 | 33 | template/swagger*.json 34 | .eslintcache 35 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/.prettierignore: -------------------------------------------------------------------------------- 1 | **/Api.ts 2 | **/locales 3 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Lokalise.i18n-ally" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "liveServer.settings.root": "/build", 3 | "i18n-ally.namespace": true, 4 | "i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}", 5 | "i18n-ally.keystyle": "nested", 6 | "i18n-ally.extract.keyPrefix": "{fileNameWithoutExt}", 7 | "i18n-ally.localesPaths": [ 8 | "src/locales" 9 | ], 10 | "i18n-ally.extract.autoDetect": true, 11 | "i18n-ally.extract.keyMaxLength": 20, 12 | "i18n-ally.extract.keygenStyle": "snake_case", 13 | "i18n-ally.sortKeys": true, 14 | "i18n-ally.sourceLanguage": "en-US", 15 | "cssVariables.lookupFiles": [ 16 | "**/*.css", 17 | "**/*.scss", 18 | "**/*.sass", 19 | "**/*.less", 20 | "node_modules/@mantine/core/styles.css" 21 | ], 22 | "editor.tabSize": 2 23 | } 24 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | %title% 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | 'postcss-preset-mantine': { 4 | autoRem: true, 5 | }, 6 | 'postcss-simple-vars': { 7 | variables: { 8 | 'mantine-breakpoint-xs': '36em', 9 | 'mantine-breakpoint-sm': '48em', 10 | 'mantine-breakpoint-md': '62em', 11 | 'mantine-breakpoint-lg': '75em', 12 | 'mantine-breakpoint-xl': '88em', 13 | }, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/prettier.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | export default { 3 | useTabs: false, 4 | tabWidth: 2, 5 | singleQuote: true, 6 | trailingComma: 'es5', 7 | semi: false, 8 | printWidth: 100, 9 | htmlWhitespaceSensitivity: 'ignore', 10 | jsonRecursiveSort: true, 11 | plugins: ['@trivago/prettier-plugin-sort-imports', 'prettier-plugin-sort-json'], 12 | importOrder: [ 13 | '', 14 | '^@Components/(.*)$', 15 | '^@Utils/(.*)$', 16 | '^@Api$', 17 | '^@Styles/(.*)$', 18 | '^@(.*).css$', 19 | '^[./]', 20 | ], 21 | } 22 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/src/components/AccountView.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Stack } from '@mantine/core' 2 | import { FC } from 'react' 3 | import { PropsWithChildren } from 'react' 4 | import { useNavigate } from 'react-router-dom' 5 | import LogoHeader from '@Components/LogoHeader' 6 | 7 | interface AccountViewProps extends PropsWithChildren { 8 | onSubmit?: (event: React.FormEvent) => Promise 9 | } 10 | 11 | const AccountView: FC = ({ onSubmit, children }) => { 12 | const navigate = useNavigate() 13 | 14 | return ( 15 |
16 | 17 | navigate('/')} /> 18 |
26 | 27 | {children} 28 | 29 |
30 |
31 |
32 | ) 33 | } 34 | 35 | export default AccountView 36 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/src/components/ColorPreview.tsx: -------------------------------------------------------------------------------- 1 | import { ColorSwatch, Group, GroupProps, MantineColorsTuple, isLightColor } from '@mantine/core' 2 | import { FC } from 'react' 3 | import classes from '@Styles/ColorPreview.module.css' 4 | 5 | interface ColorsPreviewProps extends GroupProps { 6 | colors: MantineColorsTuple 7 | displayColorsInfo: boolean | undefined 8 | } 9 | 10 | const ColorPreview: FC = ({ colors, displayColorsInfo, ...others }) => { 11 | const items = colors.map((color, index) => ( 12 |
13 | 20 | {displayColorsInfo && ( 21 |
22 | {color} 23 |
24 | )} 25 |
26 |
27 | )) 28 | 29 | return ( 30 | 31 | {items} 32 | 33 | ) 34 | } 35 | 36 | export default ColorPreview 37 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/src/components/Empty.tsx: -------------------------------------------------------------------------------- 1 | import { MantineSize, Stack, Text } from '@mantine/core' 2 | import { mdiInbox } from '@mdi/js' 3 | import { Icon } from '@mdi/react' 4 | import { FC, ReactNode } from 'react' 5 | import { useTranslation } from 'react-i18next' 6 | import classes from '@Styles/Empty.module.css' 7 | 8 | interface EmptyProps { 9 | bordered?: boolean 10 | description?: ReactNode 11 | fontSize?: string | MantineSize | undefined 12 | mdiPath?: string 13 | iconSize?: number 14 | } 15 | 16 | const Empty: FC = (props) => { 17 | const { t } = useTranslation() 18 | 19 | return ( 20 | 21 | 22 | 23 | {props.description ?? t('common.content.no_data')} 24 | 25 | 26 | ) 27 | } 28 | 29 | export default Empty 30 | -------------------------------------------------------------------------------- /src/GZCTF/ClientApp/src/components/ErrorFallback.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Center, Text, Stack, Title, useMantineTheme, Textarea, Group } from '@mantine/core' 2 | import { FC } from 'react' 3 | import { FallbackProps } from 'react-error-boundary' 4 | import { useTranslation } from 'react-i18next' 5 | import { useIsMobile } from '@Utils/ThemeOverride' 6 | import { clearLocalCache } from '@Utils/useConfig' 7 | 8 | const ErrorFallback: FC = ({ error, resetErrorBoundary }: FallbackProps) => { 9 | const theme = useMantineTheme() 10 | const { t } = useTranslation() 11 | const isMobile = useIsMobile() 12 | 13 | return ( 14 |
15 | 16 | 17 | # {t('common.error.encountered')} 18 | 19 | 20 | {error.message} 21 | 22 |