def reassign_teams(include_assigned=False): db = api.common.get_conn() if include_assigned: teams = api.team.get_all_teams(include_ineligible=True) else: teams = list( db.teams.find({"server_number": { "$exists": False }}, { "_id": 0, "tid": 1 })) for team in teams: old_server_number = team.get("server_number") server_number = get_assigned_server_number(new_team=False, tid=team["tid"]) if old_server_number != server_number: db.teams.update( {'tid': team["tid"]}, {'$set': { 'server_number': server_number, 'instances': {} }}) # Re-assign instances safe_fail(api.problem.get_visible_problems, team["tid"]) return len(teams)
def check_question(question=None, answer=None, data=None): data = join_kwargs(data, question=question, answer=answer) data['question'] = int(data['question']) validate(submission_schema, data) num = data.pop('question') answer = data.pop('answer') question = safe_fail(get_question, num=num) if not question: raise InternalException('Question not found') correct = question['answer'] in answer solved = safe_fail(has_solved, question['qid']) with get_conn() as cursor: uid = session['uid'] points = question['success'] if correct else -question['failure'] query = 'INSERT INTO `submissions` (`uid`, `qid`, `answer`, `points`, `correct`) VALUES (%s, %s, %s, %s, %s);' args = (uid, question['qid'], answer, points if not solved else 0, 1 if correct else 0) cursor.execute(query, args) if correct: return WebSuccess('Correct!', data={'url': get_next_question_url()}) else: return WebError('Incorrect')
def insert_problem(problem, sid=None): """ Inserts a problem into the database. Does sane validation. Args: Problem dict. score: points awarded for completing the problem. category: problem's category author: author of the problem description: description of the problem. Optional: version: version of the problem tags: list of problem tags. hints: hints for completing the problem. organization: Organization that author is associated with Returns: The newly created problem id. """ if sid is None: raise InternalException("Must provide an sid to insert problem.") db = api.common.get_conn() validate(problem_schema, problem) # initially disable problems problem["disabled"] = True problem["pid"] = api.common.hash("{}-{}".format(problem["name"], problem["author"])) for instance in problem["instances"]: validate(instance_schema, instance) set_instance_ids(problem, sid) if safe_fail(get_problem, pid=problem["pid"]) is not None: # problem is already inserted, so update instead old_problem = copy(get_problem(pid=problem["pid"])) # leave all instances from different shell server instances = list(filter(lambda i: i["sid"] != sid, old_problem["instances"])) # add instances from this shell server instances.extend(problem["instances"]) problem["instances"] = instances # disable problems with zero instances problem["disabled"] = old_problem["disabled"] or len(problem["instances"]) == 0 # run the update update_problem(problem["pid"], problem) return if safe_fail(get_problem, name=problem["name"]) is not None: raise WebException("Problem with identical name \"{}\" already exists.".format(problem["name"])) db.problems.insert(problem) api.cache.fast_cache.clear() return problem["pid"]
def reassign_teams(include_assigned=False): db = api.common.get_conn() if include_assigned: teams = api.team.get_all_teams(show_ineligible=True) else: teams = list( db.teams.find({ "server_number": { "$exists": False } }, { "_id": 0, "tid": 1 })) for team in teams: old_server_number = team.get("server_number") server_number = get_assigned_server_number( new_team=False, tid=team["tid"]) if old_server_number != server_number: db.teams.update({ 'tid': team["tid"] }, {'$set': { 'server_number': server_number, 'instances': {} }}) # Re-assign instances safe_fail(api.problem.get_visible_problems, team["tid"]) return len(teams)
def insert_achievement(achievement): """ Inserts an achievement object into the database. Args: achievement: the achievement object loaded from json. Returns: The achievment's aid. """ db = api.common.get_conn() validate(achievement_schema, achievement) achievement["disabled"] = achievement.get("disabled", False) achievement["aid"] = api.common.hash(achievement["name"]) if safe_fail(get_achievement, aid=achievement["aid"]) is not None: raise WebException("achievement with identical aid already exists.") if safe_fail(get_achievement, name=achievement["name"]) is not None: raise WebException("achievement with identical name already exists.") db.achievements.insert(achievement) api.cache.fast_cache.clear() return achievement["aid"]
def insert_problem(problem, sid=None): """ Inserts a problem into the database. Does sane validation. Args: Problem dict. score: points awarded for completing the problem. category: problem's category author: author of the problem description: description of the problem. Optional: version: version of the problem tags: list of problem tags. hints: hints for completing the problem. organization: Organization that author is associated with Returns: The newly created problem id. """ db = api.common.get_conn() validate(problem_schema, problem) # initially disable problems problem["disabled"] = True problem["pid"] = api.common.hash("{}-{}".format(problem["name"], problem["author"])) for instance in problem["instances"]: validate(instance_schema, instance) set_instance_ids(problem, sid) if safe_fail(get_problem, pid=problem["pid"]) is not None: # problem is already inserted, so update instead old_problem = copy(get_problem(pid=problem["pid"])) # leave all instances from different shell server instances = list(filter(lambda i: i["sid"] != sid, old_problem["instances"])) # add instances from this shell server instances.extend(problem["instances"]) problem["instances"] = instances # disable problems with zero instances problem["disabled"] = old_problem["disabled"] or len(problem["instances"]) == 0 # run the update update_problem(problem["pid"], problem) return if safe_fail(get_problem, name=problem["name"]) is not None: raise WebException("Problem with identical name \"{}\" already exists.".format(problem["name"])) db.problems.insert(problem) api.cache.fast_cache.clear() return problem["pid"]
def insert_problem(problem): """ Inserts a problem into the database. Does sane validation. Args: Problem dict. score: points awarded for completing the problem. category: problem's category description: description of the problem. grader: path relative to grader_base_path threshold: Amount of points necessary for a team to unlock this problem. Optional: disabled: True or False. Defaults to False. hint: hint for completing the problem. tags: list of problem tags. relatedproblems: list of related problems. weightmap: problem's unlock weightmap autogen: Whether or not the problem will be auto generated. Returns: The newly created problem id. """ db = api.common.get_conn() validate(problem_schema, problem) problem["disabled"] = problem.get("disabled", False) problem["pid"] = api.common.hash(problem["name"]) weightmap = {} if problem.get("weightmap"): for name, weight in problem["weightmap"].items(): name_hash = api.common.hash(name) weightmap[name_hash] = weight problem["weightmap"] = weightmap if safe_fail(get_problem, pid=problem["pid"]) is not None: raise WebException("Problem with identical pid already exists.") if safe_fail(get_problem, name=problem["name"]) is not None: raise WebException("Problem with identical name already exists.") db.problems.insert(problem) api.cache.fast_cache.clear() return problem["pid"]
def authorize_role(role=None): """ This route is used to ensure sensitive static content is witheld from withheld from clients. """ if role == "user" and safe_fail(api.user.get_user): return "Client is logged in.", 200 elif role == "teacher" and safe_fail(api.user.is_teacher): return "Client is a teacher.", 200 elif role == "admin" and safe_fail(api.user.is_admin): return "Client is an administrator.", 200 elif role == "anonymous": return "Client is authorized.", 200 else: return "Client is not authorized.", 401
def login(username, password): """ Authenticates a user. """ # Read in submitted username and password validate(user_login_schema, { "username": username, "password": password }) user = safe_fail(api.user.get_user, name=username) if user is None: raise WebException("Incorrect username.") if user.get("disabled", False): raise WebException("This account has been disabled.") if confirm_password(password, user['password_hash']): if debug_disable_general_login: if session.get('debugaccount', False): raise WebException("Correct credentials! But the game has not started yet...") if user['uid'] is not None: session['uid'] = user['uid'] session.permanent = True else: raise WebException("Login Error") else: raise WebException("Incorrect password")
def create_group_request(params, uid=None): """ Creates a new group. Validates forms. All required arguments are assumed to be keys in params. Args: group-name: The name of the group Optional: uid: The uid of the user creating the group. If omitted, the uid will be grabbed from the logged in user. Returns: The new gid """ if uid is None: uid = api.user.get_user()["uid"] validate(register_group_schema, params) if safe_fail(get_group, name=params["group-name"], owner_uid=uid) is not None: raise WebException("A class with that name already exists!") return create_group(uid, params["group-name"])
def join_group_request(params, tid=None): """ Tries to place a team into a group. Validates forms. All required arguments are assumed to be keys in params. Args: group-name: The name of the group to join. group-owner: The name of the owner of the group Optional: tid: If omitted,the tid will be grabbed from the logged in user. """ owner_uid = api.user.get_user(name=params["group-owner"])["uid"] validate(join_group_schema, params) if safe_fail(get_group, name=params["group-name"], owner_uid=owner_uid) is None: raise WebException("No class exists with that name!") group = get_group(name=params["group-name"], owner_uid=owner_uid) if tid is None: tid = api.user.get_team()["tid"] if tid in group['members']: raise WebException("Your team is already a member of that class!") join_group(tid, group["gid"])
def update_server(sid, params): """ Update a shell server from the pool of servers. Args: sid: The sid of the server to update params: A dict containing: port username password """ db = api.common.get_conn() validate(server_schema, params) server = safe_fail(get_server, sid=sid) if server is None: raise WebException( "Shell server with sid '{}' does not exist.".format(sid)) params["name"] = server["name"] validate(server_schema, params) if isinstance(params["port"], str): params["port"] = int(params["port"]) db.shell_servers.update({"sid": server["sid"]}, {"$set": params})
def request_password_reset(username): """ Emails a user a link to reset their password. Checks that a username was submitted to the function and grabs the relevant team info from the db. Generates a secure token and inserts it into the team's document as 'password_reset_token'. A link is emailed to the registered email address with the random token in the url. The user can go to this link to submit a new password, if the token submitted with the new password matches the db token the password is hashed and updated in the db. Args: username: the username of the account """ validate(password_reset_request_schema, {"username": username}) user = safe_fail(api.user.get_user, name=username) if user is None: raise WebException("No registration found for '{}'.".format(username)) token = api.common.token() api.user.set_password_reset_token(user['uid'], token) msgBody = """We recently received a request to reset the password for the following {0} account:\n\n\t{2}\n\nOur records show that this is the email address used to register the above account. If you did not request to reset the password for the above account then you need not take any further steps. If you did request the password reset please follow the link below to set your new password. \n\n {1}/reset#{3} \n\n Best of luck! \n\n ~The {0} Team """.format(api.config.competition_name, api.config.competition_urls[0], username, token) send_email(user['email'], "{} Password Reset".format(api.config.competition_name), msgBody)
def update_server(sid, params): """ Update a shell server from the pool of servers. Args: sid: The sid of the server to update params: A dict containing: port username password """ db = api.common.get_conn() validate(server_schema, params) server = safe_fail(get_server, sid=sid) if server is None: raise WebException("Shell server with sid '{}' does not exist.".format(sid)) params["name"] = server["name"] validate(server_schema, params) if isinstance(params["port"], str): params["port"] = int(params["port"]) db.shell_servers.update({"sid": server["sid"]}, {"$set": params})
def add_server(params): """ Add a shell server to the pool of servers. Args: params: A dict containing: host port username password Returns: The sid. """ db = api.common.get_conn() validate(server_schema, params) if isinstance(params["port"], str): params["port"] = int(params["port"]) if safe_fail(get_server, name=params["name"]) is not None: raise WebException("Shell server with this name already exists") params["sid"] = api.common.hash(params["name"]) db.shell_servers.insert(params) return params["sid"]
def delete_group_request(params, uid=None): """ Tries to delete a group. Validates forms. All required arguments are assumed to be keys in params. Args: group-name: The name of the group to join. Optional: uid: If omitted, the uid will be grabbed from the logged in user. """ validate(delete_group_schema, params) if uid is None: uid = api.user.get_user()['uid'] if safe_fail(get_group, name=params['group-name'], owner_uid=uid) is None: raise WebException("No class exists with that name!") if uid is None: uid = api.user.get_user()["uid"] group = get_group(name=params["group-name"], owner_uid=uid) delete_group(group['gid'])
def update_problem(pid, updated_problem): """ Updates a problem with new properties. Args: pid: the pid of the problem to update. updated_problem: an updated problem object. Returns: The updated problem object. """ db = api.common.get_conn() if updated_problem.get("name", None) is not None: if safe_fail(get_problem, name=updated_problem["name"]) is not None: raise WebException("Problem with identical name already exists.") problem = get_problem(pid=pid, show_disabled=True).copy() problem.update(updated_problem) # pass validation by removing/readding pid problem.pop("pid", None) validate(problem_schema, problem) problem["pid"] = pid db.problems.update({"pid": pid}, problem) api.cache.fast_cache.clear() return problem
def create_user(username, firstname, lastname, email, password_hash, tid, teacher=False, country="US", admin=False, verified=False): """ This inserts a user directly into the database. It assumes all data is valid. Args: username: user's username firstname: user's first name lastname: user's last name email: user's email password_hash: a hash of the user's password tid: the team id to join teacher: whether this account is a teacher Returns: Returns the uid of the newly created user """ db = api.common.get_conn() settings = api.config.get_settings() uid = api.common.token() if safe_fail(get_user, name=username) is not None: raise InternalException("User already exists!") max_team_size = api.config.get_settings()["max_team_size"] updated_team = db.teams.find_and_modify( query={"tid": tid, "size": {"$lt": max_team_size}}, update={"$inc": {"size": 1}}, new=True) if not updated_team: raise InternalException("There are too many users on this team!") #All teachers are admins. if admin or db.users.count() == 0: admin = True teacher = True user = { 'uid': uid, 'firstname': firstname, 'lastname': lastname, 'username': username, 'email': email, 'password_hash': password_hash, 'tid': tid, 'teacher': teacher, 'admin': admin, 'disabled': False, 'country': country, 'verified': not settings["email"]["email_verification"] or verified, } db.users.insert(user) if settings["email"]["email_verification"] and not user["verified"]: api.email.send_user_verification_email(username) return uid
def test_create_user_request_general_validation(self): """ Tests the registration form validation functionality. Covers: partially: user.create_user_request """ #Generally invalidate every length requirement for bad_length_mod in [0, 200]: for user_blueprint in [self.new_team_user, self.existing_team_user]: for key in user_blueprint.keys(): sheep_user = user_blueprint.copy() #Make sure to keep the basic properties if key == "create-new-team": continue elif key == "email": sheep_user[key] = "x@x." + "x" * bad_length_mod else: sheep_user[key] = "A" * bad_length_mod if sheep_user["create-new-team"] != "true" and \ safe_fail(api.team.get_team, name=sheep_user["team-name-existing"]) is None: team = self.base_team.copy() team['team_name'], team['password'] = \ sheep_user["team-name-existing"], sheep_user["team-password-existing"] api.team.create_team(team) with pytest.raises(WebException): api.user.create_user_request(sheep_user) assert False, "Validation failed to catch {} length {}".format(bad_length_mod, key)
def login(username, password): """ Authenticates a user. """ # Read in submitted username and password validate(user_login_schema, {"username": username, "password": password}) user = safe_fail(api.user.get_user, name=username) if user is None: raise WebException("Incorrect username.") if user.get("disabled", False): raise WebException("This account has been disabled.") if confirm_password(password, user['password_hash']): if debug_disable_general_login: if session.get('debugaccount', False): raise WebException( "Correct credentials! But the game has not started yet...") if user['uid'] is not None: session['uid'] = user['uid'] session.permanent = True else: raise WebException("Login Error") else: raise WebException("Incorrect Password")
def delete_group_request(params, uid=None): """ Tries to delete a group. Validates forms. All required arguments are assumed to be keys in params. Args: group-name: The name of the group to join. Optional: uid: If omitted, the uid will be grabbed from the logged in user. """ validate(delete_group_schema, params) if uid is None: uid = api.user.get_user()["uid"] if safe_fail(get_group, name=params["group-name"], owner_uid=uid) is None: raise WebException("No class exists with that name!") if uid is None: uid = api.user.get_user()["uid"] group = get_group(name=params["group-name"], owner_uid=uid) delete_group(group["gid"])
def join_group_hook(): """ Tries to place a team into a group. Validates forms. All required arguments are assumed to be keys in params. """ params = api.common.flat_multi(request.form) validate(join_group_schema, params) owner_team = api.team.get_team(name=params["group-owner"]) if safe_fail(api.group.get_group, name=params["group-name"], owner_tid=owner_team["tid"]) is None: raise WebException("No class exists with that name!") group = api.group.get_group(name=params["group-name"], owner_tid=owner_team["tid"]) group_settings = api.group.get_group_settings(gid=group["gid"]) team = api.team.get_team() for member_uid in api.team.get_team_uids(tid=team["tid"]): member = api.user.get_user(uid=member_uid) if not api.user.verify_email_in_whitelist(member["email"], group_settings["email_filter"]): raise WebException( "{}'s email does not belong to the whitelist for that group. Your team may not join this group at this time.".format( member["username"] ) ) roles = api.group.get_roles_in_group(group["gid"], tid=team["tid"]) if roles["teacher"] or roles["member"]: raise WebException("Your team is already a member of that class!") api.group.join_group(group["gid"], team["tid"]) return WebSuccess("Successfully joined group")
def request_password_reset(username): """ Emails a user a link to reset their password. Checks that a username was submitted to the function and grabs the relevant team info from the db. Generates a secure token and inserts it into the team's document as 'password_reset_token'. A link is emailed to the registered email address with the random token in the url. The user can go to this link to submit a new password, if the token submitted with the new password matches the db token the password is hashed and updated in the db. Args: username: the username of the account """ validate(password_reset_request_schema, {"username":username}) user = safe_fail(api.user.get_user, name=username) if user is None: raise WebException("No registration found for '{}'.".format(username)) token = api.common.token() api.user.set_password_reset_token(user['uid'], token) msgBody = """We recently received a request to reset the password for the following {0} account:\n\n\t{2}\n\nOur records show that this is the email address used to register the above account. If you did not request to reset the password for the above account then you need not take any further steps. If you did request the password reset please follow the link below to set your new password. \n\n {1}/reset#{3} \n\n Best of luck! \n\n ~The {0} Team """.format(api.config.competition_name, api.config.competition_urls[0], username, token) send_email(user['email'], "{} Password Reset".format(api.config.competition_name), msgBody)
def join_group_request(params, tid=None): """ Tries to place a team into a group. Validates forms. All required arguments are assumed to be keys in params. Args: group-name: The name of the group to join. group-owner: The name of the owner of the group Optional: tid: If omitted,the tid will be grabbed from the logged in user. """ owner_uid = api.user.get_user(name=params["group-owner"])["uid"] validate(join_group_schema, params) if safe_fail(get_group, name=params["group-name"], owner_uid=owner_uid) is None: raise WebException("No class exists with that name!") group = get_group(name=params["group-name"], owner_uid=owner_uid) if tid is None: tid = api.user.get_team()["tid"] if tid in group["members"]: raise WebException("Your team is already a member of that class!") join_group(tid, group["gid"])
def update_achievement(aid, updated_achievement): """ Updates a achievement with new properties. Args: aid: the aid of the achievement to update. updated_achievement: an updated achievement object. Returns: The updated achievement object. """ db = api.common.get_conn() if updated_achievement.get("name", None) is not None: if safe_fail(get_achievement, name=updated_achievement["name"]) is not None: raise WebException("Achievement with identical name already exists.") achievement = get_achievement(aid=aid, show_disabled=True).copy() achievement.update(updated_achievement) # pass validation by removing/readding aid achievement.pop("aid") validate(achievement_schema, achievement) achievement["aid"] = aid db.achievements.update({"aid": aid}, achievement) api.cache.fast_cache.clear() return achievement
def analyze_problems(): """ Checks the sanity of inserted problems. Includes weightmap and grader verification. Returns: A list of error strings describing the problems. """ grader_missing_error = "{}: Missing grader at '{}'." unknown_weightmap_pid = "{}: Has weightmap entry '{}' which does not exist." problems = get_all_problems() errors = [] for problem in problems: if not isfile(join(grader_base_path, problem["grader"])): errors.append( grader_missing_error.format(problem["name"], problem["grader"])) for pid in problem["weightmap"].keys(): if safe_fail(get_problem, pid=pid) is None: errors.append( unknown_weightmap_pid.format(problem["name"], pid)) return errors
def insert_problem(problem): """ Inserts a problem into the database. Does sane validation. Args: Problem dict. score: points awarded for completing the problem. category: problem's category author: author of the problem description: description of the problem. Optional: version: version of the problem tags: list of problem tags. hints: hints for completing the problem. organization: Organization that author is associated with Returns: The newly created problem id. """ db = api.common.get_conn() validate(problem_schema, problem) for instance in problem["instances"]: validate(instance_schema, instance) # initially disable problems problem["disabled"] = True problem["pid"] = api.common.hash("{}-{}".format(problem["name"], problem["author"])) if safe_fail(get_problem, pid=problem["pid"]) is not None: # problem is already inserted, so update instead old_problem = get_problem(pid=problem["pid"]) problem["disabled"] = old_problem["disabled"] assert len(problem["instances"]) >= len(old_problem["instances"]), "Cannot update problem with fewer instances." update_problem(problem["pid"], problem) return if safe_fail(get_problem, name=problem["name"]) is not None: raise WebException("Problem with identical name \"{}\" already exists.".format(problem["name"])) db.problems.insert(problem) api.cache.fast_cache.clear() return problem["pid"]
def join_group_hook(): """ Tries to place a team into a group. Validates forms. All required arguments are assumed to be keys in params. """ params = api.common.flat_multi(request.form) validate(join_group_schema, params) owner_team = safe_fail(api.team.get_team, name=params["group-owner"]) if not owner_team: raise WebException("No teacher exists with that name!") if safe_fail(api.group.get_group, name=params["group-name"], owner_tid=owner_team["tid"]) is None: raise WebException("No classroom exists with that name!") group = api.group.get_group(name=params["group-name"], owner_tid=owner_team["tid"]) group_settings = api.group.get_group_settings(gid=group["gid"]) team = api.team.get_team() if group_settings["email_filter"]: for member_uid in api.team.get_team_uids(tid=team["tid"]): member = api.user.get_user(uid=member_uid) if not api.user.verify_email_in_whitelist( member["email"], group_settings["email_filter"]): raise WebException( "{}'s email does not belong to the whitelist for that classroom. Your team may not join this classroom at this time." .format(member["username"])) roles = api.group.get_roles_in_group(group["gid"], tid=team["tid"]) if roles["teacher"] or roles["member"]: raise WebException("Your team is already a member of that classroom!") api.group.join_group(group["gid"], team["tid"]) return WebSuccess("Successfully joined classroom")
def test_unicode_fields(self): """ Ensures that unicode characters will work in user and team fields """ team_name = u"Team \N{GREEK CAPITAL LETTER DELTA}" username = u"User \u039B" user1 = self.new_team_user.copy() user2 = self.existing_team_user.copy() user1["username"] = username user1["team-name-new"] = team_name user2["team-name-existing"] = team_name api.user.create_user_request(user1) api.user.create_user_request(user2) assert safe_fail(api.user.get_user, name=username) is not None, "Cannot look up unicode username" assert safe_fail(api.team.get_team, name=team_name) is not None, "Cannot look up unicode team name"
def check_create_username(username): """ Ensures that the username is not already used and raises and error if it is Args: username: username to check Returns: Nothing """ if safe_fail(get_user, name=username) is not None: raise InternalException("User already exists!")
def create_user(username, firstname, lastname, email, password_hash, tid, teacher=False, background="undefined", country="undefined", receive_ctf_emails=False): """ This inserts a user directly into the database. It assumes all data is valid. Args: username: user's username firstname: user's first name lastname: user's last name email: user's email password_hash: a hash of the user's password tid: the team id to join teacher: whether this account is a teacher Returns: Returns the uid of the newly created user """ db = api.common.get_conn() uid = api.common.token() if safe_fail(get_user, name=username) is not None: raise InternalException("User already exists!") updated_team = db.teams.find_and_modify( query={"tid": tid, "size": {"$lt": api.team.max_team_users}}, update={"$inc": {"size": 1}}, new=True) if not updated_team: raise InternalException("There are too many users on this team!") user = { 'uid': uid, 'firstname': firstname, 'lastname': lastname, 'username': username, 'email': email, 'password_hash': password_hash, 'tid': tid, 'teacher': teacher, 'avatar': 3, 'eventid': 0, 'disabled': False, 'level': 'Not Started', 'background': background, 'country': country, 'receive_ctf_emails': receive_ctf_emails } db.users.insert(user) return uid
def is_logged_in(): """ Check if the user is currently logged in. Returns: True if the user is logged in, false otherwise. """ logged_in = "uid" in session if logged_in and not safe_fail(api.user.get_user, uid=session["uid"]): logout() return False return logged_in
def is_logged_in(): """ Check if the user is currently logged in. Returns: True if the user is logged in, false otherwise. """ logged_in = "uid" in session if logged_in: user = safe_fail(api.user.get_user, uid=session["uid"]) if not user or user["disabled"]: logout() return False return logged_in
def test_unicode_fields(self): """ Ensures that unicode characters will work in user and team fields """ team_name = u"Team \N{GREEK CAPITAL LETTER DELTA}" username = u"User \u039B" user1 = self.new_team_user.copy() user2 = self.existing_team_user.copy() user1["username"] = username user1["team-name-new"] = team_name user2["team-name-existing"] = team_name api.user.create_user_request(user1) api.user.create_user_request(user2) assert safe_fail( api.user.get_user, name=username) is not None, "Cannot look up unicode username" assert safe_fail( api.team.get_team, name=team_name) is not None, "Cannot look up unicode team name"
def get_next_question_url(num=None, uid=None): if not num: if not uid: if 'uid' not in session: raise InternalException('Need uid to see next') uid = session['uid'] scores = api.user.get_user_scores() num = scores['num'] or 0 next_question = safe_fail(get_question, num=int(num)+1) if not next_question: url = '/survived' else: url = 'question%d'%(next_question['num'], ) return url
def create_group_hook(): """ Creates a new group. Validates forms. All required arguments are assumed to be keys in params. """ params = api.common.flat_multi(request.form) validate(register_group_schema, params) # Current user is the prospective owner. team = api.user.get_team() if safe_fail(api.group.get_group, name=params["group-name"], owner_tid=team["tid"]) is not None: raise WebException("A group with that name already exists!") gid = api.group.create_group(team["tid"], params["group-name"]) return WebSuccess("Successfully created group.", data=gid)
def login(username=None, password=None, data=None): data = join_kwargs(data, username=username, password=password) validate(login_schema, data) username = data.pop('username') password = data.pop('password') user = safe_fail(get_user, name=username) if user is not None and confirm_password(password, user['password_hash']): if user['uid'] is not None: session['uid'] = user['uid'] session.permanent = True else: raise WebException('Login error') else: raise WebException('Username or password incorrect')
def insert_bundle(bundle): """ Inserts the bundle into the database after validating it with the bundle_schema """ db = api.common.get_conn() validate(bundle_schema, bundle) bid = api.common.hash("{}-{}".format(bundle["name"], bundle["author"])) if safe_fail(get_bundle, bid) is not None: # bundle already exists, update it instead update_bundle(bid, bundle) return bundle["bid"] = bid bundle["dependencies_enabled"] = False db.bundles.insert(bundle)
def login(username, password): """ Authenticates a user. """ # Read in submitted username and password validate(user_login_schema, {"username": username, "password": password}) user = safe_fail(api.user.get_user, name=username) if user is None: raise WebException("Incorrect username.") if user.get("disabled", False): raise WebException("This account has been disabled.") if not user["verified"]: raise WebException("This account has not been verified yet.") if confirm_password(password, user['password_hash']): if not user["verified"]: try: api.email.send_user_verification_email(username) raise WebException( "This account is not verified. An additional email has been sent to {}.". format(user["email"])) except InternalException as e: raise WebException( "You have hit the maximum number of verification emails. Please contact support." ) if debug_disable_general_login: if session.get('debugaccount', False): raise WebException( "Correct credentials! But the game has not started yet...") if user['uid'] is not None: session['uid'] = user['uid'] session.permanent = True else: raise WebException("Login Error") else: raise WebException("Incorrect password")
def login(username, password): """ Authenticates a user. """ # Read in submitted username and password validate(user_login_schema, {"username": username, "password": password}) user = safe_fail(api.user.get_user, name=username) if user is None: raise WebException("Incorrect username.") if user.get("disabled", False): raise WebException("This account has been disabled.") if not user["verified"]: raise WebException("This account has not been verified yet.") if confirm_password(password, user['password_hash']): if not user["verified"]: try: api.email.send_user_verification_email(username) raise WebException( "This account is not verified. An additional email has been sent to {}." .format(user["email"])) except InternalException as e: raise WebException( "You have hit the maximum number of verification emails. Please contact support." ) if debug_disable_general_login: if session.get('debugaccount', False): raise WebException( "Correct credentials! But the game has not started yet...") if user['uid'] is not None: session['uid'] = user['uid'] session.permanent = True else: raise WebException("Login Error") else: raise WebException("Incorrect password")
def add_server(params): """ Add a shell server to the pool of servers. First server is automatically assigned server_number 1 (yes, 1-based numbering) if not otherwise specified. Args: params: A dict containing: host port username password server_number Returns: The sid. """ db = api.common.get_conn() validate(server_schema, params) if isinstance(params["port"], str): params["port"] = int(params["port"]) if isinstance(params.get("server_number"), str): params["server_number"] = int(params["server_number"]) if safe_fail(get_server, name=params["name"]) is not None: raise WebException("Shell server with this name already exists") params["sid"] = api.common.hash(params["name"]) # Automatically set first added server as server_number 1 if db.shell_servers.count() == 0: params["server_number"] = params.get("server_number", 1) db.shell_servers.insert(params) return params["sid"]
def test_create_user_request_general_validation(self): """ Tests the registration form validation functionality. Covers: partially: user.create_user_request """ #Generally invalidate every length requirement for bad_length_mod in [0, 200]: for user_blueprint in [ self.new_team_user, self.existing_team_user ]: for key in user_blueprint.keys(): sheep_user = user_blueprint.copy() #Make sure to keep the basic properties if key == "create-new-team": continue elif key == "email": sheep_user[key] = "x@x." + "x" * bad_length_mod else: sheep_user[key] = "A" * bad_length_mod if sheep_user["create-new-team"] != "true" and \ safe_fail(api.team.get_team, name=sheep_user["team-name-existing"]) is None: team = self.base_team.copy() team['team_name'], team['password'] = \ sheep_user["team-name-existing"], sheep_user["team-password-existing"] api.team.create_team(team) with pytest.raises(WebException): api.user.create_user_request(sheep_user) assert False, "Validation failed to catch {} length {}".format( bad_length_mod, key)
def analyze_problems(): """ Checks the sanity of inserted problems. Includes weightmap and grader verification. Returns: A list of error strings describing the problems. """ grader_missing_error = "{}: Missing grader at '{}'." unknown_weightmap_pid = "{}: Has weightmap entry '{}' which does not exist." problems = get_all_problems() errors = [] for problem in problems: if not isfile(join(grader_base_path, problem["grader"])): errors.append(grader_missing_error.format(problem["name"], problem["grader"])) for pid in problem["weightmap"].keys(): if safe_fail(get_problem, pid=pid) is None: errors.append(unknown_weightmap_pid.format(problem["name"], pid)) return errors
("Email must be between 5 and 50 characters.", [str, Length(min=5, max=50)]), ("Your email does not look like an email address.", [_check_email_format]) ), Required('firstname'): check( ("First Name must be between 1 and 50 characters.", [str, Length(min=1, max=50)]) ), Required('lastname'): check( ("Last Name must be between 1 and 50 characters.", [str, Length(min=1, max=50)]) ), Required('country'): check( ("Please select a country", [str, Length(min=2, max=2)]) ), Required('username'): check( ("Usernames must be between 3 and 20 characters.", [str, Length(min=3, max=20)]), ("This username already exists.", [ lambda name: safe_fail(get_user, name=name) is None]) ), Required('password'): check(("Passwords must be between 3 and 20 characters.", [str, Length(min=3, max=20)]) ), Required('background'): check(("You must provide your background!", [str, Length(min=3, max=20)]) ) }, extra=True) new_eligible_team_schema = Schema({ Required('team-name-new'): check( ("The team name must be between 3 and 40 characters.", [str, Length(min=3, max=40)]), ("A team with that name already exists.", [ lambda name: safe_fail(api.team.get_team, name=name) is None]) ),