Adding more protections for 502's during imports (#2220)

* Be more defensive on asset loading during imports
* On primary databases only import backups when we are actually able to make it to the target migration
This commit is contained in:
Kevin Chung
2022-11-05 19:08:12 -04:00
committed by GitHub
parent 95bfb96a82
commit dfa7f87823
3 changed files with 28 additions and 1 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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