mirror of https://github.com/EasyCTF/librectf
194 lines
5.8 KiB
Python
194 lines
5.8 KiB
Python
import json
|
|
import os
|
|
|
|
from flask import (
|
|
Blueprint,
|
|
abort,
|
|
current_app,
|
|
flash,
|
|
redirect,
|
|
render_template,
|
|
url_for,
|
|
)
|
|
from flask_login import current_user, login_required
|
|
|
|
from easyctf.decorators import block_before_competition, team_required, no_cache
|
|
from easyctf.forms.chals import ProblemSubmitForm, ProgrammingSubmitForm
|
|
from easyctf.models import AutogenFile, Job, Problem, Solve, User, WrongFlag
|
|
from easyctf.objects import cache, db, sentry
|
|
|
|
blueprint = Blueprint("chals", __name__, template_folder="templates")
|
|
|
|
|
|
@blueprint.route("/list", methods=["GET", "POST"])
|
|
@login_required
|
|
@team_required
|
|
@block_before_competition
|
|
def list():
|
|
problem_submit_form = ProblemSubmitForm()
|
|
if problem_submit_form.validate_on_submit():
|
|
problem = Problem.get_by_id(int(problem_submit_form.pid.data))
|
|
if problem is None or not current_user.team.has_unlocked(problem):
|
|
flash("Problem not found.", "info")
|
|
return redirect(url_for("chals.list"))
|
|
|
|
result, message = problem.try_submit(problem_submit_form.flag.data)
|
|
|
|
if result == "success":
|
|
flash(message, "success")
|
|
elif result == "error":
|
|
flash(message, "info")
|
|
if result == "failure":
|
|
flash(message, "danger")
|
|
return redirect(url_for("chals.list"))
|
|
categories = Problem.categories()
|
|
if current_user.admin:
|
|
problems = Problem.query.filter(Problem.value > 0).order_by(Problem.value).all()
|
|
else:
|
|
problems = current_user.team.get_unlocked_problems()
|
|
return render_template(
|
|
"chals/list.html",
|
|
categories=categories,
|
|
problems=problems,
|
|
problem_submit_form=problem_submit_form,
|
|
)
|
|
|
|
|
|
@blueprint.route("/solves/<int:pid>")
|
|
@login_required
|
|
@team_required
|
|
@block_before_competition
|
|
def solves(pid):
|
|
problem = Problem.query.filter_by(pid=pid).first()
|
|
if problem is None:
|
|
abort(404)
|
|
return render_template("chals/solves.html", problem=problem)
|
|
|
|
|
|
@blueprint.route("/shell")
|
|
@block_before_competition
|
|
@team_required
|
|
@login_required
|
|
def shell():
|
|
return render_template("chals/shell.html")
|
|
|
|
|
|
@blueprint.route("/shell/credentials")
|
|
@block_before_competition
|
|
@team_required
|
|
@login_required
|
|
def shell_credentials():
|
|
team = current_user.team
|
|
credentials = team.credentials()
|
|
if not credentials:
|
|
return abort(500)
|
|
username, password = credentials
|
|
return json.dumps(dict(username=username, password=password))
|
|
|
|
|
|
@blueprint.route("/programming/")
|
|
@blueprint.route("/programming/<int:pid>", methods=["GET", "POST"])
|
|
@login_required
|
|
@team_required
|
|
@block_before_competition
|
|
def programming(pid=None):
|
|
problems = current_user.team.get_unlocked_problems(programming=True)
|
|
if pid is None:
|
|
if len(problems) == 0:
|
|
return redirect(url_for("chals.list"))
|
|
return redirect(url_for("chals.programming", pid=problems[0].pid))
|
|
problem = Problem.get_by_id(pid)
|
|
if not problem:
|
|
return abort(404)
|
|
if not current_user.team.has_unlocked(problem) or not problem.programming:
|
|
return redirect(url_for("chals.list"))
|
|
|
|
programming_submit_form = ProgrammingSubmitForm()
|
|
if programming_submit_form.validate_on_submit():
|
|
if not problem.programming:
|
|
return redirect(url_for("chals.list"))
|
|
job = Job(
|
|
uid=current_user.uid,
|
|
tid=current_user.tid,
|
|
pid=pid,
|
|
language=programming_submit_form.language.data,
|
|
contents=programming_submit_form.code.data,
|
|
)
|
|
db.session.add(job)
|
|
db.session.commit()
|
|
flash("Code was sent! Refresh the page for updates.", "success")
|
|
return redirect(url_for("chals.submission", id=job.id))
|
|
|
|
return render_template(
|
|
"chals/programming.html",
|
|
problem=problem,
|
|
problems=problems,
|
|
programming_submit_form=programming_submit_form,
|
|
)
|
|
|
|
|
|
@blueprint.route("/programming/status")
|
|
@login_required
|
|
@team_required
|
|
@block_before_competition
|
|
def status():
|
|
jobs = (
|
|
Job.query.filter_by(tid=current_user.tid).order_by(Job.submitted.desc()).all()
|
|
)
|
|
return render_template("chals/status.html", jobs=jobs)
|
|
|
|
|
|
@blueprint.route("/programming/submission/<int:id>")
|
|
@login_required
|
|
@team_required
|
|
@block_before_competition
|
|
def submission(id):
|
|
job = Job.query.filter_by(id=id).first()
|
|
if not job:
|
|
return abort(404)
|
|
if not current_user.admin and job.tid != current_user.tid:
|
|
return abort(403)
|
|
return render_template(
|
|
"chals/submission.html", problem=job.problem, job=job, user=job.user
|
|
)
|
|
|
|
|
|
@blueprint.route("/autogen/<int:pid>/<filename>")
|
|
@login_required
|
|
@team_required
|
|
@block_before_competition
|
|
@no_cache
|
|
def autogen(pid, filename):
|
|
problem = Problem.query.filter_by(pid=pid).first()
|
|
if not problem or not problem.autogen:
|
|
return abort(404)
|
|
|
|
tid = current_user.tid
|
|
# If autogen file exists in db, redirect to filestore
|
|
autogen_file = AutogenFile.query.filter_by(
|
|
pid=pid, tid=tid, filename=filename
|
|
).first()
|
|
if autogen_file:
|
|
return redirect(
|
|
"{}/{}".format(current_app.config["FILESTORE_STATIC"], autogen_file.url)
|
|
)
|
|
|
|
current_path = os.getcwd()
|
|
if problem.path:
|
|
os.chdir(problem.path)
|
|
autogen = problem.get_autogen(tid)
|
|
grader = problem.get_grader()
|
|
generated_problem = grader.generate(autogen)
|
|
if "files" in generated_problem:
|
|
data = generated_problem["files"].get(filename)
|
|
if data is None:
|
|
return abort(404)
|
|
autogen_file = AutogenFile(pid=pid, tid=tid, filename=filename, data=data)
|
|
db.session.add(autogen_file)
|
|
db.session.commit()
|
|
return redirect(
|
|
"{}/{}".format(current_app.config["FILESTORE_STATIC"], autogen_file.url)
|
|
)
|
|
os.chdir(current_path)
|
|
return abort(404)
|