Skip to content

Commit

Permalink
Add doc string
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexis committed Aug 12, 2024
1 parent 72649b8 commit 97e9f0c
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 64 deletions.
45 changes: 31 additions & 14 deletions CTFd-Unique_flags/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,53 @@ class UniqueFlag(CTFdStaticFlag):

@staticmethod
def compare(chal_key_obj, provided_flag):
"""
Compare the provided flag to the saved flag
Args:
chal_key_obj: A CTFd.models.Flags object
provided_flag: A string provided by the user
Returns:
bool: Whether or not the provided flag is correct
"""
# Get the actual flag to check for the challenge submitted (the function compare() is called for each flag of the challenge)

saved_flag = chal_key_obj.content
curr_team_id = get_current_team().id

if len(saved_flag) != len(provided_flag):
return False

result = 0

for x, y in zip(saved_flag, provided_flag):
result |= ord(x) ^ ord(y)


if result == 0:
team_id = chal_key_obj.data
if int(team_id) == int(curr_team_id):
return True
else:
curr_user_id = get_current_user().id
cheater = CheaterTeams(challengeid=chal_key_obj.challenge_id, cheaterid=curr_user_id, cheatteamid=curr_team_id, sharerteamid=team_id, flagid=chal_key_obj.id)
db.session.add(cheater)
return False
else:
if result != 0:
return False

# Check if the team id of the player is the same as the team id of the flag data
# True = the flag is correct and the player is in the right team
# False = the flag is correct but the player is not in the right team
team_id = chal_key_obj.data
if int(team_id) == int(curr_team_id):
return True

# The player is not in the right team, so we add the record in the cheater_teams table
curr_user_id = get_current_user().id
cheater = CheaterTeams(challengeid=chal_key_obj.challenge_id, cheaterid=curr_user_id, cheatteamid=curr_team_id, sharerteamid=team_id, flagid=chal_key_obj.id)
db.session.add(cheater)
return False



def load(app):

"""
Load the plugin into CTFd
Creates the database table and registers the blueprint
"""
app.db.create_all()
app.register_blueprint(plugin_blueprint)

Expand Down
36 changes: 36 additions & 0 deletions CTFd-Unique_flags/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
from CTFd.models import db, Challenges

class CheaterTeams(db.Model):
"""
Model for the cheater_teams table
Columns:
id (int): The ID of the record
challengeid (int): The ID of the challenge
cheaterid (int): The ID of the cheater
cheatteamid (int): The ID of the team that maybe cheated
sharerteamid (int): The ID of the team that shared the flag
flagid (int): The ID of the flag
date (datetime): The date of the record creation
"""

__tablename__ = 'cheater_teams'

id = db.Column(db.Integer, primary_key=True)
Expand All @@ -15,23 +28,46 @@ class CheaterTeams(db.Model):
date = db.Column(db.DateTime, default=db.func.current_timestamp())

def __init__(self, challengeid, cheaterid, cheatteamid, sharerteamid, flagid):
""" Initializes the CheaterTeams object
Args:
challengeid (int): The ID of the challenge
cheaterid (int): The ID of the cheater
cheatteamid (int): The ID of the team that maybe cheated
sharerteamid (int): The ID of the team that shared the flag
flagid (int): The ID of the flag
"""
self.challengeid = challengeid
self.cheaterid = cheaterid
self.cheatteamid = cheatteamid
self.sharerteamid = sharerteamid
self.flagid = flagid

def __repr__(self):
"""
Returns the string representation of the CheaterTeams object
"""
return "<CheaterTeams Team {0} maybe cheated for challenge {1} with the flag {2} belonging to the team {3} at {4} >".format(self.cheatteamid, self.challengeid, self.flagid, self.sharerteamid, self.date)

def cheated_team_name(self):
"""
Get the name of the team that maybe cheated
"""
return Teams.query.filter_by(id=self.cheatteamid).first().name

def shared_team_name(self):
"""
Get the name of the team that shared the flag
"""
return Teams.query.filter_by(id=self.sharerteamid).first().name

def challenge_name(self):
"""
Get the name of the challenge
"""
return Challenges.query.filter_by(id=self.challengeid).first().name

def cheater_name(self):
"""
Get the name of the cheater
"""
return Users.query.filter_by(id=self.cheaterid).first().email
15 changes: 15 additions & 0 deletions CTFd-Unique_flags/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
@plugin_blueprint.route("/admin/unique-flag", methods=["GET", "POST"])
@admins_only
def home():
""" Import unique flags or show the unique flags administration page
Returns:
render_template: Render the admin-import.html template or redirects to the unique_flags.home page
"""
infos = get_infos()
errors = get_errors()

Expand All @@ -38,6 +43,11 @@ def home():
@plugin_blueprint.route("/admin/unique-flag/delete-flags", methods=["POST"])
@admins_only
def delete_flags():
""" Deletes all unique flags or flags of a specific challenge
Returns:
redirection: Redirects to the unique_flags.home page
"""
if request.form.get('challenge_id') is None:
count = Flags.query.filter_by(type="uniqueflag").delete()
else:
Expand All @@ -53,4 +63,9 @@ def delete_flags():
@plugin_blueprint.route("/admin/unique-flag/cheating-monitor", methods=["GET"])
@admins_only
def view_cheater():
""" View the cheater teams
Returns:
render_template: Render the cheat-monitor.html template
"""
return render_template('cheat-monitor.html', cheaters=CheaterTeams.query.all())
20 changes: 19 additions & 1 deletion CTFd-Unique_flags/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,31 @@
from CTFd.models import Teams, Flags, db

def getTeamID(classe, groupe):
"""
Get the ID of a team from its class and group
Args:
classe (string)
groupe (string)
Returns:
int: The ID of the team
"""
team_name = f"Team-{classe.upper()}-{int(groupe):02}"
result = Teams.query.filter_by(name=team_name).first()
return "Error" if result is None else result.id


def importFlag(csv_content):
"""
Import flags from a CSV file into the database
Args:
csv_content (string): The content of the CSV file (Check assets/example.csv) to see the format
Returns:
A list of infos and a list of errors
"""
infos = get_infos()
errors = get_errors()

Expand All @@ -23,7 +41,7 @@ def importFlag(csv_content):
errors.append("You need at least the columns 'CLASS', 'GROUP', 'FLAG', 'CHALLENGE_ID'.")
return infos, errors

previous_team = "" # Cette variable permet de ne pas demander plusieurs fois à la base de données l'ID de l'équipe si la classe et le groupe n'ont pas changé.
previous_team = "" # This variable is used to avoid multiple queries to the database

flags = []
for row in csvreader:
Expand Down
3 changes: 3 additions & 0 deletions CTFd-Universal_flag_submitter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@


def load(app):
"""
Load the plugin into CTFd and registers the blueprint
"""

app.register_blueprint(plugin_blueprint)

Expand Down
51 changes: 12 additions & 39 deletions CTFd-Universal_flag_submitter/decorators.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,27 @@
import functools
from CTFd.utils import get_config
from flask import abort

import contextlib
import os
from flask import abort, redirect, render_template, request, url_for
from flask import abort, request
from CTFd.utils.user import (
authed,
get_current_team,
get_current_user
)
from CTFd.utils import config, get_config
from CTFd.utils.logging import log
from CTFd.models import db
from flask import Blueprint
from CTFd.utils.decorators import admins_only

from CTFd.models import Teams, Flags, db
from CTFd.models import (
ChallengeFiles,
Challenges,
Fails,
Flags,
Hints,
Solves,
Tags,
db,
)
from CTFd.utils.helpers import info_for, error_for

from CTFd.utils import user as current_user
from CTFd.utils.user import get_current_team, get_current_user
from CTFd.utils import config, get_config, set_config
from CTFd.utils.dates import ctf_ended, ctf_paused, ctftime
from CTFd.plugins.challenges import CHALLENGE_CLASSES, get_chal_class
from flask import render_template, Blueprint, request
from CTFd.utils.decorators import admins_only

from CTFd.utils.helpers import get_errors, get_infos
from .utils import add_fail, add_solves
from CTFd.cache import (
cache,
clear_challenges,
clear_config,
clear_pages,
clear_standings,
)
from CTFd.utils import config, get_config
from CTFd.utils.dates import ctf_paused, ctftime
from flask import request



def is_allowed_to_attempt(f):
"""
Decorator to check if the user is allowed to submit a flag.
"""

@functools.wraps(f)
def is_allowed_to_attempt_wrapper(*args, **kwargs):
Expand All @@ -55,18 +30,16 @@ def is_allowed_to_attempt_wrapper(*args, **kwargs):
if authed() is False:
return (
{"success": False,
"message": "Veuillez vous authentifier.",
"message": "You must be logged in to access to this feature.",
"design": "neutral"
},
403,
)



if config.is_teams_mode() and get_current_team() is None:
return (
{"success": False,
"message": "veuillez d'abord rejoindre une équipe.",
"message": "Please create or join a team to submit flags.",
"design": "neutral"
},
403,
Expand Down
11 changes: 10 additions & 1 deletion CTFd-Universal_flag_submitter/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@
@require_complete_profile
@during_ctf_time_only
@require_verified_emails
#@require_team
def attempt_hidden_challenge():
"""
Attempt to solve a hidden challenge
Returns:
dict: A dictionary containing the success status, message, and design
"""
chall = db.session.query(Challenges).filter(Challenges.state == "visible").all()

if len(chall) == 0:
Expand Down Expand Up @@ -59,7 +65,10 @@ def attempt_hidden_challenge():
@plugin_blueprint.route("/admin/hide-challenge", methods=["GET", "POST"])
@admins_only
def home():

"""
Hide challenges from the challenge list and show hidden challenges administration page
"""

if request.method == "GET":
infos = get_infos()
errors = get_errors()
Expand Down
10 changes: 6 additions & 4 deletions CTFd-Universal_flag_submitter/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

def add_submission(submission_type, challenge_id, request):
"""
Générique pour ajouter une soumission de fail ou solve.
submission_type: 'fail' ou 'solve' pour déterminer le type de soumission.
challenge_id: ID du challenge concerné.
request: objet de requête Flask.
Generic function to add a submission to the database
Args:
submission_type (string): The type of submission to add
challenge_id (int): The ID of the challenge
request: The request object
"""

# Récupérer l'utilisateur
Expand Down
5 changes: 5 additions & 0 deletions CTFd-Writeup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
from CTFd.utils import config, get_config, set_config

def load(app):
"""
Load the plugin into CTFd, registers the blueprint and creates the database table
Overrides the challenge.html template if the plugin is enabled
"""

app.db.create_all()
app.register_blueprint(plugin_blueprint)
dir_path = Path(__file__).parent.resolve()
Expand Down
4 changes: 1 addition & 3 deletions CTFd-Writeup/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

def plugin_enabled(f):
"""
Decorator that requires the plugin enabled
:param f:
:return:
Decorator to prevent access to a route if the plugin is disabled
"""
@functools.wraps(f)
def plugin_enabled_wrapper(*args, **kwargs):
Expand Down
3 changes: 3 additions & 0 deletions CTFd-Writeup/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@


class WriteupModel(db.Model):
"""
Model for the writeups table
"""
__tablename__ = "writeups"
id = Column(Integer, ForeignKey('challenges.id', ondelete="CASCADE"), primary_key=True)
content = Column(Text)
Expand Down
Loading

0 comments on commit 97e9f0c

Please sign in to comment.