diff --git a/csp/conf/__init__.py b/csp/conf/__init__.py index aaf64c8..c407682 100644 --- a/csp/conf/__init__.py +++ b/csp/conf/__init__.py @@ -1,26 +1,57 @@ -from . import defaults - - -DIRECTIVES = set(defaults.POLICY) -PSEUDO_DIRECTIVES = {d for d in DIRECTIVES if '_' in d} - - -def setting_to_directive(setting, value, prefix='CSP_'): - setting = setting[len(prefix):].lower() - if setting not in PSEUDO_DIRECTIVES: - setting = setting.replace('_', '-') - assert setting in DIRECTIVES - if isinstance(value, str): - value = [value] - return setting, value +__all__ = [ + 'defaults', + 'deprecation', + 'directive_to_setting', + 'get_declared_policies', + 'get_declared_policy_definitions', + 'setting_to_directive', + 'DIRECTIVES', +] + +from django.conf import settings - -def directive_to_setting(directive, prefix='CSP_'): - setting = '{}{}'.format( - prefix, - directive.replace('-', '_').upper() +from . import defaults +from .deprecation import ( + directive_to_setting, + setting_to_directive, + _handle_legacy_settings, +) + + +DIRECTIVES = defaults.DIRECTIVES +PSEUDO_DIRECTIVES = defaults.PSEUDO_DIRECTIVES + + +def _csp_definitions_update(csp_definitions, other): + """ Update one csp definitions dictionary with another """ + if isinstance(other, dict): + other = other.items() + for name, csp in other: + csp_definitions.setdefault(name, {}).update(csp) + return csp_definitions + + +def get_declared_policy_definitions(): + custom_definitions = _csp_definitions_update( + {}, + getattr( + settings, + 'CSP_POLICY_DEFINITIONS', + {'default': {}}, + ), + ) + _handle_legacy_settings( + custom_definitions['default'], + allow_legacy=not hasattr(settings, 'CSP_POLICY_DEFINITIONS'), + ) + definitions = _csp_definitions_update( + {}, + {name: defaults.POLICY for name in custom_definitions} ) - return setting + for name, csp in custom_definitions.items(): + definitions.setdefault(name, {}).update(csp) + return definitions -LEGACY_KWARGS = {directive_to_setting(d, prefix='') for d in DIRECTIVES} +def get_declared_policies(): + return getattr(settings, 'CSP_POLICIES', defaults.POLICIES) diff --git a/csp/conf/defaults.py b/csp/conf/defaults.py index e47437b..b918ecb 100644 --- a/csp/conf/defaults.py +++ b/csp/conf/defaults.py @@ -42,3 +42,6 @@ 'include_nonce_in': ('default-src',), 'exclude_url_prefixes': (), } + +DIRECTIVES = set(POLICY) +PSEUDO_DIRECTIVES = {d for d in DIRECTIVES if '_' in d} diff --git a/csp/conf/deprecation.py b/csp/conf/deprecation.py index 921503e..2e9d539 100644 --- a/csp/conf/deprecation.py +++ b/csp/conf/deprecation.py @@ -3,11 +3,7 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured -from . import ( - setting_to_directive, - directive_to_setting, - DIRECTIVES, -) +from . import defaults BLOCK_ALL_MIXED_CONTENT_DEPRECATION_WARNING = ( @@ -21,8 +17,26 @@ ) +def setting_to_directive(setting, value, prefix='CSP_'): + setting = setting[len(prefix):].lower() + if setting not in defaults.PSEUDO_DIRECTIVES: + setting = setting.replace('_', '-') + assert setting in defaults.DIRECTIVES + if isinstance(value, str): + value = [value] + return setting, value + + +def directive_to_setting(directive, prefix='CSP_'): + setting = '{}{}'.format( + prefix, + directive.replace('-', '_').upper() + ) + return setting + + _LEGACY_SETTINGS = { - directive_to_setting(directive) for directive in DIRECTIVES + directive_to_setting(directive) for directive in defaults.DIRECTIVES }