Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/werkzeug/datastructures/csp.py: 59%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

76 statements  

1from __future__ import annotations 

2 

3import collections.abc as cabc 

4import typing as t 

5 

6from .structures import CallbackDict 

7 

8if t.TYPE_CHECKING: 

9 import typing_extensions as te 

10 

11 

12def csp_property(key: str, deprecated: str | None = None) -> t.Any: 

13 """Create a property for a CSP directive.""" 

14 return property( 

15 lambda x: x._get_value(key, deprecated=deprecated), 

16 lambda x, v: x._set_value(key, v, deprecated=deprecated), 

17 lambda x: x._del_value(key, deprecated, deprecated=deprecated), 

18 f"The ``{key}`` directive.", 

19 ) 

20 

21 

22class ContentSecurityPolicy(CallbackDict[str, str]): 

23 """A dict that stores values for a ``Content-Security-Policy`` header. 

24 Properties are available to access the CSP directives. The properties have 

25 the same name as the directives, with dashes replaced with underscore. 

26 

27 To add a directive that does not have a property implemented, set the dict 

28 key directly, like ``csp["new-directive"] = "value"``. 

29 

30 .. versionchanged:: 3.2 

31 Added the ``required_trusted_types_for``, ``trusted_types``, and 

32 ``upgrade_insecure_requests`` properties. 

33 

34 .. versionchanged:: 3.2 

35 The ``prefetch_src``, ``navigate_to``, and ``plugin_types`` properties 

36 are deprecated and will be removed in Werkzeug 3.3. 

37 

38 .. versionchanged:: 3.2 

39 The ``on_update`` parameter was removed. 

40 

41 .. versionadded:: 1.0 

42 """ 

43 

44 # sections from MDN docs 

45 # fetch directives 

46 child_src: str | None = csp_property("child-src") 

47 connect_src: str | None = csp_property("connect-src") 

48 default_src: str | None = csp_property("default-src") 

49 font_src: str | None = csp_property("font-src") 

50 frame_src: str | None = csp_property("frame-src") 

51 img_src: str | None = csp_property("img-src") 

52 manifest_src: str | None = csp_property("manifest-src") 

53 media_src: str | None = csp_property("media-src") 

54 object_src: str | None = csp_property("object-src") 

55 script_src: str | None = csp_property("script-src") 

56 script_src_attr: str | None = csp_property("script-src-attr") 

57 script_src_elem: str | None = csp_property("script-src-elem") 

58 style_src: str | None = csp_property("style-src") 

59 style_src_attr: str | None = csp_property("style-src-attr") 

60 style_src_elem: str | None = csp_property("style-src-elem") 

61 worker_src: str | None = csp_property("worker-src") 

62 # document directives 

63 base_uri: str | None = csp_property("base-uri") 

64 sandbox: str | None = csp_property("sandbox") 

65 # navigation directives 

66 form_action: str | None = csp_property("form-action") 

67 frame_ancestors: str | None = csp_property("frame-ancestors") 

68 # reporting directives 

69 report_to: str | None = csp_property("report-to") 

70 # other directives 

71 require_trusted_types_for: str | None = csp_property("require-trusted-types-for") 

72 trusted_types: str | None = csp_property("trusted-types") 

73 upgrade_insecure_requests: str | None = csp_property("upgrade-insecure-requests") 

74 # deprecated directives 

75 report_uri: str | None = csp_property("report-uri") # still widely supported 

76 prefetch_src: str | None = csp_property("prefetch-src", deprecated="3.3") 

77 # removed directives 

78 navigate_to: str | None = csp_property("navigate-to", deprecated="3.3") 

79 plugin_types: str | None = csp_property("plugin-types", deprecated="3.3") 

80 

81 def __init__( 

82 self, 

83 values: cabc.Mapping[str, str] | cabc.Iterable[tuple[str, str]] | None = None, 

84 ) -> None: 

85 super().__init__(values) 

86 self.provided = values is not None 

87 

88 def _get_value(self, key: str, deprecated: str | None = None) -> str | None: 

89 """Used internally by the accessor properties.""" 

90 if deprecated is not None: 

91 import warnings 

92 

93 warnings.warn( 

94 f"The CSP '{key}' directive is deprecated and will be removed" 

95 f" in Werkzeug {deprecated}.", 

96 DeprecationWarning, 

97 stacklevel=3, 

98 ) 

99 

100 return self.get(key) 

101 

102 def _set_value( 

103 self, key: str, value: str | None, deprecated: str | None = None 

104 ) -> None: 

105 """Used internally by the accessor properties.""" 

106 if deprecated is not None: 

107 import warnings 

108 

109 warnings.warn( 

110 f"The CSP '{key}' directive is deprecated and will be removed" 

111 f" in Werkzeug {deprecated}.", 

112 DeprecationWarning, 

113 stacklevel=3, 

114 ) 

115 

116 if value is None: 

117 self.pop(key, None) 

118 else: 

119 self[key] = value 

120 

121 def _del_value(self, key: str, deprecated: str | None = None) -> None: 

122 """Used internally by the accessor properties.""" 

123 if deprecated is not None: 

124 import warnings 

125 

126 warnings.warn( 

127 f"The CSP '{key}' directive is deprecated and will be removed" 

128 f" in Werkzeug {deprecated}.", 

129 DeprecationWarning, 

130 stacklevel=3, 

131 ) 

132 

133 if key in self: 

134 del self[key] 

135 

136 @classmethod 

137 def from_header(cls, value: str | None) -> te.Self: 

138 """Parse a ``Content-Security-Policy`` header value and create an 

139 instance of this class. 

140 

141 .. versionadded:: 3.2 

142 """ 

143 if not value: 

144 return cls() 

145 

146 items = [] 

147 

148 for policy in value.split(";"): 

149 policy = policy.strip() 

150 

151 # Ignore badly formatted policies (no space) 

152 if " " in policy: 

153 directive, value = policy.strip().split(" ", 1) 

154 items.append((directive.strip(), value.strip())) 

155 

156 return cls(items) 

157 

158 def to_header(self) -> str: 

159 """Convert to a ``Content-Security-Policy`` header value.""" 

160 return "; ".join(f"{key} {value}" for key, value in self.items()) 

161 

162 def __str__(self) -> str: 

163 return self.to_header() 

164 

165 def __repr__(self) -> str: 

166 kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items())) 

167 return f"<{type(self).__name__} {kv_str}>"