def validate_name(self, data): name = data.get("name") if name is None: return name = name.strip() existing_user = Users.query.filter_by(name=name).first() current_user = get_current_user() if is_admin(): user_id = data.get("id") if user_id: if existing_user and existing_user.id != user_id: raise ValidationError("Имя пользователя уже занято", field_names=["name"]) else: if existing_user: if current_user: if current_user.id != existing_user.id: raise ValidationError( "Имя пользователя уже занято", field_names=["name"]) else: raise ValidationError("Имя пользователя уже занято", field_names=["name"]) else: if name == current_user.name: return data else: name_changes = get_config("name_changes", default=True) if bool(name_changes) is False: raise ValidationError("Изменение имени отключено", field_names=["name"]) if existing_user: raise ValidationError("Имя пользователя уже занято", field_names=["name"])
def get(self, query_args): q = query_args.pop("q", None) field = str(query_args.pop("field", None)) filters = build_model_filters(model=Users, query=q, field=field) if is_admin() and request.args.get("view") == "admin": users = (Users.query.filter_by(**query_args).filter( *filters).paginate(per_page=50, max_per_page=100)) else: users = (Users.query.filter_by( banned=False, hidden=False, **query_args).filter(*filters).paginate(per_page=50, max_per_page=100)) response = UserSchema(view="user", many=True).dump(users.items) if response.errors: return {"success": False, "errors": response.errors}, 400 return { "meta": { "pagination": { "page": users.page, "next": users.next_num, "prev": users.prev_num, "pages": users.pages, "per_page": users.per_page, "total": users.total, } }, "success": True, "data": response.data, }
def post(self, team_id): team = Teams.query.filter_by(id=team_id).first_or_404() # Generate an invite code if no user or body is specified if len(request.data) == 0: invite_code = team.get_invite_code() response = {"code": invite_code} return {"success": True, "data": response} data = request.get_json() user_id = data.get("user_id") user = Users.query.filter_by(id=user_id).first_or_404() if user.team_id is None: team.members.append(user) db.session.commit() else: return ( { "success": False, "errors": {"id": ["User has already joined a team"]}, }, 400, ) view = "admin" if is_admin() else "user" schema = TeamSchema(view=view) response = schema.dump(team) if response.errors: return {"success": False, "errors": response.errors}, 400 members = response.data.get("members") return {"success": True, "data": members}
def validate_email(self, data): email = data.get("email") if email is None: return existing_team = Teams.query.filter_by(email=email).first() if is_admin(): team_id = data.get("id") if team_id: if existing_team and existing_team.id != team_id: raise ValidationError( "Email address has already been used", field_names=["email"]) else: if existing_team: raise ValidationError( "Email address has already been used", field_names=["email"]) else: current_team = get_current_team() if email == current_team.email: return data else: if existing_team: raise ValidationError( "Email address has already been used", field_names=["email"])
def validate_captain_id(self, data): captain_id = data.get("captain_id") if captain_id is None: return if is_admin(): team_id = data.get("id") if team_id: target_team = Teams.query.filter_by(id=team_id).first() else: target_team = get_current_team() captain = Users.query.filter_by(id=captain_id).first() if captain in target_team.members: return else: raise ValidationError("Invalid Captain ID", field_names=["captain_id"]) else: current_team = get_current_team() current_user = get_current_user() if current_team.captain_id == current_user.id: return else: raise ValidationError( "Only the captain can change team captain", field_names=["captain_id"], )
def request_new_challenge(challenge_id): if is_admin(): challenge = OracleChallenges.query.filter( Challenges.id == challenge_id).first_or_404() else: challenge = OracleChallenges.query.filter( OracleChallenges.id == challenge_id, and_(Challenges.state != "hidden", Challenges.state != "locked"), ).first_or_404() data = request.form or request.get_json() team_id = get_current_team().id force_new = data["force_new"] try: r = requests.post( str(challenge.oracle) + "/create", json={ "team_id": team_id, "force_new": force_new }, ) except requests.exceptions.ConnectionError: return "ERROR: Challenge oracle is not available. Talk to an admin." if r.status_code != 200: return "ERROR: Challenge oracle is not available. Talk to an admin." return r.text
def integrations(): if is_admin() or is_setup() is False: name = request.values.get("name") state = request.values.get("state") try: state = unserialize(state, max_age=3600) except (BadSignature, BadTimeSignature): state = False except Exception: state = False if state: if name == "mlc": mlc_client_id = request.values.get("mlc_client_id") mlc_client_secret = request.values.get("mlc_client_secret") set_config("oauth_client_id", mlc_client_id) set_config("oauth_client_secret", mlc_client_secret) return render_template("admin/integrations.html") else: abort(404) else: abort(403) else: abort(403)
def validate_email(self, data): email = data.get('email') if email is None: return existing_user = Users.query.filter_by(email=email).first() user_id = data.get('id') if user_id and is_admin(): if existing_user and existing_user.id != user_id: raise ValidationError('Email address has already been used', field_names=['email']) else: current_user = get_current_user() if email == current_user.email: return data else: if existing_user: raise ValidationError( 'Email address has already been used', field_names=['email']) if check_email_is_whitelisted(email) is False: raise ValidationError( "Only email addresses under {domains} may register". format(domains=get_config('domain_whitelist')), field_names=['email']) if get_config('verify_emails'): current_user.verified = False
def _check_score_visibility(*args, **kwargs): v = get_config("score_visibility") if v == "public": return f(*args, **kwargs) elif v == "private": if authed(): return f(*args, **kwargs) else: if request.content_type == "application/json": abort(403) else: return redirect( url_for("auth.login", next=request.full_path)) elif v == "hidden": return ( render_template("errors/403.html", error="Scores are currently hidden"), 403, ) elif v == "admins": if is_admin(): return f(*args, **kwargs) else: abort(404)
def get(self, team_id): if team_id == 'me': if not authed(): abort(403) team = get_current_team() else: if accounts_visible() is False or scores_visible() is False: abort(404) team = Teams.query.filter_by(id=team_id).first_or_404() awards = team.get_awards( admin=is_admin() ) schema = AwardSchema(many=True) response = schema.dump(awards) if response.errors: return { 'success': False, 'errors': response.errors }, 400 return { 'success': True, 'data': response.data }
def validate_name(self, data): name = data.get('name') if name is None: return existing_user = Users.query.filter_by(name=name).first() if is_admin(): user_id = data.get('id') if user_id: if existing_user and existing_user.id != user_id: raise ValidationError('User name has already been taken', field_names=['name']) else: if existing_user: raise ValidationError('User name has already been taken', field_names=['name']) else: current_user = get_current_user() if name == current_user.name: return data else: name_changes = get_config('name_changes', default=True) if bool(name_changes) is False: raise ValidationError('Name changes are disabled', field_names=['name']) if existing_user: raise ValidationError('User name has already been taken', field_names=['name'])
def validate_password_confirmation(self, data): password = data.get("password") confirm = data.get("confirm") target_user = get_current_user() if is_admin(): pass else: if password and (bool(confirm) is False): raise ValidationError( "Please confirm your current password", field_names=["confirm"] ) if password and confirm: test = verify_password( plaintext=confirm, ciphertext=target_user.password ) if test is True: return data else: raise ValidationError( "Your previous password is incorrect", field_names=["confirm"] ) else: data.pop("password", None) data.pop("confirm", None)
def multi_scoreboard(sb=None): if sb == None: sb = 'Global' infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Scoreboard has been frozen") if is_admin() is True and scores_visible() is False: infos.append("Scores are not currently visible to users") standings = get_standings() teams = [] scoreboards = ["Global"] for t in Teams.query.all(): if sb == "Global" and (t.name not in teams): teams.append(t.name) for f in t.fields: if f.name not in scoreboards: scoreboards.append(f.name) if f.name == sb and (t.name not in teams): teams.append(t.name) if sb not in scoreboards: abort(404) filtered_standings = [st for st in standings if st[2] in teams] return render_template("multi_scoreboard.html", standings=filtered_standings, infos=infos, scoreboards=scoreboards, scoreboard=sb)
def get(cls, user, challenge): if is_teams_mode() and not is_admin(): return cls.query.filter_by(team_id=user.team_id, challenge_id=challenge.id).first() else: return cls.query.filter_by(user_id=user.id, challenge_id=challenge.id).first()
def unique_email(email, model=Users): obj = model.query.filter_by(email=email).first() if is_admin(): if obj: raise ValidationError('Email address has already been used') if obj and obj.id != get_current_user().id: raise ValidationError('Email address has already been used')
def validate_password_confirmation(self, data): password = data.get('password') confirm = data.get('confirm') if is_admin(): pass else: current_team = get_current_team() current_user = get_current_user() if current_team.captain_id != current_user.id: raise ValidationError( 'Only the captain can change the team password', field_names=['captain_id']) if password and (bool(confirm) is False): raise ValidationError('Please confirm your current password', field_names=['confirm']) if password and confirm: test = verify_password(plaintext=confirm, ciphertext=current_team.password) if test is True: return data else: raise ValidationError( 'Your previous password is incorrect', field_names=['confirm']) else: data.pop('password', None) data.pop('confirm', None)
def _require_complete_profile(*args, **kwargs): if authed(): if is_admin(): return f(*args, **kwargs) else: user = get_current_user() if user.filled_all_required_fields is False: info_for( "views.settings", "Please fill out all required profile fields before continuing", ) return redirect(url_for("views.settings")) if is_teams_mode(): team = get_current_team() if team and team.filled_all_required_fields is False: # This is an abort because it's difficult for us to flash information on the teams page return abort( 403, description= "Please fill in all required team profile fields", ) return f(*args, **kwargs) else: # Fallback to whatever behavior the route defaults to return f(*args, **kwargs)
def validate_captain_id(self, data): captain_id = data.get('captain_id') # if captain_id is None: # return if is_admin(): return # team_id = data.get('id') # if team_id: # target_team = Teams.query.filter_by(id=team_id).first() # else: # target_team = get_current_team() # captain = Users.query.filter_by(id=captain_id).first() # if captain in target_team.members: # return # else: # raise ValidationError('Invalid Captain ID', field_names=['captain_id']) else: if captain_id is None: return current_team = get_current_team() current_user = get_current_user() if current_team.captain_id == current_user.id: return else: raise ValidationError( 'Only the captain can change team captain', field_names=['captain_id'])
def validate_password_confirmation(self, data): password = data.get("password") confirm = data.get("confirm") target_user = get_current_user() if is_admin(): pass else: if password and (bool(confirm) is False): raise ValidationError( "请确认您当前的密码", field_names=["confirm"] ) if password and confirm: test = verify_password( plaintext=confirm, ciphertext=target_user.password ) if test is True: return data else: raise ValidationError( "当前密码输入错误", field_names=["confirm"] ) else: data.pop("password", None) data.pop("confirm", None)
def get(self, hint_id): user = get_current_user() hint = Hints.query.filter_by(id=hint_id).first_or_404() view = "unlocked" if hint.cost: view = "locked" unlocked = HintUnlocks.query.filter_by(account_id=user.account_id, target=hint.id).first() if unlocked: view = "unlocked" solved = Solves.query.filter_by( account_id=user.account_id, challenge_id=hint.challenge_id).first() is not None if solved: view = "unlocked" if is_admin(): if request.args.get("preview", False): view = "admin" response = HintSchema(view=view).dump(hint) if response.errors: return {"success": False, "errors": response.errors}, 400 return {"success": True, "data": response.data}
def validate_name(self, data): name = data.get('name') if name is None: return existing_team = Teams.query.filter_by(name=name).first() # Admins should be able to patch anyone but they cannot cause a collision. if is_admin(): team_id = int(data.get('id', 0)) if team_id: if existing_team and existing_team.id != team_id: raise ValidationError('Team name has already been taken', field_names=['name']) else: # If there's no Team ID it means that the admin is creating a team with no ID. if existing_team: raise ValidationError('Team name has already been taken', field_names=['name']) else: current_team = get_current_team() # We need to allow teams to edit themselves and allow the "conflict" if data['name'] == current_team.name: return data else: name_changes = get_config('name_changes', default=True) if bool(name_changes) is False: raise ValidationError('Name changes are disabled', field_names=['name']) if existing_team: raise ValidationError('Team name has already been taken', field_names=['name'])
def _check_score_visibility(*args, **kwargs): v = get_config(ConfigTypes.SCORE_VISIBILITY) if v == ScoreVisibilityTypes.PUBLIC: return f(*args, **kwargs) elif v == ScoreVisibilityTypes.PRIVATE: if authed(): return f(*args, **kwargs) else: if request.content_type == "application/json": abort(403) else: return redirect(url_for("auth.login", next=request.full_path)) elif v == ScoreVisibilityTypes.HIDDEN: return ( render_template("errors/403.html", error="Scores are currently hidden"), 403, ) elif v == ScoreVisibilityTypes.ADMINS: if is_admin(): return f(*args, **kwargs) else: abort(404)
def validate_password_confirmation(self, data): password = data.get("password") confirm = data.get("confirm") if is_admin(): pass else: current_team = get_current_team() current_user = get_current_user() if current_team.captain_id != current_user.id: raise ValidationError( "Only the captain can change the team password", field_names=["captain_id"], ) if password and (bool(confirm) is False): raise ValidationError("Please confirm your current password", field_names=["confirm"]) if password and confirm: test_team = verify_password(plaintext=confirm, ciphertext=current_team.password) test_captain = verify_password( plaintext=confirm, ciphertext=current_user.password) if test_team is True or test_captain is True: return data else: raise ValidationError( "Your previous password is incorrect", field_names=["confirm"]) else: data.pop("password", None) data.pop("confirm", None)
def get(self, challenge_id): response = [] challenge = Challenges.query.filter_by(id=challenge_id).first_or_404() # TODO: Need a generic challenge visibility call. # However, it should be stated that a solve on a gated challenge is not considered private. if challenge.state == 'hidden' and is_admin() is False: abort(404) Model = get_model() solves = Solves.query.join(Model, Solves.account_id == Model.id)\ .filter(Solves.challenge_id == challenge_id, Model.banned == False, Model.hidden == False)\ .order_by(Solves.date.asc()) for solve in solves: response.append({ 'account_id': solve.account_id, 'name': solve.account.name, 'date': isoformat(solve.date) }) return { 'success': True, 'data': response }
def get(self): user = get_current_user() fails = user.get_fails(admin=True) view = "user" if not is_admin() else "admin" response = SubmissionSchema(view=view, many=True).dump(fails) if response.errors: return {"success": False, "errors": response.errors}, 400 if is_admin(): data = response.data else: data = [] count = len(response.data) return {"success": True, "data": data, "meta": {"count": count}}
def get(self): # This can return None (unauth) if visibility is set to public user = get_current_user() challenges = (Challenges.query.filter( and_(Challenges.state != "hidden", Challenges.state != "locked")).order_by( Challenges.value).all()) if user: solve_ids = (Solves.query.with_entities( Solves.challenge_id).filter_by( account_id=user.account_id).order_by( Solves.challenge_id.asc()).all()) if is_admin(): pass else: if config.is_teams_mode() and get_current_team() is None: abort(403) else: solve_ids = [] response = [] tag_schema = TagSchema(view="user", many=True) for challenge in challenges: if challenge.requirements: requirements = challenge.requirements.get("prerequisites", []) anonymize = challenge.requirements.get("anonymize") if compare(requirements, solve_ids): pass else: if anonymize: response.append({ "id": challenge.id, "type": "hidden", "name": "???", "value": 0, "category": "???", "tags": [], "template": "", "script": "", }) # Fallthrough to continue continue challenge_type = get_chal_class(challenge.type) response.append({ "id": challenge.id, "type": challenge_type.name, "name": challenge.name, "value": challenge.value, "category": challenge.category, "tags": tag_schema.dump(challenge.tags).data, "template": challenge_type.templates["view"], "script": challenge_type.scripts["view"], }) db.session.close() return {"success": True, "data": response}
def post(self, team_id): team = Teams.query.filter_by(id=team_id).first_or_404() data = request.get_json() user_id = data["user_id"] user = Users.query.filter_by(id=user_id).first_or_404() if user.team_id is None: team.members.append(user) db.session.commit() else: return ( { "success": False, "errors": {"id": ["User has already joined a team"]}, }, 400, ) view = "admin" if is_admin() else "user" schema = TeamSchema(view=view) response = schema.dump(team) if response.errors: return {"success": False, "errors": response.errors}, 400 members = response.data.get("members") return {"success": True, "data": members}
def get(self, challenge_id): response = [] challenge = Challenges.query.filter_by(id=challenge_id).first_or_404() # TODO: Need a generic challenge visibility call. # However, it should be stated that a solve on a gated challenge is not considered private. if challenge.state == 'hidden' and is_admin() is False: abort(404) Model = get_model() solves = Solves.query.join(Model, Solves.account_id == Model.id)\ .filter(Solves.challenge_id == challenge_id, Model.banned == False, Model.hidden == False)\ .order_by(Solves.date.asc()) endpoint = None if get_config('user_mode') == TEAMS_MODE: endpoint = 'teams.public' arg = 'team_id' elif get_config('user_mode') == USERS_MODE: endpoint = 'users.public' arg = 'user_id' for solve in solves: response.append({ 'account_id': solve.account_id, 'name': solve.account.name, 'date': isoformat(solve.date), 'account_url': url_for(endpoint, **{arg: solve.account_id}) }) return { 'success': True, 'data': response }
def delete(self, team_id): team = Teams.query.filter_by(id=team_id).first_or_404() data = request.get_json() user_id = data["user_id"] user = Users.query.filter_by(id=user_id).first_or_404() if user.team_id == team.id: team.members.remove(user) # Remove information that links the user to the team Submissions.query.filter_by(user_id=user.id).delete() Awards.query.filter_by(user_id=user.id).delete() Unlocks.query.filter_by(user_id=user.id).delete() db.session.commit() else: return ( {"success": False, "errors": {"id": ["User is not part of this team"]}}, 400, ) view = "admin" if is_admin() else "user" schema = TeamSchema(view=view) response = schema.dump(team) if response.errors: return {"success": False, "errors": response.errors}, 400 members = response.data.get("members") return {"success": True, "data": members}
def get(self, hint_id): user = get_current_user() hint = Hints.query.filter_by(id=hint_id).first_or_404() view = 'unlocked' if hint.cost: view = 'locked' unlocked = HintUnlocks.query.filter_by( account_id=user.account_id, target=hint.id ).first() if unlocked: view = 'unlocked' if is_admin(): if request.args.get('preview', False): view = 'admin' response = HintSchema(view=view).dump(hint) if response.errors: return { 'success': False, 'errors': response.errors }, 400 return { 'success': True, 'data': response.data }