diff --git a/CTFd/utils/exports/__init__.py b/CTFd/utils/exports/__init__.py index 928caae7..784b85e4 100644 --- a/CTFd/utils/exports/__init__.py +++ b/CTFd/utils/exports/__init__.py @@ -30,6 +30,7 @@ from CTFd.utils.exports.freeze import freeze_export from CTFd.utils.migrations import ( create_database, drop_database, + get_available_revisions, get_current_revision, stamp_latest_revision, ) @@ -195,6 +196,15 @@ def import_ctf(backup, erase=True): mysql = get_app_config("SQLALCHEMY_DATABASE_URI").startswith("mysql") mariadb = is_database_mariadb() + # Only import if we can actually make it to the target migration + if sqlite is False and alembic_version not in get_available_revisions(): + set_import_error( + "Exception: The target migration in this backup is not available in this version of CTFd." + ) + raise Exception( + "The target migration in this backup is not available in this version of CTFd." + ) + if erase: set_import_status("erasing") # Clear out existing connections to release any locks diff --git a/CTFd/utils/initialization/__init__.py b/CTFd/utils/initialization/__init__.py index 903d6168..8e0c376c 100644 --- a/CTFd/utils/initialization/__init__.py +++ b/CTFd/utils/initialization/__init__.py @@ -192,6 +192,11 @@ def init_request_processors(app): @app.before_request def needs_setup(): + if import_in_progress(): + if request.endpoint == "admin.import_ctf": + return + else: + return "Import currently in progress", 403 if is_setup() is False: if request.endpoint in ( "views.setup", @@ -213,7 +218,7 @@ def init_request_processors(app): if request.endpoint == "admin.import_ctf": return else: - abort(403, description="Import currently in progress") + return "Import currently in progress", 403 if authed(): user_ips = get_current_user_recent_ips() diff --git a/CTFd/utils/migrations/__init__.py b/CTFd/utils/migrations/__init__.py index a5aab82a..4202e5e4 100644 --- a/CTFd/utils/migrations/__init__.py +++ b/CTFd/utils/migrations/__init__.py @@ -1,4 +1,6 @@ import os +import re +from pathlib import Path from alembic.migration import MigrationContext from flask import current_app as app @@ -48,3 +50,13 @@ def stamp_latest_revision(): # Get proper migrations directory regardless of cwd directory = os.path.join(os.path.dirname(app.root_path), "migrations") stamp(directory=directory) + + +def get_available_revisions(): + revisions = [] + directory = Path(os.path.dirname(app.root_path), "migrations", "versions") + for f in directory.glob("*.py"): + with f.open() as migration: + revision = re.search(r'revision = "(.*?)"', migration.read()).group(1) + revisions.append(revision) + return revisions