csp.py 3.2 KB

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