def register(): if not Config.get().register_open: return error("Registration is closed") username = request.json.get("username", "").strip() if not username: return error("Username is required") user = User.query.filter(User.name == username).first() if user: return error("The user `{}` already exists".format(username)) email = request.json.get("email", "").strip() if not email: return error("Email address is required") user = User.query.filter(User.email == email).first() if user: return error("The email address is already used") # TODO: check email format # TODO check the number of teammates password = request.json.get("password", "").strip() if not password: return error("Password is required") if request.json.get("teamtoken"): token = request.json.get("teamtoken").strip() team = Team.query.filter(Team.token == token, Team.valid == True).first() if not team: return error("Team token is invalid") elif request.json.get("teamname"): teamname = request.json.get("teamname").strip() team = Team.query.filter(Team.name == teamname).first() if team and team.valid: return error("The team `{}` already exists".format(teamname)) team = Team(name=teamname) team.valid = True team.renewToken() db.session.add(team) db.session.commit() else: return error("Either team token or team name is required") user = User() user.name = username user.password = password user.email = email user.team_id = team.id user.verified = False user.issueResetToken() db.session.add(user) db.session.commit() logger.log(":heavy_plus_sign: `{}@{}` registered".format(user.name, user.team.name)) send_verification_mail(user) return jsonify({"id": user.id, "name": user.name})
def challenge_recalc(): """recalc challenge scores""" config = Config.get() # type: Config # commit for chall in Challenge.query.all(): # type: Chall chall.recalc_score(config.score_expr) db.session.add(chall) db.session.commit() print("[+]{}: {}".format(chall.score, chall.name))
def init(): """initialize CTF by yaml file""" # initialize db db.create_all() db.session.commit() ctf = Config.get() or Config() # type: Config ctf.name = app.config["CTF_NAME"] ctf.flag_format = app.config["FLAGFORMAT"] ctf.start_at = int( app.config["START_AT"].timestamp() # - app.config["START_AT"].utcoffset().total_seconds() ) ctf.end_at = int( app.config["END_AT"].timestamp() # - app.config["END_AT"].utcoffset().total_seconds() ) ctf.email = app.config["EMAIL"] ctf.email_password = app.config["EMAIL_PASSWORD"] ctf.invite_url = app.config["INVITE_URL"] ctf.score_expr = app.config["SCORE_EXPR"] ctf.is_open = ctf.is_open or False ctf.register_open = ctf.register_open or False admin = User.query.filter(User.is_admin == True).first() or User() # type: User admin.name = app.config["ADMIN_NAME"] admin.email = "*****@*****.**" admin.verified = True admin.password = app.config["ADMIN_PASSWORD"] admin.is_admin = True # commit db.session.add(ctf) db.session.add(admin) db.session.commit() # print printConfig(ctf)
def open(register, close): """open CTF and/or registration""" config = Config.get() config.register_open = not close if not register: config.is_open = not close # commit db.session.add(config) db.session.commit() # print printConfig(config) print("[+]Done")
def update(): user = get_login_user() config = Config.get() ctf_name = config.name register_open = config.register_open ctf_open = config.ctf_open ctf_frozen = config.ctf_frozen valid_only = not ctf_frozen users = get_users(valid_only=valid_only) teams = get_teams(valid_only=True) r = { "is_login": bool(user), "start_at": datetime.fromtimestamp(config.start_at).isoformat() + "Z", "end_at": datetime.fromtimestamp(config.end_at).isoformat() + "Z", "ctf_name": ctf_name, "flag_format": config.flag_format, "invite_url": config.invite_url, "ctf_open": ctf_open, "ctf_frozen": ctf_frozen, "score_expr": config.score_expr.replace("V", "base_score").replace("N", "solve_count"), "register_open": register_open, "users": users, "teams": teams, "challenges": {}, } if user: userinfo, teaminfo = get_user_and_team(user, valid_only=valid_only) r["user"] = userinfo r["team"] = teaminfo if config.ctf_open or config.ctf_frozen: r["challenges"] = get_challenges(abst=not bool(user)) return jsonify(r)
def send_verification_mail(user: User): config = Config.get() # type: Config body = """Hi, {username} You have just registered {ctf}. Please confirm your email address by visiting the following link. {address} Share your team token with your team members. You can see your team token in the profile page of your team. Thanks, {ctf} Organizers""".format( username=user.name, ctf=config.name, address=os.path.join(request.url_root, "#/confirm/" + user.reset_token), ) subject = "{} registration confirm".format(config.name) sendmail_async(body, subject, user.email, config.email, config.email_password)
def send_passwordreset_mail(user: User): config = Config.get() # type: Config body = """Hi, {username} You have just requested to reset your password for {ctf}. Visit the following link to reset your password: {address} If you did not request a password reset, please ignore this email or reply this email. Thanks, {ctf} Organizers""".format( username=user.name, ctf=config.name, address=os.path.join(request.url_root, "#/reset/" + user.reset_token), ) subject = "{} password reset issue".format(config.name) sendmail_async(body, subject, user.email, config.email, config.email_password)
def register(): teamname = request.json.get("teamname", None) if not teamname: return error("Team name is required") if not Config.get().register_open: return error("Registration is closed") team = Team.query.filter(Team.name == teamname).first() if team and team.valid: return error("The team `{}` already exists".format(teamname)) if not team: team = Team() team.name = teamname team.renewToken() db.session.add(team) db.session.commit() return jsonify({"id": team.id, "name": teamname, "token": team.token})
def wrap(*args, **kwargs): config = Config.get() if not config.is_open: return error("CTF has been closed", 403) return f(*args, **kwargs)
def submit(user): challenge_id = request.json.get("id", None) if not challenge_id: return error("challenge id required") flag = request.json.get("flag", "").strip() if not challenge_id: return error("flag required") c = Challenge.query.filter(Challenge.id == challenge_id, Challenge.is_open == True).first() if c is None: return error("invalid challenge id") if user.team: solves = user.team.getSolves(valid_only=False) team = user.team else: solves = user.getSolves(valid_only=False) team = Team() team.name = "" ids = [solved.id for solved in solves] already_solved = bool(c.id in ids) s = Submission() s.flag = flag s.challenge_id = c.id s.user_id = user.id if user.team: s.team_id = user.team.id if "survey" in c.tags: s.created_at = Config.get().start_at if c.flag == flag and already_solved: logger.log( ":heavy_check_mark: `{}@{}` has submitted flag `{}` to `{}`. It has already solved." .format(user.name, team.name, c.name, flag)) return jsonify({ "message": "Correct, and you or your team already has solved `{}`".format( c.name) }) elif c.flag == flag and not already_solved: config = Config.get() if not config.ctf_frozen: s.is_valid = True s.is_correct = True db.session.add(s) db.session.commit() c.recalc_score(config.score_expr) db.session.add(c) db.session.commit() else: s.is_valid = False s.is_correct = True db.session.add(s) db.session.commit() logger.log( ":heavy_check_mark: `{}@{}` has submitted flag `{}` to `{}`. :100:" .format(user.name, team.name, c.name, flag)) return jsonify({"message": "Correct! You solved `{}`.".format(c.name)}) elif c.flag != flag and already_solved: logger.log( ":x: `{}@{}` has submitted flag `{}` to `{}`. The correct flag is `{}`. This team already solved this challenges." .format(user.name, team.name, c.name, flag, c.flag)) return error( "Wrong flag, but you or your team already has solved `{}`".format( c.name)) else: s.is_valid = False s.is_correct = False db.session.add(s) db.session.commit() logger.log( ":x: `{}@{}` has submitted flag `{}` to `{}`. The correct flag is `{}`" .format(user.name, team.name, c.name, flag, c.flag)) return error("Wrong flag")