Exemplo n.º 1
0
def test_register_plugin_stylesheet():
    '''Test that register_plugin_stylesheet adds stylesheet paths to the original theme'''
    app = create_ctfd()
    with app.app_context():
        register_plugin_script('/fake/stylesheet/path.css')
        register_plugin_script('http://ctfd.io/fake/stylesheet/path.css')
        with app.test_client() as client:
            r = client.get('/')
            output = r.get_data(as_text=True)
            assert '/fake/stylesheet/path.css' in output
            assert 'http://ctfd.io/fake/stylesheet/path.css' in output
Exemplo n.º 2
0
def test_register_plugin_script():
    '''Test that register_plugin_script adds script paths to the core theme'''
    app = create_ctfd()
    with app.app_context():
        register_plugin_script('/fake/script/path.js')
        register_plugin_script('http://ctfd.io/fake/script/path.js')
        with app.test_client() as client:
            r = client.get('/')
            output = r.get_data(as_text=True)
            assert '/fake/script/path.js' in output
            assert 'http://ctfd.io/fake/script/path.js' in output
    destroy_ctfd(app)
Exemplo n.º 3
0
def load(app):
    notify = Blueprint('notify', __name__, template_folder='templates')
    notify_static = Blueprint('notify_static',
                              __name__,
                              static_folder='static')

    @notify.route('/admin/plugins/notify/send', methods=['GET', 'POST'])
    @admins_only
    def notify_send():
        if request.method == 'GET':
            return render_template('notify.html')
        elif request.method == 'POST':
            msg = request.form.get('msg')
            title = request.form.get('title')
            client_secret = get_config('thunderpush_client_secret')
            server_secret = get_config('thunderpush_server_secret')
            thunderpush_url = get_config('thunderpush_url')
            thunderpush_port = get_config('thunderpush_port')
            t = Thunder(apikey=client_secret,
                        apisecret=server_secret,
                        host=thunderpush_url,
                        port=thunderpush_port)
            t.send_message_to_channel(channel='all_teams',
                                      message={
                                          'title': title,
                                          'msg': msg
                                      })
            return '', 200

    @notify.route('/notify/static/ctfd-notify.js', methods=['GET'])
    def notify_static_generator():
        client_secret = get_config('thunderpush_client_secret')
        thunderpush_url = get_config('thunderpush_url')
        thunderpush_port = get_config('thunderpush_port')
        js = render_template('ctfd-notify.js',
                             url=thunderpush_url,
                             port=thunderpush_port,
                             secret=client_secret)
        return Response(js, mimetype='application/javascript')

    app.register_blueprint(notify)
    app.register_blueprint(notify_static, url_prefix='/notify')
    scripts = [
        "/notify/static/sockjs-0.3.4.min.js", "/notify/static/thunderpush.js",
        "/notify/static/push.min.js", "/notify/static/ctfd-notify.js"
    ]
    for s in scripts:
        utils.register_plugin_script(s)
Exemplo n.º 4
0
def load(app):
    app.db.create_all()

    linear_unlocking = Blueprint('linear_unlocking',
                                 __name__,
                                 template_folder='templates')
    linear_unlocking_static = Blueprint('linear_unlocking_static',
                                        __name__,
                                        static_folder='static')
    app.register_blueprint(linear_unlocking)
    app.register_blueprint(linear_unlocking_static,
                           url_prefix='/linear-unlocking')

    utils.register_plugin_script(
        "/linear-unlocking/static/linear-unlocking-chalboard.js")

    def get_challenges_by_categories():
        chals = db.session.query(Challenges.id, Challenges.name,
                                 Challenges.category)
        jchals = []
        for x in chals:
            jchals.append({'id': x.id, 'name': x.name, 'category': x.category})
        # Sort into categories
        categories = set(map(lambda x: x['category'], jchals))
        cats = []
        for c in categories:
            cats.append({
                'name': c,
                'challenges': [j for j in jchals if j['category'] == c]
            })
        return cats

    def get_linear_unlocking_chains():
        chals = db.session.query(Challenges.id, Challenges.name,
                                 Challenges.category)
        jchals = {}
        for x in chals:
            jchals[x.id] = (x.name, x.category)

        lu_ids = []
        lu_models = LinearUnlockingModel.query.all()
        for lu_model in lu_models:
            lu_entries = LinearUnlockingEntry.query.filter_by(
                linearunlockid=lu_model.id).all()
            entry = {
                'id': lu_model.id,
                'name': lu_model.name,
                'is_hidden': lu_model.is_hidden,
                'chain': []
            }
            for m in lu_entries:
                entry['chain'].append({
                    'chalid': m.chalid,
                    'chalname': jchals[m.chalid][0],
                    'chalcategory': jchals[m.chalid][1]
                })
            lu_ids.append(entry)
        return lu_ids

    @app.route('/admin/plugins/linear-unlocking', methods=['GET', 'POST'])
    @admins_only
    def linear_unlocking_config_view():
        if request.method == 'POST':
            lu_chain = []
            lu_name = request.form['name']
            for i in range(len(request.form)):
                challenge_name = 'challenge[{}]'.format(i)
                if challenge_name in request.form:
                    chalid = request.form[challenge_name]
                    lu_chain.append(chalid)
                else:
                    break

            if len(lu_name) >= 1 and len(lu_chain) >= 2:
                lu = LinearUnlockingModel(lu_name)
                db.session.add(lu)
                db.session.commit()
                lu_id = lu.id

                position = 1
                prev_chalid = -1
                for chalid in lu_chain:
                    lu_entry = LinearUnlockingEntry(
                        linearunlockid=lu_id,
                        position=position,
                        chalid=chalid,
                        requires_chalid=prev_chalid)
                    db.session.add(lu_entry)
                    db.session.commit()
                    position += 1
                    prev_chalid = chalid

        return render_template(
            'linear-unlocking-config.html',
            challenge_categories=get_challenges_by_categories(),
            linear_unlocking_chains=get_linear_unlocking_chains())

    @app.route('/admin/plugins/linear-unlocking/delete', methods=['POST'])
    @admins_only
    def linear_unlocking_delete():
        if request.method == 'POST':
            lu_id = request.form['lu_id']
            LinearUnlockingEntry.query.filter_by(linearunlockid=lu_id).delete()
            LinearUnlockingModel.query.filter_by(id=lu_id).delete()
            db.session.commit()
            return redirect('/admin/plugins/linear-unlocking')

    @app.route('/admin/plugins/linear-unlocking/toggle-hide', methods=['POST'])
    @admins_only
    def linear_unlocking_togglehide():
        if request.method == 'POST':
            lu_id = request.form['lu_id']
            is_hide = request.form['is_hide'] == "true"
            lu_model = LinearUnlockingModel.query.filter_by(
                id=lu_id).first_or_404()
            lu_model.is_hidden = is_hide
            db.session.commit()
            return redirect('/admin/plugins/linear-unlocking')

    @app.route('/linearunlockings')
    def get_linear_unlockings():
        response = {'linearunlockings': []}
        lu_models = LinearUnlockingModel.query.all()
        for lu_model in lu_models:
            lu_entries = LinearUnlockingEntry.query.filter_by(
                linearunlockid=lu_model.id).all()
            for lu_entry in lu_entries:
                chal = Challenges.query.filter_by(id=lu_entry.chalid).first()
                response['linearunlockings'].append({
                    'id':
                    lu_model.id,
                    'is_hidden':
                    lu_model.is_hidden,
                    'chalid':
                    lu_entry.chalid,
                    'chalname':
                    chal.name,
                    'requires_chalid':
                    lu_entry.requires_chalid
                })
        db.session.close()
        return jsonify(response)

    # Overwriting existing route for retrieving chal view
    def chal_view_linearunlocked(chal_id):
        teamid = session.get('id')

        chal = Challenges.query.filter_by(id=chal_id).first_or_404()
        chal_class = get_chal_class(chal.type)

        # Get solved challenge ids
        solves = []
        if utils.is_admin():
            solves = Solves.query.filter_by(teamid=session['id']).all()
        elif utils.user_can_view_challenges():
            if utils.authed():
                solves = Solves.query\
                    .join(Teams, Solves.teamid == Teams.id)\
                    .filter(Solves.teamid == session['id'])\
                    .all()
        solve_ids = []
        for solve in solves:
            solve_ids.append(solve.chalid)

        # Return nothing if there is at least one linear unlocking requirement not solved
        lu_entries = LinearUnlockingEntry.query.filter_by(chalid=chal.id).all()
        for lu_entry in lu_entries:
            if lu_entry.requires_chalid > -1 and lu_entry.requires_chalid not in solve_ids:
                return jsonify([])

        tags = [
            tag.tag for tag in Tags.query.add_columns('tag').filter_by(
                chal=chal.id).all()
        ]
        files = [
            str(f.location) for f in Files.query.filter_by(chal=chal.id).all()
        ]
        unlocked_hints = set([
            u.itemid
            for u in Unlocks.query.filter_by(model='hints', teamid=teamid)
        ])
        hints = []

        for hint in Hints.query.filter_by(chal=chal.id).all():
            if hint.id in unlocked_hints or utils.ctf_ended():
                hints.append({
                    'id': hint.id,
                    'cost': hint.cost,
                    'hint': hint.hint
                })
            else:
                hints.append({'id': hint.id, 'cost': hint.cost})

        challenge, response = chal_class.read(challenge=chal)

        response['files'] = files
        response['tags'] = tags
        response['hints'] = hints

        db.session.close()
        return jsonify(response)

    # Overwriting existing route for retrieving chals
    def chals_linearunlocked():
        # Get solved challenge ids
        solves = []
        if utils.is_admin():
            solves = Solves.query.filter_by(teamid=session['id']).all()
        elif utils.user_can_view_challenges():
            if utils.authed():
                solves = Solves.query\
                    .join(Teams, Solves.teamid == Teams.id)\
                    .filter(Solves.teamid == session['id'])\
                    .all()
        solve_ids = []
        for solve in solves:
            solve_ids.append(solve.chalid)

        db_chals = Challenges.query.filter(
            or_(Challenges.hidden != True,
                Challenges.hidden == None)).order_by(Challenges.value).all()
        response = {'game': []}
        linearunlock_games = {}
        other_games = []

        for chal in db_chals:
            # Skip if is linear locked and should be hidden
            lu_id = -1
            lu_name = "__NOT_IN_ANY_CHAIN__"
            lu_position = -1
            is_hidden = False
            lu_entries = LinearUnlockingEntry.query.filter_by(
                chalid=chal.id).all()
            for lu_entry in lu_entries:
                # Initialize lu_id if possible, used for sorting the challenges later
                if lu_id == -1:
                    lu_model = LinearUnlockingModel.query.filter_by(
                        id=lu_entry.linearunlockid).first()
                    lu_id = lu_model.id
                    lu_name = lu_model.name
                    lu_position = lu_entry.position

                if lu_entry.requires_chalid > -1 and lu_entry.requires_chalid not in solve_ids:
                    lu_model = LinearUnlockingModel.query.filter_by(
                        id=lu_entry.linearunlockid).first()
                    if lu_model.is_hidden:
                        is_hidden = True
                        break
            if is_hidden:
                continue

            tags = [
                tag.tag for tag in Tags.query.add_columns('tag').filter_by(
                    chal=chal.id).all()
            ]
            chal_type = get_chal_class(chal.type)

            game = {
                'id': chal.id,
                'type': chal_type.name,
                'name': chal.name,
                'value': chal.value,
                'category': chal.category,
                'tags': tags,
                'template': chal_type.templates['modal'],
                'script': chal_type.scripts['modal'],
                # Add more info for chain presentation
                'chainid': lu_id,
                'chainname': lu_name,
                'chainposition': lu_position,
            }
            if lu_id > -1:
                if lu_id not in linearunlock_games:
                    linearunlock_games[lu_id] = []
                linearunlock_games[lu_id].append(game)
            else:
                other_games.append(game)

        # Add all linear unlock chain challenges in sorted order first
        for lu_id, lu_chain_games in linearunlock_games.iteritems():
            lu_chain_games.sort(key=lambda x: x['chainposition'])
            response['game'].extend(lu_chain_games)
        # Then add all other games that are not in any chain
        response['game'].extend(other_games)

        db.session.close()
        return jsonify(response)

    def admin_delete_chal_linearunlocked():
        lu_to_delete = []
        lu_entries = LinearUnlockingEntry.query.filter_by(
            chalid=request.form['id']).all()
        for entry in lu_entries:
            if entry.linearunlockid not in lu_to_delete:
                lu_to_delete.append(entry.linearunlockid)

        for lu_id in lu_to_delete:
            LinearUnlockingEntry.query.filter_by(linearunlockid=lu_id).delete()
            LinearUnlockingModel.query.filter_by(id=lu_id).delete()
            db.session.commit()

        return admin_delete_chal()

    app.view_functions[
        'admin_challenges.admin_delete_chal'] = admin_delete_chal_linearunlocked
    app.view_functions['challenges.chals'] = chals_linearunlocked
    app.view_functions['challenges.chal_view'] = chal_view_linearunlocked