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

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

80 statements  

1from __future__ import annotations 

2 

3import typing as t 

4 

5from .structures import CallbackDict 

6 

7 

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

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

10 return property( 

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

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

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

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

15 ) 

16 

17 

18class ContentSecurityPolicy(CallbackDict[str, t.Any]): 

19 """A parsed ``Content-Security-Policy`` header. 

20 

21 Set :attr:`.Response.content_security_policy` or 

22 :attr:`.Response.content_security_policy_report_only` to an instance to set 

23 the header. Modifying the instance will update the header. 

24 

25 Typically, you'll use the various directive properties. It also allows 

26 indexing ``csp[directive]`` to get, set, or delete unknown directives that 

27 do not have corresponding properties. 

28 

29 .. versionchanged:: 3.2 

30 Directives with only a name and no space or value are considered boolean 

31 rather than discarded. 

32 

33 Added the ``required_trusted_types_for``, ``trusted_types``, and 

34 ``upgrade_insecure_requests`` properties. 

35 

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

37 are deprecated and will be removed in Werkzeug 4.0. 

38 

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: bool | 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="4.0") 

77 # removed directives 

78 navigate_to: str | None = _csp_property("navigate-to", deprecated="4.0") 

79 plugin_types: str | None = _csp_property("plugin-types", deprecated="4.0") 

80 

81 def _get_value(self, key: str, deprecated: str | None = None) -> t.Any | None: 

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

83 if deprecated is not None: 

84 import warnings 

85 

86 warnings.warn( 

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

88 f" in Werkzeug {deprecated}.", 

89 DeprecationWarning, 

90 stacklevel=3, 

91 ) 

92 

93 if key in self: 

94 if (value := self[key]) is None: 

95 return True 

96 

97 return value 

98 

99 return None 

100 

101 def _set_value( 

102 self, key: str, value: t.Any | None, deprecated: str | None = None 

103 ) -> None: 

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

105 if deprecated is not None: 

106 import warnings 

107 

108 warnings.warn( 

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

110 f" in Werkzeug {deprecated}.", 

111 DeprecationWarning, 

112 stacklevel=3, 

113 ) 

114 

115 if not value: 

116 self.pop(key, None) 

117 else: 

118 self[key] = value 

119 

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

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

122 if deprecated is not None: 

123 import warnings 

124 

125 warnings.warn( 

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

127 f" in Werkzeug {deprecated}.", 

128 DeprecationWarning, 

129 stacklevel=3, 

130 ) 

131 

132 if key in self: 

133 del self[key] 

134 

135 @classmethod 

136 def from_header(cls, value: str | None) -> t.Self: 

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

138 instance of this class. 

139 

140 .. versionadded:: 3.2 

141 """ 

142 if not value: 

143 return cls() 

144 

145 items: list[tuple[str, str | None]] = [] 

146 

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

148 policy = policy.strip(" \t") 

149 

150 # Ignore badly formatted policies (no space) 

151 if " " in policy: 

152 directive, _, value = policy.partition(" ") 

153 items.append((directive.strip(" \t"), value.strip(" \t"))) 

154 else: 

155 items.append((policy, None)) 

156 

157 return cls(items) 

158 

159 def to_header(self) -> str: 

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

161 out = [] 

162 

163 for key, value in self.items(): 

164 if value is None: 

165 out.append(key) 

166 else: 

167 out.append(f"{key} {value}") 

168 

169 return "; ".join(out) 

170 

171 def __str__(self) -> str: 

172 return self.to_header() 

173 

174 def __repr__(self) -> str: 

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

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