Exemple #1
0
    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"])
Exemple #2
0
    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,
        }
Exemple #3
0
    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}
Exemple #4
0
    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"])
Exemple #5
0
    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
Exemple #7
0
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)
Exemple #8
0
    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
Exemple #9
0
    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)
Exemple #10
0
    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
        }
Exemple #11
0
    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'])
Exemple #12
0
    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)
Exemple #14
0
 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()
Exemple #15
0
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')
Exemple #16
0
    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)
Exemple #17
0
    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)
Exemple #18
0
    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'])
Exemple #19
0
    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)
Exemple #20
0
    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)
Exemple #23
0
    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)
Exemple #24
0
    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
        }
Exemple #25
0
    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}}
Exemple #26
0
    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}
Exemple #27
0
    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}
Exemple #28
0
    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
        }
Exemple #29
0
    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}
Exemple #30
0
    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
        }