Ejemplo n.º 1
0
def delete_challenge(challenge_id: int, **kwargs):
    """
    Deletes the specified challenge
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()
    groups = kwargs['userinfo'].get('groups')
    if (current_username != challenge.submitter) and (not is_ctf_admin(groups)):
        return not_authorized()

    if challenge.filename:
        threading.Thread(
            target=delete_s3_object,
            args=(challenge.filename,)
        ).start()

    delete_challenge_tags(challenge.id)
    delete_flags(challenge.id)
    challenge.delete()
    return jsonify({
        'status': "success"
    }), 200
Ejemplo n.º 2
0
def all_tags(challenge_id: int):
    """
    Operations pertaining to tags

    :GET: Returns a list of all tags for the challenge with 'challenge_id'
    """
    # Ensure challenge exists
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    return jsonify([tag.tag for tag in challenge.tags]), 200
Ejemplo n.º 3
0
def get_category(category_name: str):
    """
    Operations relating to a single category

    :param category_name: Name of the category requested

    :GET: Returns the category's values
    :DELETE: Deletes the category
    """
    category = Category.query.filter_by(name=category_name.lower()).first()
    if not category:
        return not_found()
    return jsonify(category.to_dict()), 200
Ejemplo n.º 4
0
def delete_tag(challenge_id: int, tag_name: str, **kwargs):
    """
    Deletes the specified tag
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    tag = ChallengeTag.query.filter(func.lower(ChallengeTag.tag) == func.lower(tag_name),
                                    ChallengeTag.challenge_id == challenge_id).first()
    if not tag:
        return not_found()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()
    groups = kwargs['userinfo'].get('groups')
    if current_username != challenge.submitter and not is_ctf_admin(groups):
        return not_authorized()

    tag.delete()
    return jsonify({
        'status': "success"
    }), 200
Ejemplo n.º 5
0
def single_challenge(challenge_id: int, **kwargs):
    """
    Operations pertaining to a single challenge

    :GET: Get the challenge identified by 'challenge_id'
    :DELETE: Delete the challenge identified by 'challenge_id'
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    current_user = kwargs['userinfo'].get("preferred_username")
    if not current_user:
        return no_username()

    return jsonify(get_all_challenge_data(challenge.id, current_user)), 200
Ejemplo n.º 6
0
def create_hint(challenge_id: int = 0, flag_id: int = 0, **kwargs):
    # pylint: disable=unused-argument
    """
    Creates a hint given parameters in the application/json body
    """
    flag = Flag.query.filter_by(id=flag_id).first()
    if not flag:
        return not_found()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()

    data = request.get_json()
    new_hint = Hint.create(data['cost'], data['hint'], flag_id)

    return jsonify(new_hint), 201
Ejemplo n.º 7
0
def solved_flags(challenge_id: int):
    """
    Operations pertaining to the solution of flags

    :GET: Get a list of the users who have solved each flag belonging to the specified challenge
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    flags = Flag.query.filter_by(challenge_id=challenge_id).all()
    response = dict()

    for flag in flags:
        solved = Solved.query.filter_by(flag_id=flag.id).all()
        response[flag.id] = [solution.username for solution in solved]

    return jsonify(response), 200
Ejemplo n.º 8
0
def delete_category(category_name: str):
    """
    Delete the specified category
    """
    category = Category.query.filter_by(name=category_name.lower()).first()
    if not category:
        return not_found()

    if Challenge.query.filter_by(category_name=category_name.lower()).first():
        return jsonify({
            'status': "error",
            'message': "You can't delete a category unless no challenges exist in that category"
        }), 409

    category.delete()
    return jsonify({
        'status': "success"
    }), 200
Ejemplo n.º 9
0
def single_difficulty(difficulty_name: str):
    """
    Deletes a difficulty
    """
    difficulty = Difficulty.query.filter_by(name=difficulty_name.lower()).first()

    if not difficulty:
        return not_found()

    if Challenge.query.filter_by(difficulty_name=difficulty_name.lower()).first():
        return jsonify({
            'status': "error",
            'message': "You can't delete a difficulty that's being used by any challenges"
        }), 409

    difficulty.delete()
    return jsonify({
        'status': "success"
    }), 200
Ejemplo n.º 10
0
def single_flag(challenge_id: int = 0, flag_id: int = 0, **kwargs):
    # pylint: disable=unused-argument
    """
    Deletes the flag specified
    """
    flag = Flag.query.filter_by(id=flag_id).first()
    if not flag:
        return not_found()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()
    groups = kwargs['userinfo'].get('groups')
    if current_username != flag.challenge.submitter and not is_ctf_admin(
            groups):
        return not_authorized()

    delete_flag(flag.id)
    return jsonify({'status': "success"}), 200
Ejemplo n.º 11
0
def purchase_hint(challenge_id: int = 0, flag_id: int = 0, hint_id: int = 0, **kwargs):
    # pylint: disable=unused-argument
    """
    Operations relating to used hints

    :POST: Allow a user to pay for a hint
    """
    hint = Hint.query.filter_by(id=hint_id).first()
    if not hint:
        return not_found()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()

    # Check that the relation doesn't already exist
    used_hints_check = UsedHint.query.filter_by(hint_id=hint_id, username=current_username).first()
    if used_hints_check:
        return collision()

    if current_username == hint.flag.challenge.submitter:
        return jsonify({
            'status': "error",
            'message': "You created this hint!"
        }), 403

    if Solved.query.filter_by(flag_id=hint.flag.id).first():
        return jsonify({
            'status': "error",
            'message': "You already solved the flag associated with this hint!"
        }), 422

    if get_user_score(current_username)[0] - hint.cost < 0:
        return jsonify({
            'status': "error",
            'message': "You don't have enough points to purchase this hint!"
        }), 422

    new_used_hint = UsedHint.create(hint_id, current_username)
    return jsonify(new_used_hint.hint.to_dict()), 201
Ejemplo n.º 12
0
def single_tag(challenge_id: int, tag_name: str, **kwargs):
    """
    Creates a tag
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    tag = ChallengeTag.query.filter_by(tag=tag_name, challenge_id=challenge_id).first()

    if tag:
        return collision()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()
    groups = kwargs['userinfo'].get('groups')
    if current_username != challenge.submitter and not is_ctf_admin(groups):
        return not_authorized()

    new_tag = ChallengeTag.create(challenge_id, tag_name)
    return jsonify(new_tag), 201
Ejemplo n.º 13
0
def all_hints(challenge_id: int, flag_id: int, **kwargs):
    # pylint: disable=unused-argument
    """
    Operations relating to the hints objects

    :GET: Get all hints associated with the specified flag and challenge
    """
    flag = Flag.query.filter_by(id=flag_id).first()
    if not flag:
        return not_found()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()

    # Delete a hint's data if a user hasn't unlocked it
    hints = [hint.to_dict() for hint in Hint.query.filter_by(flag_id=flag_id).all()]
    is_flag_creator = flag.challenge.submitter == current_username
    for hint in hints:
        if not is_flag_creator and \
           not UsedHint.query.filter_by(hint_id=hint['id'], username=current_username).first():
            del hint['hint']
    return jsonify(hints), 200
Ejemplo n.º 14
0
def add_flag(challenge_id: int, **kwargs):
    """
    Create a flag given parameters in application/json body
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    data = request.get_json()
    flag_exists = Flag.query.filter_by(challenge_id=challenge_id,
                                       flag=data['flag']).first()
    if flag_exists:
        return collision()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()
    groups = kwargs['userinfo'].get('groups')
    if current_username != challenge.submitter and not is_ctf_admin(groups):
        return not_authorized()

    new_flag = Flag.create(data['point_value'], data['flag'], challenge_id)
    return jsonify(new_flag), 201
Ejemplo n.º 15
0
def all_flags(challenge_id: int, **kwargs):
    """
    Operations relating to flags

    :GET: Retrieves a list of flags associated with a challenge. The flag value is omitted if the
        person fetching hasn't yet solved the flag
    :POST: Creates a flag associated with a challenge
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    # If the person hasn't solved the flag, the flag data should be omitted.
    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()

    used_hints = set(used_hint.hint_id
                     for used_hint in UsedHint.query.filter_by(
                         username=current_username).all())
    flags = {
        flag.id: flag.to_dict()
        for flag in Flag.query.filter_by(challenge_id=challenge_id).all()
    }
    for flag in flags:
        is_creator = challenge.submitter == current_username
        if not is_creator and \
           not Solved.query.filter_by(username=current_username, flag_id=flags[flag]['id']).first():
            del flags[flag]['flag']
        flags[flag]['hints'] = {
            hint.id: hint.to_dict()
            for hint in Hint.query.filter_by(flag_id=flag).all()
        }
        for hint in flags[flag]['hints'].values():
            if not is_creator and hint['id'] not in used_hints:
                del flags[flag]['hints'][hint['id']]['hint']
    return jsonify(flags), 200
Ejemplo n.º 16
0
def solve_flag(challenge_id: int, **kwargs):
    """
    Operations pertaining to the solved relations on a challenge (but really a flag).

    :param challenge_id: The challenge that a solution is being attempted on

    :POST: Attempt solution of all flags associated with this challenge
    """
    challenge = Challenge.query.filter_by(id=challenge_id).first()
    if not challenge:
        return not_found()

    data = request.get_json()
    flag_attempt = data['flag']
    flags = Flag.query.filter_by(challenge_id=challenge_id).all()

    current_username = kwargs['userinfo'].get('preferred_username')
    if not current_username:
        return no_username()

    if challenge.submitter == current_username:
        return jsonify({
            'status': "error",
            'message': "You created this flag!"
        }), 403

    for flag in flags:
        if flag.flag == flag_attempt:
            check_solved = Solved.query.filter_by(
                flag_id=flag.id, username=current_username).first()
            if check_solved:
                return collision()

            Solved.create(flag.id, current_username)
            return jsonify(challenge.to_dict()), 201
    return jsonify({'status': "error", 'message': "Incorrect flag"}), 400