OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/feature_policy/FeaturePolicy.h" | 5 #include "platform/feature_policy/FeaturePolicy.h" |
6 | 6 |
7 #include "platform/json/JSONValues.h" | 7 #include "platform/json/JSONValues.h" |
8 #include "platform/network/HTTPParsers.h" | 8 #include "platform/network/HTTPParsers.h" |
9 #include "platform/weborigin/KURL.h" | 9 #include "platform/weborigin/KURL.h" |
10 #include "platform/weborigin/SecurityOrigin.h" | 10 #include "platform/weborigin/SecurityOrigin.h" |
11 #include "wtf/PtrUtil.h" | 11 #include "wtf/PtrUtil.h" |
12 #include "wtf/text/StringBuilder.h" | 12 #include "wtf/text/StringBuilder.h" |
13 | 13 |
14 namespace blink { | 14 namespace blink { |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 // Given a string name, return the matching feature struct, or nullptr if it is | 18 // Given a string name, return the matching feature struct, or nullptr if it is |
19 // not the name of a policy-controlled feature. | 19 // not the name of a policy-controlled feature. |
20 const FeaturePolicy::Feature* featureForName( | 20 const FeaturePolicy::Feature* featureForName( |
21 const String& featureName, | 21 const String& featureName, |
22 FeaturePolicy::FeatureList& features) { | 22 FeaturePolicy::FeatureList& features) { |
23 for (const FeaturePolicy::Feature* feature : features) { | 23 for (const FeaturePolicy::Feature* feature : features) { |
24 if (featureName == feature->featureName) | 24 if (featureName == feature->featureName) |
25 return feature; | 25 return feature; |
26 } | 26 } |
27 return nullptr; | 27 return nullptr; |
28 } | 28 } |
29 | 29 |
30 // Converts a list of JSON feature policy items into a mapping of features to | |
31 // whitelists. For future compatibility, unrecognized features are simply | |
32 // ignored, as are unparseable origins. If |messages| is not null, then any | |
33 // errors in the input will cause an error message to be appended to it. | |
34 HashMap<const FeaturePolicy::Feature*, | |
35 std::unique_ptr<FeaturePolicy::Whitelist>> | |
36 parseFeaturePolicyFromJson(std::unique_ptr<JSONArray> policyItems, | |
37 RefPtr<SecurityOrigin> origin, | |
38 FeaturePolicy::FeatureList& features, | |
39 Vector<String>* messages) { | |
40 HashMap<const FeaturePolicy::Feature*, | |
41 std::unique_ptr<FeaturePolicy::Whitelist>> | |
42 whitelists; | |
43 | |
44 for (size_t i = 0; i < policyItems->size(); ++i) { | |
45 JSONObject* item = JSONObject::cast(policyItems->at(i)); | |
46 if (!item) { | |
47 if (messages) | |
48 messages->append("Policy is not an object"); | |
49 continue; // Array element is not an object; skip | |
50 } | |
51 | |
52 for (size_t j = 0; j < item->size(); ++j) { | |
53 JSONObject::Entry entry = item->at(j); | |
54 String featureName = entry.first; | |
55 JSONArray* targets = JSONArray::cast(entry.second); | |
56 if (!targets) { | |
57 if (messages) | |
58 messages->append("Whitelist is not an array of strings."); | |
59 continue; | |
60 } | |
61 | |
62 const FeaturePolicy::Feature* feature = | |
63 featureForName(featureName, features); | |
64 if (!feature) | |
65 continue; // Feature is not recognized; skip | |
66 | |
67 std::unique_ptr<FeaturePolicy::Whitelist> whitelist( | |
68 new FeaturePolicy::Whitelist); | |
69 String targetString; | |
70 for (size_t j = 0; j < targets->size(); ++j) { | |
71 if (targets->at(j)->asString(&targetString)) { | |
72 if (equalIgnoringCase(targetString, "self")) { | |
73 whitelist->add(origin); | |
74 } else if (targetString == "*") { | |
75 whitelist->addAll(); | |
76 } else { | |
77 KURL originUrl = KURL(KURL(), targetString); | |
78 if (originUrl.isValid()) { | |
79 whitelist->add(SecurityOrigin::create(originUrl)); | |
80 } | |
81 } | |
82 } else { | |
83 if (messages) | |
84 messages->append("Whitelist is not an array of strings."); | |
85 } | |
86 } | |
87 whitelists.set(feature, std::move(whitelist)); | |
88 } | |
89 } | |
90 return whitelists; | |
91 } | |
92 | |
93 } // namespace | 30 } // namespace |
94 | 31 |
95 // Definitions of all features controlled by Feature Policy should appear here. | 32 // Definitions of all features controlled by Feature Policy should appear here. |
96 const FeaturePolicy::Feature kDocumentCookie{ | 33 const FeaturePolicy::Feature kDocumentCookie{ |
97 "cookie", FeaturePolicy::FeatureDefault::EnableForAll}; | 34 "cookie", FeaturePolicy::FeatureDefault::EnableForAll}; |
98 const FeaturePolicy::Feature kDocumentDomain{ | 35 const FeaturePolicy::Feature kDocumentDomain{ |
99 "domain", FeaturePolicy::FeatureDefault::EnableForAll}; | 36 "domain", FeaturePolicy::FeatureDefault::EnableForAll}; |
100 const FeaturePolicy::Feature kDocumentWrite{ | 37 const FeaturePolicy::Feature kDocumentWrite{ |
101 "docwrite", FeaturePolicy::FeatureDefault::EnableForAll}; | 38 "docwrite", FeaturePolicy::FeatureDefault::EnableForAll}; |
102 const FeaturePolicy::Feature kGeolocationFeature{ | 39 const FeaturePolicy::Feature kGeolocationFeature{ |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
188 } | 125 } |
189 | 126 |
190 // static | 127 // static |
191 std::unique_ptr<FeaturePolicy> FeaturePolicy::createFromParentPolicy( | 128 std::unique_ptr<FeaturePolicy> FeaturePolicy::createFromParentPolicy( |
192 const FeaturePolicy* parent, | 129 const FeaturePolicy* parent, |
193 RefPtr<SecurityOrigin> currentOrigin) { | 130 RefPtr<SecurityOrigin> currentOrigin) { |
194 return createFromParentPolicy(parent, std::move(currentOrigin), | 131 return createFromParentPolicy(parent, std::move(currentOrigin), |
195 getDefaultFeatureList()); | 132 getDefaultFeatureList()); |
196 } | 133 } |
197 | 134 |
198 void FeaturePolicy::setHeaderPolicy(const String& policy, | 135 // static |
199 Vector<String>* messages) { | 136 WebVector<WebFeaturePolicy::ParsedWhitelist> FeaturePolicy::parseFeaturePolicy( |
iclelland
2016/11/23 20:20:28
As a new public interface, it would be good to hav
raymes
2016/11/30 06:25:17
Done - I added a test.
| |
200 DCHECK(m_headerWhitelists.isEmpty()); | 137 const String& policy, |
138 const SecurityOrigin* origin, | |
139 Vector<String>* messages) { | |
140 Vector<WebFeaturePolicy::ParsedWhitelist> whitelists; | |
141 | |
142 if (origin->isUnique()) | |
iclelland
2016/11/23 20:20:28
This is a new check -- as far as I can tell, a uni
raymes
2016/11/30 06:25:17
Yeah it is a new check. You're right - let me remo
| |
143 return whitelists; | |
144 | |
201 // Use a reasonable parse depth limit; the actual maximum depth is only going | 145 // Use a reasonable parse depth limit; the actual maximum depth is only going |
202 // to be 4 for a valid policy, but we'll give the featurePolicyParser a chance | 146 // to be 4 for a valid policy, but we'll give the featurePolicyParser a chance |
203 // to report more specific errors, unless the string is really invalid. | 147 // to report more specific errors, unless the string is really invalid. |
204 std::unique_ptr<JSONArray> policyJSON = parseJSONHeader(policy, 50); | 148 std::unique_ptr<JSONArray> policyItems = parseJSONHeader(policy, 50); |
205 if (!policyJSON) { | 149 if (!policyItems) { |
206 if (messages) | 150 if (messages) |
207 messages->append("Unable to parse header"); | 151 messages->append("Unable to parse header"); |
208 return; | 152 return whitelists; |
209 } | 153 } |
210 m_headerWhitelists = parseFeaturePolicyFromJson( | 154 |
211 std::move(policyJSON), m_origin, m_features, messages); | 155 for (size_t i = 0; i < policyItems->size(); ++i) { |
156 JSONObject* item = JSONObject::cast(policyItems->at(i)); | |
157 if (!item) { | |
158 if (messages) | |
159 messages->append("Policy is not an object"); | |
160 continue; // Array element is not an object; skip | |
161 } | |
162 | |
163 for (size_t j = 0; j < item->size(); ++j) { | |
164 JSONObject::Entry entry = item->at(j); | |
165 String featureName = entry.first; | |
166 JSONArray* targets = JSONArray::cast(entry.second); | |
167 if (!targets) { | |
168 if (messages) | |
169 messages->append("Whitelist is not an array of strings."); | |
170 continue; | |
171 } | |
172 | |
173 WebFeaturePolicy::ParsedWhitelist whitelist; | |
174 whitelist.featureName = featureName; | |
175 Vector<WebString> origins; | |
176 String targetString; | |
177 for (size_t j = 0; j < targets->size(); ++j) { | |
178 if (targets->at(j)->asString(&targetString)) { | |
179 if (equalIgnoringCase(targetString, "self")) { | |
180 origins.append(origin->toString()); | |
181 } else if (targetString == "*") { | |
182 whitelist.matchesAllOrigins = true; | |
183 } else { | |
184 KURL originUrl = KURL(KURL(), targetString); | |
185 if (originUrl.isValid()) | |
iclelland
2016/11/23 20:20:28
This might as well be
if (KURL(KURL(), targetStrin
raymes
2016/11/29 08:20:34
Good point - we can probably use a WebSecurityOrig
| |
186 origins.append(targetString); | |
187 } | |
188 } else { | |
189 if (messages) | |
190 messages->append("Whitelist is not an array of strings."); | |
191 } | |
192 } | |
193 whitelist.origins = origins; | |
194 whitelists.append(whitelist); | |
195 } | |
196 } | |
197 return whitelists; | |
198 } | |
199 | |
200 void FeaturePolicy::setHeaderPolicy( | |
201 const WebVector<WebFeaturePolicy::ParsedWhitelist>& policy) { | |
202 DCHECK(m_headerWhitelists.isEmpty()); | |
203 for (const WebFeaturePolicy::ParsedWhitelist& parsedWhitelist : policy) { | |
iclelland
2016/11/23 20:20:28
This method seems like it's mostly a conversion fu
raymes
2016/11/29 08:20:34
I haven't made this change yet (and my connection
raymes
2016/11/30 06:25:17
Done now.
| |
204 const FeaturePolicy::Feature* feature = | |
205 featureForName(parsedWhitelist.featureName, m_features); | |
206 if (!feature) | |
207 continue; | |
208 std::unique_ptr<Whitelist> whitelist(new FeaturePolicy::Whitelist); | |
209 if (parsedWhitelist.matchesAllOrigins) { | |
210 whitelist->addAll(); | |
211 } else { | |
212 for (const WebString& origin : parsedWhitelist.origins) { | |
213 KURL originUrl = KURL(KURL(), origin); | |
214 if (originUrl.isValid()) | |
215 whitelist->add(SecurityOrigin::create(originUrl)); | |
216 } | |
217 } | |
218 m_headerWhitelists.set(feature, std::move(whitelist)); | |
219 } | |
212 } | 220 } |
213 | 221 |
214 bool FeaturePolicy::isFeatureEnabledForOrigin( | 222 bool FeaturePolicy::isFeatureEnabledForOrigin( |
215 const FeaturePolicy::Feature& feature, | 223 const FeaturePolicy::Feature& feature, |
216 const SecurityOrigin& origin) const { | 224 const SecurityOrigin& origin) const { |
217 DCHECK(m_inheritedFeatures.contains(&feature)); | 225 DCHECK(m_inheritedFeatures.contains(&feature)); |
218 if (!m_inheritedFeatures.get(&feature)) { | 226 if (!m_inheritedFeatures.get(&feature)) { |
219 return false; | 227 return false; |
220 } | 228 } |
221 if (m_headerWhitelists.contains(&feature)) { | 229 if (m_headerWhitelists.contains(&feature)) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 sb.append(" "); | 266 sb.append(" "); |
259 sb.append(whitelist.key->featureName); | 267 sb.append(whitelist.key->featureName); |
260 sb.append(": "); | 268 sb.append(": "); |
261 sb.append(whitelist.value->toString()); | 269 sb.append(whitelist.value->toString()); |
262 sb.append("\n"); | 270 sb.append("\n"); |
263 } | 271 } |
264 return sb.toString(); | 272 return sb.toString(); |
265 } | 273 } |
266 | 274 |
267 } // namespace blink | 275 } // namespace blink |
OLD | NEW |