diff --git a/README.md b/README.md index de5fc65..f0ffa5b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ If you have any issues during installation, file an issue. ## Notes +####reCAPTCHA +Site Key: *6Lc4xhMTAAAAAIaiF3yEWGbHRaGgMg4FHor61p1G* +Secret Key: *6Lc4xhMTAAAAACFaG2NyuKoMdZQtSa_1LI76BCEu* + **Resources** : Flask, MySQL diff --git a/server/api/models.py b/server/api/models.py index c63243f..9f6b7be 100644 --- a/server/api/models.py +++ b/server/api/models.py @@ -4,17 +4,59 @@ import utils db = SQLAlchemy() class Users(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(64)) - username = db.Column(db.String(64), unique=True) - username_lower = db.Column(db.String(64), unique=True) - email = db.Column(db.String(64), unique=True) - password = db.Column(db.String(128)) - admin = db.Column(db.Boolean) + uid = db.Column(db.Integer, primary_key=True) + tid = db.Column(db.Integer) + name = db.Column(db.String(64)) + username = db.Column(db.String(64), unique=True) + username_lower = db.Column(db.String(64), unique=True) + email = db.Column(db.String(64), unique=True) + password = db.Column(db.String(128)) + admin = db.Column(db.Boolean) - def __init__(self, name, username, email, password): - self.name = name - self.username = username - self.username_lower = username.lower() - self.email = email.lower() - self.password = utils.hash_password(password) \ No newline at end of file + def __init__(self, name, username, email, password): + self.name = name + self.username = username + self.username_lower = username.lower() + self.email = email.lower() + self.password = utils.hash_password(password) + +class Teams(db.Model): + tid = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(64), unique=True) + join_code = db.Column(db.String(128), unique=True) + school = db.Column(db.Text) + size = db.Column(db.Integer) + score = db.Column(db.Integer) + observer = db.Column(db.Boolean) + owner = db.Column(db.Integer) + + def __init__(self, name, school): + self.name = name + self.school = school + +class Problems(db.Model): + pid = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(128)) + description = db.Column(db.Text) + hint = db.Column(db.Text) + flag = db.Column(db.Text) + disabled = db.Column(db.Boolean) + value = db.Column(db.Integer) + solves = db.Column(db.Integer) + + def __init__(self, name, description, hint, flag, value): + self.name = name + self.description = description + self.hint = hint + self.flag = flag + self.value = value + +class Solves(db.Model): + sid = db.Column(db.Integer, primary_key=True) + pid = db.Column(db.Integer) + tid = db.Column(db.Integer) + date = db.Column(db.Integer, default=utils.get_time_since_epoch()) + + def __init__(self, pid, tid): + self.pid = pid + self.tid = tid diff --git a/server/api/user.py b/server/api/user.py index 315df69..f80a0db 100644 --- a/server/api/user.py +++ b/server/api/user.py @@ -1,9 +1,61 @@ -from flask import Blueprint +from flask import Blueprint, session, request +from flask import current_app as app + +from models import db, Users from utils import api_wrapper +import utils + blueprint = Blueprint("user", __name__) @blueprint.route("/register", methods=["POST"]) @api_wrapper def user_register(): - return { "success": 0, "message": "Registration is not open yet." } \ No newline at end of file + name = request.form["name"] + username = request.form["username"] + password = request.form["password"] + password_confirm = request.form["password_confirm"] + email = request.form["email"] + + username_exists = Users.query.add_columns("name", "uid").filter_by(username=username).first() + email_exists = Users.query.add_columns("name", "uid").filter_by(email=email).first() + + if password != password_confirm: + return { "success": 0, "message": "Passwords do not match." } + if len(password) > 128: + return { "success": 0, "message": "Password is too long." } + if len(password) == 0: + return { "success": 0, "message": "Password is too short." } + if len(username) > 64: + return { "success": 0, "message": "Username is too long." } + if username_exists: + return { "success": 0, "message": "Username is already taken." } + if email_exists: + return { "success": 0, "message": "Email has already been used." } + + add_user(name, username, email, password) + + return { "success": 1, "message": "Success!" } + +@blueprint.route("/logout", methods=["POST"]) +@api_wrapper +def user_logout(): + session.clear() + +@blueprint.route("/login", methods=["POST"]) +@api_wrapper +def user_login(): + username = request.form["username"] + password = request.form["password"] + user = Users.query.filter_by(username=username).first() + if utils.check_password(user.password, password): + session["username"] = username + session["admin"] = user.admin + return { "success": 1, "message": "Success!" } + else: + return { "success": 0, "message": "Invalid credentials." } + +def add_user(name, username, email, password): + user = Users(name, username, email, password) + db.session.add(user) + db.session.commit() diff --git a/server/api/utils.py b/server/api/utils.py index 8ecbd6a..f638462 100644 --- a/server/api/utils.py +++ b/server/api/utils.py @@ -40,4 +40,4 @@ def api_wrapper(f): traceback.print_exc() web_result = { "success": 0, "message": "Something went wrong! Please notify us about this immediately.", error: traceback.format_exc() } return json.dumps(web_result), response, { "Content-Type": "application/json; charset=utf-8" } - return wrapper \ No newline at end of file + return wrapper diff --git a/server/app.py b/server/app.py index 5d52e6f..447af53 100644 --- a/server/app.py +++ b/server/app.py @@ -6,32 +6,39 @@ import json import api from api.api import api as api_blueprint +from api.user import blueprint as user_blueprint app = Flask(__name__) + +with app.app_context(): + from api.models import db + db.init_app(app) + db.create_all() + app.secret_key = config.SECRET +app.config["SQLALCHEMY_DATABASE_URI"] = config.SQLALCHEMY_DATABASE_URI +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = config.SQLALCHEMY_TRACK_MODIFICATIONS app.register_blueprint(api_blueprint) +app.register_blueprint(user_blueprint, url_prefix="/api/user") @app.route("/api") def api_main(): - return json.dumps({ "success": 1, "message": "The API is online." }) + return json.dumps({ "success": 1, "message": "The API is online." }) if __name__ == "__main__": - with app.app_context(): - parser = ArgumentParser(description="EasyCTF Server Configuration") - parser.add_argument("-d", "--debug", action="store_true", help="Run the server in debug mode.", default=False) - args = parser.parse_args() - keyword_args, _ = dict(args._get_kwargs()), args._get_args() - - app.debug = keyword_args["debug"] - - app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:i_hate_passwords@localhost/easyctf" - app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - - from api.models import db - db.init_app(app) - db.create_all() + with app.app_context(): + parser = ArgumentParser(description="EasyCTF Server Configuration") + parser.add_argument("-d", "--debug", action="store_true", help="Run the server in debug mode.", default=False) + args = parser.parse_args() + keyword_args, _ = dict(args._get_kwargs()), args._get_args() +<<<<<<< HEAD app.register_blueprint(api.admin.blueprint, url_prefix="/api/admin") app.register_blueprint(api.user.blueprint, url_prefix="/api/user") - app.run(host="0.0.0.0", port=8000) \ No newline at end of file + app.run(host="0.0.0.0", port=8000) +======= + app.debug = keyword_args["debug"] + + app.run(host="0.0.0.0", port=8000) +>>>>>>> 6e538e221f28f239512f5c52a7d73ccb0f27576c diff --git a/server/config.py b/server/config.py index 3dd4da5..85f7010 100644 --- a/server/config.py +++ b/server/config.py @@ -10,5 +10,9 @@ with open(".secret_key", "a+") as secret: key = secret.read() SECRET = key + +SQLALCHEMY_DATABASE_URI = "mysql://root:i_hate_passwords@localhost/easyctf" +SQLALCHEMY_TRACK_MODIFICATIONS = False + CTF_BEGIN = 0 # To be used later CTF_END = 0 # To be used later diff --git a/web/about.html b/web/about.html index ef839a6..ea58eb1 100644 --- a/web/about.html +++ b/web/about.html @@ -3,9 +3,35 @@
No, we're not running around in a gym, tagging other players. Capture the flag contests, or CTFs for short, are intense cybersecurity contests where participants try to capture a piece of information. To do this, they must use skills to capture a virtual flag, usually taking the form of a string, like this: flag{this_is_a_flag}
. There are two common types of CTF competitions: jeopardy, and attack-defense.
CTFs are different from the hacking you may hear from the news. While hacking is commonly associated with stealing and destruction, CTFs are all about learning and community.
+ +EasyCTF is a CTF that's tailored for the high school level. Started by high school students, it was created with a passion for learning. The following events have passed, but the site will remain online for historical purposes.
+ +