1from __future__ import annotations 
    2 
    3from .mixins import UpdateDictMixin 
    4 
    5 
    6def csp_property(key): 
    7    """Return a new property object for a content security policy header. 
    8    Useful if you want to add support for a csp extension in a 
    9    subclass. 
    10    """ 
    11    return property( 
    12        lambda x: x._get_value(key), 
    13        lambda x, v: x._set_value(key, v), 
    14        lambda x: x._del_value(key), 
    15        f"accessor for {key!r}", 
    16    ) 
    17 
    18 
    19class ContentSecurityPolicy(UpdateDictMixin, dict): 
    20    """Subclass of a dict that stores values for a Content Security Policy 
    21    header. It has accessors for all the level 3 policies. 
    22 
    23    Because the csp directives in the HTTP header use dashes the 
    24    python descriptors use underscores for that. 
    25 
    26    To get a header of the :class:`ContentSecuirtyPolicy` object again 
    27    you can convert the object into a string or call the 
    28    :meth:`to_header` method.  If you plan to subclass it and add your 
    29    own items have a look at the sourcecode for that class. 
    30 
    31    .. versionadded:: 1.0.0 
    32       Support for Content Security Policy headers was added. 
    33 
    34    """ 
    35 
    36    base_uri = csp_property("base-uri") 
    37    child_src = csp_property("child-src") 
    38    connect_src = csp_property("connect-src") 
    39    default_src = csp_property("default-src") 
    40    font_src = csp_property("font-src") 
    41    form_action = csp_property("form-action") 
    42    frame_ancestors = csp_property("frame-ancestors") 
    43    frame_src = csp_property("frame-src") 
    44    img_src = csp_property("img-src") 
    45    manifest_src = csp_property("manifest-src") 
    46    media_src = csp_property("media-src") 
    47    navigate_to = csp_property("navigate-to") 
    48    object_src = csp_property("object-src") 
    49    prefetch_src = csp_property("prefetch-src") 
    50    plugin_types = csp_property("plugin-types") 
    51    report_to = csp_property("report-to") 
    52    report_uri = csp_property("report-uri") 
    53    sandbox = csp_property("sandbox") 
    54    script_src = csp_property("script-src") 
    55    script_src_attr = csp_property("script-src-attr") 
    56    script_src_elem = csp_property("script-src-elem") 
    57    style_src = csp_property("style-src") 
    58    style_src_attr = csp_property("style-src-attr") 
    59    style_src_elem = csp_property("style-src-elem") 
    60    worker_src = csp_property("worker-src") 
    61 
    62    def __init__(self, values=(), on_update=None): 
    63        dict.__init__(self, values or ()) 
    64        self.on_update = on_update 
    65        self.provided = values is not None 
    66 
    67    def _get_value(self, key): 
    68        """Used internally by the accessor properties.""" 
    69        return self.get(key) 
    70 
    71    def _set_value(self, key, value): 
    72        """Used internally by the accessor properties.""" 
    73        if value is None: 
    74            self.pop(key, None) 
    75        else: 
    76            self[key] = value 
    77 
    78    def _del_value(self, key): 
    79        """Used internally by the accessor properties.""" 
    80        if key in self: 
    81            del self[key] 
    82 
    83    def to_header(self): 
    84        """Convert the stored values into a cache control header.""" 
    85        from ..http import dump_csp_header 
    86 
    87        return dump_csp_header(self) 
    88 
    89    def __str__(self): 
    90        return self.to_header() 
    91 
    92    def __repr__(self): 
    93        kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items())) 
    94        return f"<{type(self).__name__} {kv_str}>"