mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-18 22:44:24 +01:00
929 better visibility constants (#1490)
* Adds Enums for visibility configs for better reusability. Old tests will continue to use the static values but new ones should use the enum values. * Closes #929
This commit is contained in:
@@ -1,7 +1,42 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
from CTFd.constants import JinjaEnum, RawEnum
|
||||||
from CTFd.utils import get_config
|
from CTFd.utils import get_config
|
||||||
from CTFd.utils.helpers import markup
|
|
||||||
|
|
||||||
|
class ConfigTypes(str, RawEnum):
|
||||||
|
CHALLENGE_VISIBILITY = "challenge_visibility"
|
||||||
|
SCORE_VISIBILITY = "score_visibility"
|
||||||
|
ACCOUNT_VISIBILITY = "account_visibility"
|
||||||
|
REGISTRATION_VISIBILITY = "registration_visibility"
|
||||||
|
|
||||||
|
|
||||||
|
@JinjaEnum
|
||||||
|
class ChallengeVisibilityTypes(str, RawEnum):
|
||||||
|
PUBLIC = "public"
|
||||||
|
PRIVATE = "private"
|
||||||
|
ADMINS = "admins"
|
||||||
|
|
||||||
|
|
||||||
|
@JinjaEnum
|
||||||
|
class ScoreVisibilityTypes(str, RawEnum):
|
||||||
|
PUBLIC = "public"
|
||||||
|
PRIVATE = "private"
|
||||||
|
HIDDEN = "hidden"
|
||||||
|
ADMINS = "admins"
|
||||||
|
|
||||||
|
|
||||||
|
@JinjaEnum
|
||||||
|
class AccountVisibilityTypes(str, RawEnum):
|
||||||
|
PUBLIC = "public"
|
||||||
|
PRIVATE = "private"
|
||||||
|
ADMINS = "admins"
|
||||||
|
|
||||||
|
|
||||||
|
@JinjaEnum
|
||||||
|
class RegistrationVisibilityTypes(str, RawEnum):
|
||||||
|
PUBLIC = "public"
|
||||||
|
PRIVATE = "private"
|
||||||
|
|
||||||
|
|
||||||
class _ConfigsWrapper:
|
class _ConfigsWrapper:
|
||||||
@@ -14,10 +49,14 @@ class _ConfigsWrapper:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def theme_header(self):
|
def theme_header(self):
|
||||||
|
from CTFd.utils.helpers import markup
|
||||||
|
|
||||||
return markup(get_config("theme_header", default=""))
|
return markup(get_config("theme_header", default=""))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def theme_footer(self):
|
def theme_footer(self):
|
||||||
|
from CTFd.utils.helpers import markup
|
||||||
|
|
||||||
return markup(get_config("theme_footer", default=""))
|
return markup(get_config("theme_footer", default=""))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
import cmarkgfm
|
import cmarkgfm
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
|
|
||||||
@@ -43,6 +45,10 @@ def _get_config(key):
|
|||||||
|
|
||||||
|
|
||||||
def get_config(key, default=None):
|
def get_config(key, default=None):
|
||||||
|
# Convert enums to raw string values to cache better
|
||||||
|
if isinstance(key, Enum):
|
||||||
|
key = str(key)
|
||||||
|
|
||||||
value = _get_config(key)
|
value = _get_config(key)
|
||||||
if value is KeyError:
|
if value is KeyError:
|
||||||
return default
|
return default
|
||||||
@@ -58,5 +64,10 @@ def set_config(key, value):
|
|||||||
config = Configs(key=key, value=value)
|
config = Configs(key=key, value=value)
|
||||||
db.session.add(config)
|
db.session.add(config)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
# Convert enums to raw string values to cache better
|
||||||
|
if isinstance(key, Enum):
|
||||||
|
key = str(key)
|
||||||
|
|
||||||
cache.delete_memoized(_get_config, key)
|
cache.delete_memoized(_get_config, key)
|
||||||
return config
|
return config
|
||||||
|
|||||||
@@ -1,44 +1,51 @@
|
|||||||
|
from CTFd.constants.config import (
|
||||||
|
AccountVisibilityTypes,
|
||||||
|
ChallengeVisibilityTypes,
|
||||||
|
ConfigTypes,
|
||||||
|
RegistrationVisibilityTypes,
|
||||||
|
ScoreVisibilityTypes,
|
||||||
|
)
|
||||||
from CTFd.utils import get_config
|
from CTFd.utils import get_config
|
||||||
from CTFd.utils.user import authed, is_admin
|
from CTFd.utils.user import authed, is_admin
|
||||||
|
|
||||||
|
|
||||||
def challenges_visible():
|
def challenges_visible():
|
||||||
v = get_config("challenge_visibility")
|
v = get_config(ConfigTypes.CHALLENGE_VISIBILITY)
|
||||||
if v == "public":
|
if v == ChallengeVisibilityTypes.PUBLIC:
|
||||||
return True
|
return True
|
||||||
elif v == "private":
|
elif v == ChallengeVisibilityTypes.PRIVATE:
|
||||||
return authed()
|
return authed()
|
||||||
elif v == "admins":
|
elif v == ChallengeVisibilityTypes.ADMINS:
|
||||||
return is_admin()
|
return is_admin()
|
||||||
|
|
||||||
|
|
||||||
def scores_visible():
|
def scores_visible():
|
||||||
v = get_config("score_visibility")
|
v = get_config(ConfigTypes.SCORE_VISIBILITY)
|
||||||
if v == "public":
|
if v == ScoreVisibilityTypes.PUBLIC:
|
||||||
return True
|
return True
|
||||||
elif v == "private":
|
elif v == ScoreVisibilityTypes.PRIVATE:
|
||||||
return authed()
|
return authed()
|
||||||
elif v == "hidden":
|
elif v == ScoreVisibilityTypes.HIDDEN:
|
||||||
return False
|
return False
|
||||||
elif v == "admins":
|
elif v == ScoreVisibilityTypes.ADMINS:
|
||||||
return is_admin()
|
return is_admin()
|
||||||
|
|
||||||
|
|
||||||
def accounts_visible():
|
def accounts_visible():
|
||||||
v = get_config("account_visibility")
|
v = get_config(ConfigTypes.ACCOUNT_VISIBILITY)
|
||||||
if v == "public":
|
if v == AccountVisibilityTypes.PUBLIC:
|
||||||
return True
|
return True
|
||||||
elif v == "private":
|
elif v == AccountVisibilityTypes.PRIVATE:
|
||||||
return authed()
|
return authed()
|
||||||
elif v == "admins":
|
elif v == AccountVisibilityTypes.ADMINS:
|
||||||
return is_admin()
|
return is_admin()
|
||||||
|
|
||||||
|
|
||||||
def registration_visible():
|
def registration_visible():
|
||||||
v = get_config("registration_visibility")
|
v = get_config(ConfigTypes.REGISTRATION_VISIBILITY)
|
||||||
if v == "public":
|
if v == RegistrationVisibilityTypes.PUBLIC:
|
||||||
return True
|
return True
|
||||||
elif v == "private":
|
elif v == RegistrationVisibilityTypes.PRIVATE:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ import functools
|
|||||||
|
|
||||||
from flask import abort, redirect, render_template, request, url_for
|
from flask import abort, redirect, render_template, request, url_for
|
||||||
|
|
||||||
|
from CTFd.constants.config import (
|
||||||
|
AccountVisibilityTypes,
|
||||||
|
ChallengeVisibilityTypes,
|
||||||
|
ConfigTypes,
|
||||||
|
RegistrationVisibilityTypes,
|
||||||
|
ScoreVisibilityTypes,
|
||||||
|
)
|
||||||
from CTFd.utils import get_config
|
from CTFd.utils import get_config
|
||||||
from CTFd.utils.user import authed, is_admin
|
from CTFd.utils.user import authed, is_admin
|
||||||
|
|
||||||
@@ -9,11 +16,11 @@ from CTFd.utils.user import authed, is_admin
|
|||||||
def check_score_visibility(f):
|
def check_score_visibility(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def _check_score_visibility(*args, **kwargs):
|
def _check_score_visibility(*args, **kwargs):
|
||||||
v = get_config("score_visibility")
|
v = get_config(ConfigTypes.SCORE_VISIBILITY)
|
||||||
if v == "public":
|
if v == ScoreVisibilityTypes.PUBLIC:
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
elif v == "private":
|
elif v == ScoreVisibilityTypes.PRIVATE:
|
||||||
if authed():
|
if authed():
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -22,13 +29,13 @@ def check_score_visibility(f):
|
|||||||
else:
|
else:
|
||||||
return redirect(url_for("auth.login", next=request.full_path))
|
return redirect(url_for("auth.login", next=request.full_path))
|
||||||
|
|
||||||
elif v == "hidden":
|
elif v == ScoreVisibilityTypes.HIDDEN:
|
||||||
return (
|
return (
|
||||||
render_template("errors/403.html", error="Scores are currently hidden"),
|
render_template("errors/403.html", error="Scores are currently hidden"),
|
||||||
403,
|
403,
|
||||||
)
|
)
|
||||||
|
|
||||||
elif v == "admins":
|
elif v == ScoreVisibilityTypes.ADMINS:
|
||||||
if is_admin():
|
if is_admin():
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -40,11 +47,11 @@ def check_score_visibility(f):
|
|||||||
def check_challenge_visibility(f):
|
def check_challenge_visibility(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def _check_challenge_visibility(*args, **kwargs):
|
def _check_challenge_visibility(*args, **kwargs):
|
||||||
v = get_config("challenge_visibility")
|
v = get_config(ConfigTypes.CHALLENGE_VISIBILITY)
|
||||||
if v == "public":
|
if v == ChallengeVisibilityTypes.PUBLIC:
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
elif v == "private":
|
elif v == ChallengeVisibilityTypes.PRIVATE:
|
||||||
if authed():
|
if authed():
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -53,7 +60,7 @@ def check_challenge_visibility(f):
|
|||||||
else:
|
else:
|
||||||
return redirect(url_for("auth.login", next=request.full_path))
|
return redirect(url_for("auth.login", next=request.full_path))
|
||||||
|
|
||||||
elif v == "admins":
|
elif v == ChallengeVisibilityTypes.ADMINS:
|
||||||
if is_admin():
|
if is_admin():
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -68,11 +75,11 @@ def check_challenge_visibility(f):
|
|||||||
def check_account_visibility(f):
|
def check_account_visibility(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def _check_account_visibility(*args, **kwargs):
|
def _check_account_visibility(*args, **kwargs):
|
||||||
v = get_config("account_visibility")
|
v = get_config(ConfigTypes.ACCOUNT_VISIBILITY)
|
||||||
if v == "public":
|
if v == AccountVisibilityTypes.PUBLIC:
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
elif v == "private":
|
elif v == AccountVisibilityTypes.PRIVATE:
|
||||||
if authed():
|
if authed():
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -81,7 +88,7 @@ def check_account_visibility(f):
|
|||||||
else:
|
else:
|
||||||
return redirect(url_for("auth.login", next=request.full_path))
|
return redirect(url_for("auth.login", next=request.full_path))
|
||||||
|
|
||||||
elif v == "admins":
|
elif v == AccountVisibilityTypes.ADMINS:
|
||||||
if is_admin():
|
if is_admin():
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -93,10 +100,10 @@ def check_account_visibility(f):
|
|||||||
def check_registration_visibility(f):
|
def check_registration_visibility(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def _check_registration_visibility(*args, **kwargs):
|
def _check_registration_visibility(*args, **kwargs):
|
||||||
v = get_config("registration_visibility")
|
v = get_config(ConfigTypes.REGISTRATION_VISIBILITY)
|
||||||
if v == "public":
|
if v == RegistrationVisibilityTypes.PUBLIC:
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
elif v == "private":
|
elif v == RegistrationVisibilityTypes.PRIVATE:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
return _check_registration_visibility
|
return _check_registration_visibility
|
||||||
|
|||||||
@@ -20,12 +20,6 @@ from CTFd.utils.config import (
|
|||||||
is_setup,
|
is_setup,
|
||||||
)
|
)
|
||||||
from CTFd.utils.config.pages import get_pages
|
from CTFd.utils.config.pages import get_pages
|
||||||
from CTFd.utils.config.visibility import (
|
|
||||||
accounts_visible,
|
|
||||||
challenges_visible,
|
|
||||||
registration_visible,
|
|
||||||
scores_visible,
|
|
||||||
)
|
|
||||||
from CTFd.utils.countries import get_countries, lookup_country_code
|
from CTFd.utils.countries import get_countries, lookup_country_code
|
||||||
from CTFd.utils.dates import isoformat, unix_time, unix_time_millis
|
from CTFd.utils.dates import isoformat, unix_time, unix_time_millis
|
||||||
from CTFd.utils.events import EventManager, RedisEventManager
|
from CTFd.utils.events import EventManager, RedisEventManager
|
||||||
@@ -61,6 +55,12 @@ def init_template_globals(app):
|
|||||||
from CTFd.constants.plugins import Plugins
|
from CTFd.constants.plugins import Plugins
|
||||||
from CTFd.constants.sessions import Session
|
from CTFd.constants.sessions import Session
|
||||||
from CTFd.forms import Forms
|
from CTFd.forms import Forms
|
||||||
|
from CTFd.utils.config.visibility import (
|
||||||
|
accounts_visible,
|
||||||
|
challenges_visible,
|
||||||
|
registration_visible,
|
||||||
|
scores_visible,
|
||||||
|
)
|
||||||
|
|
||||||
app.jinja_env.globals.update(config=config)
|
app.jinja_env.globals.update(config=config)
|
||||||
app.jinja_env.globals.update(get_pages=get_pages)
|
app.jinja_env.globals.update(get_pages=get_pages)
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ from flask.helpers import safe_join
|
|||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
from CTFd.cache import cache
|
from CTFd.cache import cache
|
||||||
|
from CTFd.constants.config import (
|
||||||
|
AccountVisibilityTypes,
|
||||||
|
ChallengeVisibilityTypes,
|
||||||
|
ConfigTypes,
|
||||||
|
RegistrationVisibilityTypes,
|
||||||
|
ScoreVisibilityTypes,
|
||||||
|
)
|
||||||
from CTFd.models import (
|
from CTFd.models import (
|
||||||
Admins,
|
Admins,
|
||||||
Files,
|
Files,
|
||||||
@@ -156,10 +163,14 @@ def setup():
|
|||||||
page = Pages(title=None, route="index", content=index, draft=False)
|
page = Pages(title=None, route="index", content=index, draft=False)
|
||||||
|
|
||||||
# Visibility
|
# Visibility
|
||||||
set_config("challenge_visibility", "private")
|
set_config(
|
||||||
set_config("registration_visibility", "public")
|
ConfigTypes.CHALLENGE_VISIBILITY, ChallengeVisibilityTypes.PRIVATE
|
||||||
set_config("score_visibility", "public")
|
)
|
||||||
set_config("account_visibility", "public")
|
set_config(
|
||||||
|
ConfigTypes.REGISTRATION_VISIBILITY, RegistrationVisibilityTypes.PUBLIC
|
||||||
|
)
|
||||||
|
set_config(ConfigTypes.SCORE_VISIBILITY, ScoreVisibilityTypes.PUBLIC)
|
||||||
|
set_config(ConfigTypes.ACCOUNT_VISIBILITY, AccountVisibilityTypes.PUBLIC)
|
||||||
|
|
||||||
# Verify emails
|
# Verify emails
|
||||||
set_config("verify_emails", None)
|
set_config("verify_emails", None)
|
||||||
@@ -354,7 +365,7 @@ def files(path):
|
|||||||
|
|
||||||
# Check user is admin if challenge_visibility is admins only
|
# Check user is admin if challenge_visibility is admins only
|
||||||
if (
|
if (
|
||||||
get_config("challenge_visibility") == "admins"
|
get_config(ConfigTypes.CHALLENGE_VISIBILITY) == "admins"
|
||||||
and user.type != "admin"
|
and user.type != "admin"
|
||||||
):
|
):
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|||||||
Reference in New Issue
Block a user