diff --git a/.env.example b/.env.example index 625be3a..01074a8 100644 --- a/.env.example +++ b/.env.example @@ -1,55 +1,55 @@ # -# CTFPad +# CTFHub # -CTFPAD_DEBUG=1 # Change here to disable debug mode -CTFPAD_DOMAIN=localhost # Change here to your server public IP / FQDN -CTFPAD_PORT=8000 # Change here to your server public port for CTFPad -CTFPAD_PROTOCOL=http # Change here to 1 if your public server uses https -CTFPAD_SECRET_KEY=74320c04549af3a5f9fd9bc007b2e20ced8 # Change here -CTFPAD_URL=${CTFPAD_PROTOCOL}://${CTFPAD_DOMAIN}:${CTFPAD_PORT} +CTFHUB_DEBUG=1 # Change here to disable debug mode +CTFHUB_DOMAIN=localhost # Change here to your server public IP / FQDN +CTFHUB_PORT=8000 # Change here to your server public port for CTFHub +CTFHUB_PROTOCOL=http # Change here to 1 if your public server uses https +CTFHUB_SECRET_KEY=74320c04549af3a5f9fd9bc007b2e20ced8 # Change here +CTFHUB_URL=${CTFHUB_PROTOCOL}://${CTFHUB_DOMAIN}:${CTFHUB_PORT} # -# CTFPad Database +# CTFHub Database # -CTFPAD_DB_HOST=db -CTFPAD_DB_PORT=5432 -CTFPAD_DB_NAME=ctfpad # Change here -CTFPAD_DB_USER=ctfpad # Change here -CTFPAD_DB_PASSWORD=1358127ce28271330b266cbf2ff556af13653fb5 # Change here +CTFHUB_DB_HOST=db +CTFHUB_DB_PORT=5432 +CTFHUB_DB_NAME=ctfhub # Change here +CTFHUB_DB_USER=ctfhub # Change here +CTFHUB_DB_PASSWORD=1358127ce28271330b266cbf2ff556af13653fb5 # Change here # # Hedgedoc settings # -CTFPAD_HEDGEDOC_PROTOCOL=http -CTFPAD_HEDGEDOC_DOMAIN=localhost -CTFPAD_HEDGEDOC_PORT=3000 -CTFPAD_HEDGEDOC_IS_INTERNAL=1 -CTFPAD_HEDGEDOC_URL=${CTFPAD_HEDGEDOC_PROTOCOL}://${CTFPAD_HEDGEDOC_DOMAIN}:${CTFPAD_HEDGEDOC_PORT} +CTFHUB_HEDGEDOC_PROTOCOL=http +CTFHUB_HEDGEDOC_DOMAIN=localhost +CTFHUB_HEDGEDOC_PORT=3000 +CTFHUB_HEDGEDOC_IS_INTERNAL=1 +CTFHUB_HEDGEDOC_URL=${CTFHUB_HEDGEDOC_PROTOCOL}://${CTFHUB_HEDGEDOC_DOMAIN}:${CTFHUB_HEDGEDOC_PORT} # -# CTFPad Email recovery feature +# CTFHub Email recovery feature # # Leave blank or customize below to enable the password recovery feature by email -CTFPAD_EMAIL_SERVER_HOST='' # smtp.gmail.com or mailgun, or sendgrid etc. -CTFPAD_EMAIL_SERVER_PORT=0 -CTFPAD_EMAIL_USERNAME='' -CTFPAD_EMAIL_PASSWORD='' +CTFHUB_EMAIL_SERVER_HOST='' # smtp.gmail.com or mailgun, or sendgrid etc. +CTFHUB_EMAIL_SERVER_PORT=0 +CTFHUB_EMAIL_USERNAME='' +CTFHUB_EMAIL_PASSWORD='' # # Notification webhook URLs # Leave blank or customize below to disable # -CTFPAD_DISCORD_WEBHOOK_URL= +CTFHUB_DISCORD_WEBHOOK_URL= # # Jitsi settings # -CTFPAD_JITSI_URL=https://meet.jit.si +CTFHUB_JITSI_URL=https://meet.jit.si # @@ -58,4 +58,4 @@ CTFPAD_JITSI_URL=https://meet.jit.si # By default, use the public instance at excalidraw.com # To use your own instance, a docker script can be found in `scripts/excalidraw/docker-compose.yml` # -CTFPAD_EXCALIDRAW_URL=https://excalidraw.com:443 +CTFHUB_EXCALIDRAW_URL=https://excalidraw.com:443 diff --git a/.github/workflows/notify.yml b/.github/workflows/notify.yml index 9ca39b2..f210173 100644 --- a/.github/workflows/notify.yml +++ b/.github/workflows/notify.yml @@ -24,8 +24,8 @@ jobs: ● ') }} color: 0x0000ff - username: ${{ github.actor }} on CTFPad - avatar_url: "https://github.com/hugsy/ctfpad/blob/refresh-readme/static/images/new_logo_circle.png?raw=true" + username: ${{ github.actor }} on CTFHub + avatar_url: "https://github.com/hugsy/ctfhub/blob/refresh-readme/static/images/new_logo_circle.png?raw=true" - name: Triggering Pull Request Discord Notification if: github.event_name == 'pull_request' && github.event.action == 'opened' && github.repository_owner == 'hugsy' @@ -41,8 +41,8 @@ jobs: --- Link: ${{ github.event.pull_request.html_url }} color: 0xff0000 - username: ${{ github.actor }} on CTFPad - avatar_url: "https://github.com/hugsy/ctfpad/blob/refresh-readme/static/images/new_logo_circle.png?raw=true" + username: ${{ github.actor }} on CTFHub + avatar_url: "https://github.com/hugsy/ctfhub/blob/refresh-readme/static/images/new_logo_circle.png?raw=true" - name: Triggering Issue Discord Notification if: github.event_name == 'issues' && github.event.action == 'opened' && github.repository_owner == 'hugsy' @@ -58,5 +58,5 @@ jobs: --- Link: ${{ github.event.issue.html_url }} color: 0x00ff00 - username: ${{ github.actor }} on CTFPad - avatar_url: "https://github.com/hugsy/ctfpad/blob/refresh-readme/static/images/new_logo_circle.png?raw=true" + username: ${{ github.actor }} on CTFHub + avatar_url: "https://github.com/hugsy/ctfhub/blob/refresh-readme/static/images/new_logo_circle.png?raw=true" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3c3196..0ab1bd1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,13 +3,13 @@ repos: rev: '3.0.6' hooks: - id: djhtml - files: ctfpad/templates/.*\.html$ + files: ctfhub/templates/.*\.html$ - id: djcss - files: static/css/.*\.css$ + files: ctfhub/static/css/.*\.css$ - id: djjs - files: static/js/.*\.js$ + files: ctfhub/static/js/.*\.js$ - repo: https://github.com/psf/black rev: '23.3.0' diff --git a/README.md b/README.md index 313497d..bd9bdfe 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ Logo

-

CTFPad

+

CTFHub

Where CTFs happen

Code style: black - Licence MIT + Licence MIT Python-Version 3.10 - CTFPad on Discord + CTFHub on Discord

## What is it? @@ -47,8 +47,8 @@ A non-exhaustive list of features: For most people, this will suffice: ```bash -$ git clone https://github.com/hugsy/ctfpad -$ cd ctfpad +$ git clone https://github.com/hugsy/ctfhub +$ cd ctfhub $ cp .env.example .env ### CHANGE THE CREDENTIALS IN .env ### $ nano .env @@ -67,15 +67,18 @@ $ nano scripts/proxy/.env $ docker compose -f scripts/proxy/docker-compose.yml -f ./docker-compose.yml up -d --build ``` -## Gallery +If you're migrating from the first versions called `ctpad`, check out see [PR #83](https://github.com/hugsy/ctfhub/pull/83) to migrate the data to the new environment, search the `Setup > Migration` part. + + +## Gallery Check out the [docs](docs/gallery.md) ## Contribution -`CTFPad` was created and maintained by [`@_hugsy_`](https://twitter.com/_hugsy_), but kept fresh thanks to [all the contributors](https://github.com/hugsy/ctfpad/graphs/contributors). +`CTFHub` was created and maintained by [`@_hugsy_`](https://twitter.com/_hugsy_), but kept fresh thanks to [all the contributors](https://github.com/hugsy/ctfhub/graphs/contributors). -[ ![contributors-img](https://contrib.rocks/image?repo=hugsy/ctfpad) ](https://github.com/hugsy/ctfpad/graphs/contributors) +[ ![contributors-img](https://contrib.rocks/image?repo=hugsy/ctfhub) ](https://github.com/hugsy/ctfhub/graphs/contributors) If you just like the tool, consider dropping on Discord (or Twitter or other) a simple *"thanks"*, it is always very appreciated. @@ -83,7 +86,7 @@ If you just like the tool, consider dropping on Discord (or Twitter or other) a And if you can, consider [sponsoring me](https://github.com/hugsy/sponsors) - it really helps dedicating time and resources to the projects! -## Extra Credits +## Credits and Links -- [CTFPad](https://github.com/StratumAuhuur/CTFPad): nice project but NodeJS, so yeah. Also [`etherpad-lite`](https://yopad.eu) doesn't support MarkDown easily. I like the name, so I took it shamelessly - The world flag images are downloaded from https://flagpedia.net/ +- [CTFHub](https://github.com/StratumAuhuur/CTFHub): NodeJS project that is based on [`etherpad-lite`](https://yopad.eu) (no MarkDown support). diff --git a/conf/certs/README.md b/conf/certs/README.md index 9e92c1d..91b5fc8 100644 --- a/conf/certs/README.md +++ b/conf/certs/README.md @@ -20,12 +20,12 @@ Example with default settings working with the provided `nginx.conf`: mkcert -install # Generate a new certificates with the different subdomains: -mkcert ctfpad.mydomain.com hedgedoc.mydomain.com excalidraw.mydomain.com collab.excalidraw.mydomain.com +mkcert ctfhub.mydomain.com hedgedoc.mydomain.com excalidraw.mydomain.com collab.excalidraw.mydomain.com # Move the generated certificates to the certs folder. Assuming you are at the repository root folder: mkdir -p ./conf/certs/ctfdad.mydomain.com -mv ctfpad.mydomain.com*-key.pem ./conf/certs/ctfdad.mydomain.com/privkey.pem -mv ctfpad.mydomain.com*.pem ./conf/certs/ctfdad.mydomain.com/fullchain.pem +mv ctfhub.mydomain.com*-key.pem ./conf/certs/ctfdad.mydomain.com/privkey.pem +mv ctfhub.mydomain.com*.pem ./conf/certs/ctfdad.mydomain.com/fullchain.pem ``` -If `ctfpad.mydomain.com` is in the `/etc/hosts` file of your machine, then go to `https://ctfpad.mydomain.com` and enjoy the app! +If `ctfhub.mydomain.com` is in the `/etc/hosts` file of your machine, then go to `https://ctfhub.mydomain.com` and enjoy the app! diff --git a/conf/nginx/nginx.conf b/conf/nginx/nginx.conf index 6573b13..78490f2 100644 --- a/conf/nginx/nginx.conf +++ b/conf/nginx/nginx.conf @@ -1,8 +1,8 @@ # -# Basic nginx reverse proxy configuration for CTFPad + hedgedoc + excalidraw +# Basic nginx reverse proxy configuration for CTFHub + hedgedoc + excalidraw # # This configuration will use nginx as a HTTPS reverse-proxy -# - CTFPad (443 -> 8000) +# - CTFHub (443 -> 8000) # - HedgeDoc (443 -> 3000) # - Excalidraw (443 -> 80) # @@ -30,26 +30,26 @@ http { # server { listen 80; - server_name ctfpad.mydomain.com hedgedoc.mydomain.com excalidraw.mydomain.com collab.excalidraw.mydomain.com; + server_name ctfhub.mydomain.com hedgedoc.mydomain.com excalidraw.mydomain.com collab.excalidraw.mydomain.com; return 301 https://$host$request_uri; } # - # CTFPad + # CTFHub # - upstream app_ctfpad_server { - server ctfpad:8000; + upstream app_ctfhub_server { + server ctfhub:8000; } server { listen 443 ssl; - server_name ctfpad.mydomain.com; - ssl_certificate /etc/nginx/certs/ctfpad.mydomain.com/fullchain.pem; # store letsencrypt keys there - ssl_certificate_key /etc/nginx/certs/ctfpad.mydomain.com/privkey.pem; # store letsencrypt keys there + server_name ctfhub.mydomain.com; + ssl_certificate /etc/nginx/certs/ctfhub.mydomain.com/fullchain.pem; # store letsencrypt keys there + ssl_certificate_key /etc/nginx/certs/ctfhub.mydomain.com/privkey.pem; # store letsencrypt keys there location / { - proxy_pass http://app_ctfpad_server; + proxy_pass http://app_ctfhub_server; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -76,8 +76,8 @@ http { server { listen 443 ssl; server_name hedgedoc.mydomain.com; - ssl_certificate /etc/nginx/certs/ctfpad.mydomain.com/fullchain.pem; # store letsencrypt keys there - ssl_certificate_key /etc/nginx/certs/ctfpad.mydomain.com/privkey.pem; # store letsencrypt keys there + ssl_certificate /etc/nginx/certs/ctfhub.mydomain.com/fullchain.pem; # store letsencrypt keys there + ssl_certificate_key /etc/nginx/certs/ctfhub.mydomain.com/privkey.pem; # store letsencrypt keys there location / { proxy_pass http://app_hedgedoc_server; @@ -116,8 +116,8 @@ http { server { listen 443 ssl; server_name excalidraw.mydomain.com; - ssl_certificate /etc/nginx/certs/ctfpad.mydomain.com/fullchain.pem; # store letsencrypt keys there - ssl_certificate_key /etc/nginx/certs/ctfpad.mydomain.com/privkey.pem; # store letsencrypt keys there + ssl_certificate /etc/nginx/certs/ctfhub.mydomain.com/fullchain.pem; # store letsencrypt keys there + ssl_certificate_key /etc/nginx/certs/ctfhub.mydomain.com/privkey.pem; # store letsencrypt keys there location / { proxy_pass http://app_excalidraw_server; @@ -145,8 +145,8 @@ http { server { listen 443 ssl; server_name collab.excalidraw.mydomain.com; - ssl_certificate /etc/nginx/certs/ctfpad.mydomain.com/fullchain.pem; # store letsencrypt keys there - ssl_certificate_key /etc/nginx/certs/ctfpad.mydomain.com/privkey.pem; # store letsencrypt keys there + ssl_certificate /etc/nginx/certs/ctfhub.mydomain.com/fullchain.pem; # store letsencrypt keys there + ssl_certificate_key /etc/nginx/certs/ctfhub.mydomain.com/privkey.pem; # store letsencrypt keys there location / { proxy_pass http://app_excalidraw_room_server; diff --git a/ctfhub/__init__.py b/ctfhub/__init__.py new file mode 100644 index 0000000..6dd1026 --- /dev/null +++ b/ctfhub/__init__.py @@ -0,0 +1 @@ +default_app_config = "ctfhub.apps.CtfhubConfig" diff --git a/ctfpad/admin.py b/ctfhub/admin.py similarity index 100% rename from ctfpad/admin.py rename to ctfhub/admin.py diff --git a/ctfpad/apps.py b/ctfhub/apps.py similarity index 50% rename from ctfpad/apps.py rename to ctfhub/apps.py index cf33b1e..0792a64 100644 --- a/ctfpad/apps.py +++ b/ctfhub/apps.py @@ -2,9 +2,9 @@ from django.utils.translation import gettext_lazy as _ -class CtfpadConfig(AppConfig): - name = "ctfpad" - verbose_name = _("ctfpad") +class CtfhubConfig(AppConfig): + name = "ctfhub" + verbose_name = _("ctfhub") def ready(self): - import ctfpad.signals + import ctfhub.signals diff --git a/ctfpad/context_processors.py b/ctfhub/context_processors.py similarity index 100% rename from ctfpad/context_processors.py rename to ctfhub/context_processors.py diff --git a/ctfpad/decorators/__init__.py b/ctfhub/decorators/__init__.py similarity index 100% rename from ctfpad/decorators/__init__.py rename to ctfhub/decorators/__init__.py diff --git a/ctfpad/decorators/user.py b/ctfhub/decorators/user.py similarity index 97% rename from ctfpad/decorators/user.py rename to ctfhub/decorators/user.py index 90f247c..7dc9e7a 100644 --- a/ctfpad/decorators/user.py +++ b/ctfhub/decorators/user.py @@ -1,8 +1,8 @@ +from django.contrib import messages from django.http.request import HttpRequest from django.shortcuts import redirect -from django.contrib import messages -from django.utils.http import urlencode from django.urls import reverse +from django.utils.http import urlencode def is_not_authenticated(view_func): @@ -29,7 +29,7 @@ def wrapper_func(request: HttpRequest, *args, **kwargs): if not request.user.is_authenticated: messages.warning(request, "You must be authenticated!") return redirect( - reverse("ctfpad:user-login") + reverse("ctfhub:user-login") + "?" + urlencode({"redirect_to": request.path}) ) diff --git a/ctfpad/forms.py b/ctfhub/forms.py similarity index 99% rename from ctfpad/forms.py rename to ctfhub/forms.py index b07259c..11bb476 100644 --- a/ctfpad/forms.py +++ b/ctfhub/forms.py @@ -1,12 +1,6 @@ import json -from django.contrib.auth.forms import UserChangeForm -from django.contrib.auth.models import User - -from django import forms -from django.core.exceptions import ValidationError -from django.forms import widgets -from ctfpad.models import ( +from ctfhub.models import ( Challenge, ChallengeCategory, ChallengeFile, @@ -15,6 +9,11 @@ Tag, Team, ) +from django import forms +from django.contrib.auth.forms import UserChangeForm +from django.contrib.auth.models import User +from django.core.exceptions import ValidationError +from django.forms import widgets class UserUpdateForm(UserChangeForm): diff --git a/ctfpad/helpers.py b/ctfhub/helpers.py similarity index 94% rename from ctfpad/helpers.py rename to ctfhub/helpers.py index 546f44c..bbdb73f 100644 --- a/ctfpad/helpers.py +++ b/ctfhub/helpers.py @@ -11,13 +11,13 @@ import magic import requests -from ctftools.settings import ( - CTFPAD_ACCEPTED_IMAGE_EXTENSIONS, - CTFPAD_DEFAULT_CTF_LOGO, - CTFPAD_DOMAIN, - CTFPAD_HTTP_REQUEST_DEFAULT_TIMEOUT, - CTFPAD_PORT, - CTFPAD_USE_SSL, +from ctfhub_project.settings import ( + CTFHUB_ACCEPTED_IMAGE_EXTENSIONS, + CTFHUB_DEFAULT_CTF_LOGO, + CTFHUB_DOMAIN, + CTFHUB_HTTP_REQUEST_DEFAULT_TIMEOUT, + CTFHUB_PORT, + CTFHUB_USE_SSL, CTFTIME_API_EVENTS_URL, CTFTIME_USER_AGENT, DISCORD_WEBHOOK_URL, @@ -36,15 +36,15 @@ @lru_cache(maxsize=1) def get_current_site() -> str: - r = "https://" if CTFPAD_USE_SSL else "http://" - r += f"{CTFPAD_DOMAIN}:{CTFPAD_PORT}" + r = "https://" if CTFHUB_USE_SSL else "http://" + r += f"{CTFHUB_DOMAIN}:{CTFHUB_PORT}" return r @lru_cache(maxsize=1) def which_hedgedoc() -> str: """Returns the docker container hostname if the default URL from the config is not accessible. - This is so that ctfpad works out of the box with `docker-compose up` as most people wanting to + This is so that ctfhub works out of the box with `docker-compose up` as most people wanting to trial it out won't bother changing the default values with public FQDN/IPs. Returns: @@ -53,7 +53,7 @@ def which_hedgedoc() -> str: if USE_INTERNAL_HEDGEDOC: return "http://hedgedoc:3000" - requests.get(HEDGEDOC_URL, timeout=CTFPAD_HTTP_REQUEST_DEFAULT_TIMEOUT) + requests.get(HEDGEDOC_URL, timeout=CTFHUB_HTTP_REQUEST_DEFAULT_TIMEOUT) return HEDGEDOC_URL @@ -223,13 +223,13 @@ def ctftime_get_ctf_logo_url(ctftime_id: int) -> str: Returns: str: [description] """ - default_logo = f"{STATIC_URL}images/{CTFPAD_DEFAULT_CTF_LOGO}" + default_logo = f"{STATIC_URL}images/{CTFHUB_DEFAULT_CTF_LOGO}" if ctftime_id != 0: try: ctf_info = ctftime_get_ctf_info(ctftime_id) logo = ctf_info.setdefault("logo", default_logo) _, ext = os.path.splitext(logo) - if ext.lower() not in CTFPAD_ACCEPTED_IMAGE_EXTENSIONS: + if ext.lower() not in CTFHUB_ACCEPTED_IMAGE_EXTENSIONS: return default_logo except ValueError: logo = default_logo diff --git a/ctfpad/migrations/0001_initial.py b/ctfhub/migrations/0001_initial.py similarity index 98% rename from ctfpad/migrations/0001_initial.py rename to ctfhub/migrations/0001_initial.py index 0146804..378e4ce 100644 --- a/ctfpad/migrations/0001_initial.py +++ b/ctfhub/migrations/0001_initial.py @@ -1,13 +1,14 @@ # Generated by Django 3.1.3 on 2020-12-01 18:22 -import ctfpad.helpers -import ctfpad.validators -from django.conf import settings -from django.db import migrations, models +import uuid + +import ctfhub.helpers +import ctfhub.validators import django.db.models.deletion import django.utils.timezone import model_utils.fields -import uuid +from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): @@ -160,7 +161,7 @@ class Migration(migrations.Migration): ( "api_key", models.CharField( - default=ctfpad.helpers.get_random_string_128, max_length=128 + default=ctfhub.helpers.get_random_string_128, max_length=128 ), ), ("avatar", models.ImageField(blank=True, upload_to="media/")), @@ -575,13 +576,13 @@ class Migration(migrations.Migration): blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, - to="ctfpad.ctf", + to="ctfhub.ctf", ), ), ( "team", models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="ctfpad.team" + on_delete=django.db.models.deletion.PROTECT, to="ctfhub.team" ), ), ( @@ -604,7 +605,7 @@ class Migration(migrations.Migration): blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, - to="ctfpad.member", + to="ctfhub.member", ), ), migrations.CreateModel( @@ -627,7 +628,7 @@ class Migration(migrations.Migration): null=True, upload_to="files/", validators=[ - ctfpad.validators.challenge_file_max_size_validator + ctfhub.validators.challenge_file_max_size_validator ], ), ), @@ -638,7 +639,7 @@ class Migration(migrations.Migration): "challenge", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, - to="ctfpad.challenge", + to="ctfhub.challenge", ), ), ], @@ -652,14 +653,14 @@ class Migration(migrations.Migration): field=models.ForeignKey( null=True, on_delete=django.db.models.deletion.DO_NOTHING, - to="ctfpad.challengecategory", + to="ctfhub.challengecategory", ), ), migrations.AddField( model_name="challenge", name="ctf", field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="ctfpad.ctf" + on_delete=django.db.models.deletion.CASCADE, to="ctfhub.ctf" ), ), migrations.AddField( @@ -669,21 +670,21 @@ class Migration(migrations.Migration): null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name="last_updater", - to="ctfpad.member", + to="ctfhub.member", ), ), migrations.AddField( model_name="challenge", name="solvers", field=models.ManyToManyField( - blank=True, related_name="solved_challenges", to="ctfpad.Member" + blank=True, related_name="solved_challenges", to="ctfhub.Member" ), ), migrations.AddField( model_name="challenge", name="tags", field=models.ManyToManyField( - blank=True, related_name="challenges", to="ctfpad.Tag" + blank=True, related_name="challenges", to="ctfhub.Tag" ), ), ] diff --git a/ctfpad/migrations/0002_auto_20210102_1139.py b/ctfhub/migrations/0002_auto_20210102_1139.py similarity index 94% rename from ctfpad/migrations/0002_auto_20210102_1139.py rename to ctfhub/migrations/0002_auto_20210102_1139.py index c804e25..a06254d 100644 --- a/ctfpad/migrations/0002_auto_20210102_1139.py +++ b/ctfhub/migrations/0002_auto_20210102_1139.py @@ -1,12 +1,12 @@ # Generated by Django 3.1.4 on 2021-01-02 11:39 -from django.db import migrations, models import model_utils.fields +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0001_initial"), + ("ctfhub", "0001_initial"), ] operations = [ diff --git a/ctfpad/migrations/0003_auto_20210113_1945.py b/ctfhub/migrations/0003_auto_20210113_1945.py similarity index 78% rename from ctfpad/migrations/0003_auto_20210113_1945.py rename to ctfhub/migrations/0003_auto_20210113_1945.py index 7e5d8f7..d018910 100644 --- a/ctfpad/migrations/0003_auto_20210113_1945.py +++ b/ctfhub/migrations/0003_auto_20210113_1945.py @@ -1,13 +1,14 @@ # Generated by Django 3.1.3 on 2021-01-13 19:45 -import ctfpad.helpers -from django.db import migrations, models import uuid +import ctfhub.helpers +from django.db import migrations, models + class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0002_auto_20210102_1139"), + ("ctfhub", "0002_auto_20210102_1139"), ] operations = [ @@ -20,14 +21,14 @@ class Migration(migrations.Migration): model_name="ctf", name="whiteboard_access_token", field=models.CharField( - default=ctfpad.helpers.get_random_string_64, max_length=64 + default=ctfhub.helpers.get_random_string_64, max_length=64 ), ), migrations.AlterField( model_name="challenge", name="note_id", field=models.CharField( - blank=True, default=ctfpad.helpers.create_new_note, max_length=38 + blank=True, default=ctfhub.helpers.create_new_note, max_length=38 ), ), ] diff --git a/ctfpad/migrations/0004_ctf_note_id.py b/ctfhub/migrations/0004_ctf_note_id.py similarity index 72% rename from ctfpad/migrations/0004_ctf_note_id.py rename to ctfhub/migrations/0004_ctf_note_id.py index a6207ec..d211aae 100644 --- a/ctfpad/migrations/0004_ctf_note_id.py +++ b/ctfhub/migrations/0004_ctf_note_id.py @@ -1,12 +1,12 @@ # Generated by Django 3.1.3 on 2021-01-13 20:21 -import ctfpad.helpers +import ctfhub.helpers from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0003_auto_20210113_1945"), + ("ctfhub", "0003_auto_20210113_1945"), ] operations = [ @@ -14,7 +14,7 @@ class Migration(migrations.Migration): model_name="ctf", name="note_id", field=models.CharField( - blank=True, default=ctfpad.helpers.create_new_note, max_length=38 + blank=True, default=ctfhub.helpers.create_new_note, max_length=38 ), ), ] diff --git a/ctfpad/migrations/0005_auto_20210204_1921.py b/ctfhub/migrations/0005_auto_20210204_1921.py similarity index 92% rename from ctfpad/migrations/0005_auto_20210204_1921.py rename to ctfhub/migrations/0005_auto_20210204_1921.py index d12613f..52108b1 100644 --- a/ctfpad/migrations/0005_auto_20210204_1921.py +++ b/ctfhub/migrations/0005_auto_20210204_1921.py @@ -1,13 +1,13 @@ # Generated by Django 3.1.3 on 2021-02-04 19:21 -from django.db import migrations, models import django.db.models.deletion import model_utils.fields +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0004_ctf_note_id"), + ("ctfhub", "0004_ctf_note_id"), ] operations = [ @@ -30,7 +30,7 @@ class Migration(migrations.Migration): on_delete=django.db.models.deletion.SET_NULL, related_name="players", related_query_name="player", - to="ctfpad.ctf", + to="ctfhub.ctf", ), ), ] diff --git a/ctfpad/migrations/0006_auto_20210329_1218.py b/ctfhub/migrations/0006_auto_20210329_1218.py similarity index 88% rename from ctfpad/migrations/0006_auto_20210329_1218.py rename to ctfhub/migrations/0006_auto_20210329_1218.py index 932a6bb..4ef3416 100644 --- a/ctfpad/migrations/0006_auto_20210329_1218.py +++ b/ctfhub/migrations/0006_auto_20210329_1218.py @@ -1,11 +1,11 @@ # Generated by Django 3.1.7 on 2021-03-29 12:18 -from django.db import migrations import model_utils.fields +from django.db import migrations def set_default_timezone(apps, schema_editor): - Member = apps.get_model("ctfpad", "Member") + Member = apps.get_model("ctfhub", "Member") for member in Member.objects.all(): member.timezone = "UTC" member.save() @@ -13,7 +13,7 @@ def set_default_timezone(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0005_auto_20210204_1921"), + ("ctfhub", "0005_auto_20210204_1921"), ] operations = [ diff --git a/ctfpad/migrations/0007_ctf_rating.py b/ctfhub/migrations/0007_ctf_rating.py similarity index 87% rename from ctfpad/migrations/0007_ctf_rating.py rename to ctfhub/migrations/0007_ctf_rating.py index 7854835..314fc5b 100644 --- a/ctfpad/migrations/0007_ctf_rating.py +++ b/ctfhub/migrations/0007_ctf_rating.py @@ -5,7 +5,7 @@ class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0006_auto_20210329_1218"), + ("ctfhub", "0006_auto_20210329_1218"), ] operations = [ diff --git a/ctfpad/migrations/0008_remove_challenge_whiteboard_id_and_more.py b/ctfhub/migrations/0008_remove_challenge_whiteboard_id_and_more.py similarity index 99% rename from ctfpad/migrations/0008_remove_challenge_whiteboard_id_and_more.py rename to ctfhub/migrations/0008_remove_challenge_whiteboard_id_and_more.py index 78b0caa..d82732c 100644 --- a/ctfpad/migrations/0008_remove_challenge_whiteboard_id_and_more.py +++ b/ctfhub/migrations/0008_remove_challenge_whiteboard_id_and_more.py @@ -1,14 +1,14 @@ # Generated by Django 4.2 on 2023-04-11 17:28 -import ctfpad.helpers +import ctfhub.helpers import django.core.validators -from django.db import migrations, models import model_utils.fields +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("ctfpad", "0007_ctf_rating"), + ("ctfhub", "0007_ctf_rating"), ] operations = [ @@ -24,7 +24,7 @@ class Migration(migrations.Migration): model_name="challenge", name="excalidraw_room_id", field=models.CharField( - default=ctfpad.helpers.generate_excalidraw_room_id, + default=ctfhub.helpers.generate_excalidraw_room_id, validators=[ django.core.validators.RegexValidator( code="nomatch", @@ -38,7 +38,7 @@ class Migration(migrations.Migration): model_name="challenge", name="excalidraw_room_key", field=models.CharField( - default=ctfpad.helpers.generate_excalidraw_room_key, + default=ctfhub.helpers.generate_excalidraw_room_key, validators=[ django.core.validators.RegexValidator( code="nomatch", diff --git a/ctfpad/migrations/__init__.py b/ctfhub/migrations/__init__.py similarity index 100% rename from ctfpad/migrations/__init__.py rename to ctfhub/migrations/__init__.py diff --git a/ctfpad/mixins.py b/ctfhub/mixins.py similarity index 100% rename from ctfpad/mixins.py rename to ctfhub/mixins.py diff --git a/ctfpad/models.py b/ctfhub/models.py similarity index 97% rename from ctfpad/models.py rename to ctfhub/models.py index 5581b31..944911d 100644 --- a/ctfpad/models.py +++ b/ctfhub/models.py @@ -1,55 +1,53 @@ -from typing import OrderedDict -import uuid -import os import hashlib -from urllib.parse import quote +import os +import tempfile +import uuid +import zipfile +from collections import Counter, namedtuple from datetime import datetime, timedelta from pathlib import Path -from collections import namedtuple, Counter from statistics import mean -import zipfile -import requests -import tempfile +from typing import OrderedDict +from urllib.parse import quote +import requests +from ctfhub.helpers import ( + create_new_note, + ctftime_ctfs, + ctftime_get_ctf_logo_url, + generate_excalidraw_room_id, + generate_excalidraw_room_key, + get_file_magic, + get_file_mime, + get_random_string_128, + register_new_hedgedoc_user, +) +from ctfhub.validators import challenge_file_max_size_validator from django.contrib.auth.models import User from django.core.validators import RegexValidator from django.db import models -from django.db.models import Sum, Count, Q +from django.db.models import Count, Q, Sum from django.db.models.functions import TruncMonth from django.urls.base import reverse -from django.utils.text import slugify from django.utils.crypto import get_random_string from django.utils.functional import cached_property -from model_utils.fields import MonitorField, StatusField +from django.utils.text import slugify from model_utils import Choices, FieldTracker +from model_utils.fields import MonitorField, StatusField -from ctfpad.helpers import ctftime_ctfs - -from ctftools.settings import ( +from ctfhub_project.settings import ( + CTF_CHALLENGE_FILE_PATH, + CTF_CHALLENGE_FILE_ROOT, + CTFTIME_URL, EXCALIDRAW_ROOM_ID_REGEX, EXCALIDRAW_ROOM_KEY_REGEX, - HEDGEDOC_URL, EXCALIDRAW_URL, - CTF_CHALLENGE_FILE_PATH, - CTF_CHALLENGE_FILE_ROOT, + HEDGEDOC_URL, + JITSI_URL, STATIC_URL, USERS_FILE_PATH, - CTFTIME_URL, - JITSI_URL, -) -from ctfpad.validators import challenge_file_max_size_validator -from ctfpad.helpers import ( - get_random_string_128, - register_new_hedgedoc_user, - create_new_note, - get_file_magic, - get_file_mime, - ctftime_get_ctf_logo_url, - generate_excalidraw_room_id, - generate_excalidraw_room_key, ) - # Create your models here. @@ -109,7 +107,7 @@ class Ctf(TimeStampedModel): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=128) created_by = models.ForeignKey( - "ctfpad.Member", on_delete=models.CASCADE, blank=True, null=True + "ctfhub.Member", on_delete=models.CASCADE, blank=True, null=True ) url = models.URLField(blank=True) description = models.TextField(blank=True) @@ -283,7 +281,7 @@ def note_url(self) -> str: def get_absolute_url(self): return reverse( - "ctfpad:ctfs-detail", + "ctfhub:ctfs-detail", args=[ str(self.id), ], @@ -1131,7 +1129,7 @@ def last_logged_in(self): @property def hedgedoc_username(self): - return f"{self.username}@ctfpad.localdomain" + return f"{self.username}@ctfhub.localdomain" @property def avatar_url(self): @@ -1188,7 +1186,7 @@ def ctfs(self): def get_absolute_url(self): return reverse( - "ctfpad:users-detail", + "ctfhub:users-detail", args=[ str(self.id), ], @@ -1283,9 +1281,9 @@ class Challenge(TimeStampedModel): ], ) solvers = models.ManyToManyField( - "ctfpad.Member", blank=True, related_name="solved_challenges" + "ctfhub.Member", blank=True, related_name="solved_challenges" ) - tags = models.ManyToManyField("ctfpad.Tag", blank=True, related_name="challenges") + tags = models.ManyToManyField("ctfhub.Tag", blank=True, related_name="challenges") @property def solved(self) -> bool: @@ -1326,7 +1324,7 @@ def save(self, **kwargs): def get_absolute_url(self): return reverse( - "ctfpad:challenges-detail", + "ctfhub:challenges-detail", args=[ str(self.id), ], @@ -1586,7 +1584,7 @@ def search_in_ctfs(cls, query: str) -> list: "ctf", entry.name, description, - reverse("ctfpad:ctfs-detail", kwargs={"pk": entry.id}), + reverse("ctfhub:ctfs-detail", kwargs={"pk": entry.id}), ) ) return results @@ -1614,7 +1612,7 @@ def search_in_challenges(cls, query: str) -> list: "challenge", entry.name, description, - reverse("ctfpad:challenges-detail", kwargs={"pk": entry.id}), + reverse("ctfhub:challenges-detail", kwargs={"pk": entry.id}), ) ) return results @@ -1640,7 +1638,7 @@ def search_in_members(cls, query: str) -> list: "member", entry.username, entry.description, - reverse("ctfpad:users-detail", kwargs={"pk": entry.id}), + reverse("ctfhub:users-detail", kwargs={"pk": entry.id}), ) ) return results @@ -1664,7 +1662,7 @@ def search_in_categories(cls, query: str) -> list: challenge.name, f"{challenge.name} - ({challenge.ctf})", reverse( - "ctfpad:challenges-detail", kwargs={"pk": challenge.id} + "ctfhub:challenges-detail", kwargs={"pk": challenge.id} ), ) ) @@ -1689,7 +1687,7 @@ def search_in_tags(cls, query: str) -> list: challenge.name, f"{challenge.name} - ({challenge.ctf})", reverse( - "ctfpad:challenges-detail", kwargs={"pk": challenge.id} + "ctfhub:challenges-detail", kwargs={"pk": challenge.id} ), ) ) @@ -1713,7 +1711,7 @@ def search_in_ctftime(cls, query: str) -> list: "ctftime", entry["title"], entry["description"], - reverse("ctfpad:ctfs-import") + f"?ctftime_id={entry['id']}", + reverse("ctfhub:ctfs-import") + f"?ctftime_id={entry['id']}", ) ) return results diff --git a/ctfpad/signals.py b/ctfhub/signals.py similarity index 94% rename from ctfpad/signals.py rename to ctfhub/signals.py index 27eedc7..8eb2331 100644 --- a/ctfpad/signals.py +++ b/ctfhub/signals.py @@ -1,11 +1,12 @@ -import random, datetime +import datetime +import random +from ctfhub.helpers import discord_send_message, get_current_site +from ctfhub.models import Challenge, Ctf from django.db.models.signals import post_save from django.dispatch import receiver -from ctfpad.models import Challenge, Ctf -from ctfpad.helpers import discord_send_message, get_current_site -from ctftools.settings import DISCORD_BOT_NAME +from ctfhub_project.settings import DISCORD_BOT_NAME # formatted with the ctf name NEW_CTF_MESSAGES = [ diff --git a/ctfpad/templates/ctfpad/categories/create.html b/ctfhub/templates/ctfhub/categories/create.html similarity index 100% rename from ctfpad/templates/ctfpad/categories/create.html rename to ctfhub/templates/ctfhub/categories/create.html diff --git a/ctfpad/templates/ctfpad/challenges/confirm_delete.html b/ctfhub/templates/ctfhub/challenges/confirm_delete.html similarity index 85% rename from ctfpad/templates/ctfpad/challenges/confirm_delete.html rename to ctfhub/templates/ctfhub/challenges/confirm_delete.html index a9f7c10..9b783d3 100644 --- a/ctfpad/templates/ctfpad/challenges/confirm_delete.html +++ b/ctfhub/templates/ctfhub/challenges/confirm_delete.html @@ -1,4 +1,4 @@ -{% extends 'ctfpad/main.html' %} +{% extends 'ctfhub/main.html' %} {% block content %} @@ -16,10 +16,10 @@

Delete challenge '{{challenge.name}}' ?

Confirm deletion?

-
+ {% csrf_token %}
diff --git a/ctfpad/templates/ctfpad/challenges/create.html b/ctfhub/templates/ctfhub/challenges/create.html similarity index 99% rename from ctfpad/templates/ctfpad/challenges/create.html rename to ctfhub/templates/ctfhub/challenges/create.html index 8e46b2b..51f917c 100644 --- a/ctfpad/templates/ctfpad/challenges/create.html +++ b/ctfhub/templates/ctfhub/challenges/create.html @@ -1,4 +1,4 @@ -{% extends 'ctfpad/main.html' %} +{% extends 'ctfhub/main.html' %} {% block content %} diff --git a/ctfpad/templates/ctfpad/challenges/detail.html b/ctfhub/templates/ctfhub/challenges/detail.html similarity index 95% rename from ctfpad/templates/ctfpad/challenges/detail.html rename to ctfhub/templates/ctfhub/challenges/detail.html index accb516..0e073bb 100644 --- a/ctfpad/templates/ctfpad/challenges/detail.html +++ b/ctfhub/templates/ctfhub/challenges/detail.html @@ -1,11 +1,11 @@ -{% extends 'ctfpad/main.html' %} +{% extends 'ctfhub/main.html' %} {% block content %}
{% include 'snippets/messages.html' %} - {% load ctfpad_filters %} + {% load ctfhub_filters %}
@@ -27,7 +27,7 @@