From ef6b57a9c9d0a0bad27669f4eca16109c7ad06a6 Mon Sep 17 00:00:00 2001 From: Stavros Date: Fri, 19 Jan 2024 15:26:11 +0200 Subject: [PATCH] feat(apps): add ctfd (#2173) * feat(apps): add ctfd * fix(ctfd): add the right username --- README.md | 1 + apps/ctfd/config.json | 43 +++++++++++++++++ apps/ctfd/docker-compose.yml | 75 ++++++++++++++++++++++++++++++ apps/ctfd/metadata/description.md | 35 ++++++++++++++ apps/ctfd/metadata/logo.jpg | Bin 0 -> 15393 bytes 5 files changed, 154 insertions(+) create mode 100644 apps/ctfd/config.json create mode 100644 apps/ctfd/docker-compose.yml create mode 100644 apps/ctfd/metadata/description.md create mode 100644 apps/ctfd/metadata/logo.jpg diff --git a/README.md b/README.md index daa61d83..a1530e80 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ This is the official repository for the Tipi App Store. It contains all the apps - [Crafty Controller](https://gitlab.com/crafty-controller/crafty-4) - Crafty 4 is the next iteration of our Minecraft Server Wrapper / Controller / Launcher. - [Conduit](https://gitlab.com/famedly/conduit) - Conduit is a simple, fast and reliable chat server written in Rust - [Cross-seed](https://github.com/cross-seed/cross-seed) - Fully-automatic, no false positives. +- [CTFd](https://github.com/CTFd/CTFd) - CTFd is a Capture The Flag framework focusing on ease of use and customizability. - [DailyTXT](https://github.com/PhiTux/DailyTxT) - Encrypted Diary Web-App - [Dash.](https://github.com/MauriceNino/dashdot) - A simple, modern server dashboard, primarily used by smaller private server - [Dashy](https://github.com/lissy93/dashy) - A self-hostable personal dashboard built for you. diff --git a/apps/ctfd/config.json b/apps/ctfd/config.json new file mode 100644 index 00000000..d59ca33e --- /dev/null +++ b/apps/ctfd/config.json @@ -0,0 +1,43 @@ +{ + "$schema": "../schema.json", + "name": "CTFd", + "port": 8546, + "available": true, + "exposable": true, + "id": "ctfd", + "tipi_version": 1, + "version": "3.6.1", + "categories": [ + "utilities" + ], + "description": "CTFd is a Capture The Flag framework focusing on ease of use and customizability.", + "short_desc": "Cyber Security Training made simple.", + "author": "CTFd", + "source": "https://github.com/CTFd/CTFd", + "website": "https://ctfd.io/", + "form_fields": [ + { + "type": "random", + "label": "CTFD_MYSQL_DB_PASSWORD", + "min": 32, + "env_variable": "CTFD_MYSQL_DB_PASSWORD" + }, + { + "type": "random", + "label": "CTFD_SECRET_KEY", + "min": 32, + "env_variable": "CTFD_SECRET_KEY" + }, + { + "type": "random", + "label": "CTFD_MYSQL_ROOT_PASSWORD", + "min": 32, + "env_variable": "CTFD_MYSQL_ROOT_PASSWORD" + } + ], + "supported_architectures": [ + "arm64", + "amd64" + ] + } + \ No newline at end of file diff --git a/apps/ctfd/docker-compose.yml b/apps/ctfd/docker-compose.yml new file mode 100644 index 00000000..a695dde3 --- /dev/null +++ b/apps/ctfd/docker-compose.yml @@ -0,0 +1,75 @@ +version: "3.7" +services: + ctfd: + image: ctfd/ctfd:3.6.1 + container_name: ctfd + restart: unless-stopped + ports: + - ${APP_PORT}:8000 + environment: + - UPLOAD_FOLDER=/var/uploads + - DATABASE_URL=mysql+pymysql://tipi:${CTFD_MYSQL_DB_PASSWORD}@ctfd-db/ctfd + - REDIS_URL=redis://ctfd-redis:6379 + - WORKERS=1 + - LOG_FOLDER=/var/log/CTFd + - ACCESS_LOG=- + - ERROR_LOG=- + - REVERSE_PROXY=true + - SECRET_KEY=${CTFD_SECRET_KEY} + volumes: + - ${APP_DATA_DIR}/data/uploads:/var/log/CTFd + - ${APP_DATA_DIR}/data/uploads:/var/uploads + depends_on: + - ctfd-db + networks: + - tipi_main_network + labels: + # Main + traefik.enable: true + traefik.http.middlewares.ctfd-web-redirect.redirectscheme.scheme: https + traefik.http.services.ctfd.loadbalancer.server.port: 8000 + # Web + traefik.http.routers.ctfd-insecure.rule: Host(`${APP_DOMAIN}`) + traefik.http.routers.ctfd-insecure.entrypoints: web + traefik.http.routers.ctfd-insecure.service: ctfd + traefik.http.routers.ctfd-insecure.middlewares: ctfd-web-redirect + # Websecure + traefik.http.routers.ctfd.rule: Host(`${APP_DOMAIN}`) + traefik.http.routers.ctfd.entrypoints: websecure + traefik.http.routers.ctfd.service: ctfd + traefik.http.routers.ctfd.tls.certresolver: myresolver + # Local domain + traefik.http.routers.ctfd-local-insecure.rule: Host(`ctfd.${LOCAL_DOMAIN}`) + traefik.http.routers.ctfd-local-insecure.entrypoints: web + traefik.http.routers.ctfd-local-insecure.service: ctfd + traefik.http.routers.ctfd-local-insecure.middlewares: ctfd-web-redirect + # Local domain secure + traefik.http.routers.ctfd-local.rule: Host(`ctfd.${LOCAL_DOMAIN}`) + traefik.http.routers.ctfd-local.entrypoints: websecure + traefik.http.routers.ctfd-local.service: ctfd + traefik.http.routers.ctfd-local.tls: true + + ctfd-db: + image: mariadb:10.4.12 + restart: unless-stopped + container_name: ctfd-db + environment: + - MYSQL_ROOT_PASSWORD=${CTFD_MYSQL_ROOT_PASSWORD} + - MYSQL_USER=tipi + - MYSQL_PASSWORD=${CTFD_MYSQL_DB_PASSWORD} + - MYSQL_DATABASE=ctfd + volumes: + - ${APP_DATA_DIR}/data/db:/var/lib/mysql + networks: + - tipi_main_network + # This command is required to set important mariadb defaults + command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --wait_timeout=28800, --log-warnings=0] + + ctfd-redis: + image: redis:4 + container_name: ctfd-redis + restart: unless-stopped + volumes: + - ${APP_DATA_DIR}/data/redis:/data + networks: + - tipi_main_network \ No newline at end of file diff --git a/apps/ctfd/metadata/description.md b/apps/ctfd/metadata/description.md new file mode 100644 index 00000000..21f3df69 --- /dev/null +++ b/apps/ctfd/metadata/description.md @@ -0,0 +1,35 @@ +# ![](https://github.com/CTFd/CTFd/blob/master/CTFd/themes/core/static/img/logo.png?raw=true) + +## What is CTFd? + +CTFd is a Capture The Flag framework focusing on ease of use and customizability. It comes with everything you need to run a CTF and it's easy to customize with plugins and themes. + +![CTFd is a CTF in a can.](https://github.com/CTFd/CTFd/blob/master/CTFd/themes/core/static/img/scoreboard.png?raw=true) + +## Features + +- Create your own challenges, categories, hints, and flags from the Admin Interface + - Dynamic Scoring Challenges + - Unlockable challenge support + - Challenge plugin architecture to create your own custom challenges + - Static & Regex based flags + - Custom flag plugins + - Unlockable hints + - File uploads to the server or an Amazon S3-compatible backend + - Limit challenge attempts & hide challenges + - Automatic bruteforce protection +- Individual and Team based competitions + - Have users play on their own or form teams to play together +- Scoreboard with automatic tie resolution + - Hide Scores from the public + - Freeze Scores at a specific time +- Scoregraphs comparing the top 10 teams and team progress graphs +- Markdown content management system +- SMTP + Mailgun email support + - Email confirmation support + - Forgot password support +- Automatic competition starting and ending +- Team management, hiding, and banning +- Customize everything using the [plugin](https://docs.ctfd.io/docs/plugins/overview) and [theme](https://docs.ctfd.io/docs/themes/overview) interfaces +- Importing and Exporting of CTF data for archival +- And a lot more... \ No newline at end of file diff --git a/apps/ctfd/metadata/logo.jpg b/apps/ctfd/metadata/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2637dbff5a195d2707d00768b8b8839de2df899d GIT binary patch literal 15393 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 literal 0 HcmV?d00001