Beispiel #1
0
def test_update_check_identifies_update(fake_get_request):
    """Update checks properly identify new versions"""
    app = create_ctfd()
    with app.app_context():
        app.config['UPDATE_CHECK'] = True
        fake_response = Mock()
        fake_get_request.return_value = fake_response
        fake_response.json = lambda: {
            u'resource': {
                u'html_url':
                u'https://github.com/CTFd/CTFd/releases/tag/9.9.9',
                u'download_url':
                u'https://api.github.com/repos/CTFd/CTFd/zipball/9.9.9',
                u'published_at': u'Wed, 25 Oct 2017 19:39:42 -0000',
                u'tag': u'9.9.9',
                u'prerelease': False,
                u'id': 6,
                u'latest': True
            }
        }
        update_check()
        assert get_config(
            'version_latest'
        ) == 'https://github.com/CTFd/CTFd/releases/tag/9.9.9'
    destroy_ctfd(app)
Beispiel #2
0
def test_update_check_ignores_downgrades(fake_get_request):
    """Update checks do nothing on old or same versions"""
    app = create_ctfd()
    with app.app_context():
        app.config['UPDATE_CHECK'] = True
        fake_response = Mock()
        fake_get_request.return_value = fake_response
        fake_response.json = lambda: {
            u'resource': {
                u'html_url':
                u'https://github.com/CTFd/CTFd/releases/tag/0.0.1',
                u'download_url':
                u'https://api.github.com/repos/CTFd/CTFd/zipball/0.0.1',
                u'published_at': u'Wed, 25 Oct 2017 19:39:42 -0000',
                u'tag': u'0.0.1',
                u'prerelease': False,
                u'id': 6,
                u'latest': True
            }
        }
        update_check()
        assert get_config('version_latest') is None

        fake_response = Mock()
        fake_get_request.return_value = fake_response
        fake_response.json = lambda: {
            u'resource': {
                u'html_url':
                u'https://github.com/CTFd/CTFd/releases/tag/{}'.format(
                    app.VERSION),
                u'download_url':
                u'https://api.github.com/repos/CTFd/CTFd/zipball/{}'.format(
                    app.VERSION),
                u'published_at':
                u'Wed, 25 Oct 2017 19:39:42 -0000',
                u'tag':
                u'{}'.format(app.VERSION),
                u'prerelease':
                False,
                u'id':
                6,
                u'latest':
                True
            }
        }
        update_check()
        assert get_config('version_latest') is None
    destroy_ctfd(app)
Beispiel #3
0
def admin_stats():
    update_check()
    teams_registered = db.session.query(db.func.count(Teams.id)).first()[0]

    wrong_count = WrongKeys.query.join(
        Teams,
        WrongKeys.teamid == Teams.id).filter(Teams.banned == False).count()
    solve_count = Solves.query.join(
        Teams,
        Solves.teamid == Teams.id).filter(Teams.banned == False).count()

    challenge_count = db.session.query(db.func.count(Challenges.id)).first()[0]
    ip_count = db.session.query(db.func.count(
        Tracking.ip.distinct())).first()[0]

    solves_sub = db.session.query(Solves.chalid, db.func.count(Solves.chalid).label('solves_cnt')) \
                           .join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False) \
                           .group_by(Solves.chalid).subquery()
    solves = db.session.query(solves_sub.columns.chalid, solves_sub.columns.solves_cnt, Challenges.name) \
                       .join(Challenges, solves_sub.columns.chalid == Challenges.id).all()
    solve_data = {}
    for chal, count, name in solves:
        solve_data[name] = count

    most_solved = None
    least_solved = None
    if len(solve_data):
        most_solved = max(solve_data, key=solve_data.get)
        least_solved = min(solve_data, key=solve_data.get)

    db.session.expunge_all()
    db.session.commit()
    db.session.close()

    return render_template('admin/statistics.html',
                           team_count=teams_registered,
                           ip_count=ip_count,
                           wrong_count=wrong_count,
                           solve_count=solve_count,
                           challenge_count=challenge_count,
                           solve_data=solve_data,
                           most_solved=most_solved,
                           least_solved=least_solved)
Beispiel #4
0
def create_app(config='CTFd.config.Config'):
    app = Flask(__name__)
    with app.app_context():
        app.config.from_object(config)
        app.jinja_loader = ThemeLoader(os.path.join(app.root_path, 'themes'),
                                       followlinks=True)

        from CTFd.models import db, Teams, Solves, Challenges, WrongKeys, Keys, Tags, Files, Tracking

        url = make_url(app.config['SQLALCHEMY_DATABASE_URI'])
        if url.drivername == 'postgres':
            url.drivername = 'postgresql'

        if url.drivername.startswith('mysql'):
            url.query['charset'] = 'utf8mb4'

        # Creates database if the database database does not exist
        if not database_exists(url):
            if url.drivername.startswith('mysql'):
                create_database(url, encoding='utf8mb4')
            else:
                create_database(url)

        # This allows any changes to the SQLALCHEMY_DATABASE_URI to get pushed back in
        # This is mostly so we can force MySQL's charset
        app.config['SQLALCHEMY_DATABASE_URI'] = str(url)

        # Register database
        db.init_app(app)

        # Register Flask-Migrate
        migrate.init_app(app, db)

        # Alembic sqlite support is lacking so we should just create_all anyway
        if url.drivername.startswith('sqlite'):
            db.create_all()
        else:
            if len(db.engine.table_names()) == 0:
                # This creates tables instead of db.create_all()
                # Allows migrations to happen properly
                migrate_upgrade()
            elif 'alembic_version' not in db.engine.table_names():
                # There is no alembic_version because CTFd is from before it had migrations
                # Stamp it to the base migration
                if confirm_upgrade():
                    migrate_stamp(revision='cb3cfcc47e2f')
                    run_upgrade()
                else:
                    exit()

        app.db = db
        app.VERSION = __version__

        cache.init_app(app)
        app.cache = cache

        update_check()

        version = utils.get_config('ctf_version')

        # Upgrading from an older version of CTFd
        if version and (StrictVersion(version) < StrictVersion(__version__)):
            if confirm_upgrade():
                run_upgrade()
            else:
                exit()

        if not utils.get_config('ctf_theme'):
            utils.set_config('ctf_theme', 'core')

        from CTFd.views import views
        from CTFd.challenges import challenges
        from CTFd.scoreboard import scoreboard
        from CTFd.auth import auth
        from CTFd.admin import admin, admin_statistics, admin_challenges, admin_pages, admin_scoreboard, admin_keys, admin_teams
        from CTFd.utils import init_utils, init_errors, init_logs

        init_utils(app)
        init_errors(app)
        init_logs(app)

        app.register_blueprint(views)
        app.register_blueprint(challenges)
        app.register_blueprint(scoreboard)
        app.register_blueprint(auth)

        app.register_blueprint(admin)
        app.register_blueprint(admin_statistics)
        app.register_blueprint(admin_challenges)
        app.register_blueprint(admin_teams)
        app.register_blueprint(admin_scoreboard)
        app.register_blueprint(admin_keys)
        app.register_blueprint(admin_pages)

        from CTFd.plugins import init_plugins

        init_plugins(app)

        return app