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 10 matching lines...) Expand all Loading... | |
113 "sync-script", FeaturePolicy::FeatureDefault::EnableForAll}; | 50 "sync-script", FeaturePolicy::FeatureDefault::EnableForAll}; |
114 const FeaturePolicy::Feature kSyncXHR{ | 51 const FeaturePolicy::Feature kSyncXHR{ |
115 "sync-xhr", FeaturePolicy::FeatureDefault::EnableForAll}; | 52 "sync-xhr", FeaturePolicy::FeatureDefault::EnableForAll}; |
116 const FeaturePolicy::Feature kUsermedia{ | 53 const FeaturePolicy::Feature kUsermedia{ |
117 "usermedia", FeaturePolicy::FeatureDefault::EnableForAll}; | 54 "usermedia", FeaturePolicy::FeatureDefault::EnableForAll}; |
118 const FeaturePolicy::Feature kVibrateFeature{ | 55 const FeaturePolicy::Feature kVibrateFeature{ |
119 "vibrate", FeaturePolicy::FeatureDefault::EnableForSelf}; | 56 "vibrate", FeaturePolicy::FeatureDefault::EnableForSelf}; |
120 const FeaturePolicy::Feature kWebRTC{ | 57 const FeaturePolicy::Feature kWebRTC{ |
121 "webrtc", FeaturePolicy::FeatureDefault::EnableForAll}; | 58 "webrtc", FeaturePolicy::FeatureDefault::EnableForAll}; |
122 | 59 |
60 // static | |
61 std::unique_ptr<FeaturePolicy::Whitelist> FeaturePolicy::Whitelist::from( | |
62 const WebFeaturePolicy::ParsedWhitelist& parsedWhitelist) { | |
63 std::unique_ptr<Whitelist> whitelist(new FeaturePolicy::Whitelist); | |
64 if (parsedWhitelist.matchesAllOrigins) { | |
65 whitelist->addAll(); | |
66 } else { | |
67 for (const WebSecurityOrigin& origin : parsedWhitelist.origins) | |
68 whitelist->add(static_cast<WTF::PassRefPtr<SecurityOrigin>>(origin)); | |
69 } | |
70 return whitelist; | |
71 } | |
72 | |
123 FeaturePolicy::Whitelist::Whitelist() : m_matchesAllOrigins(false) {} | 73 FeaturePolicy::Whitelist::Whitelist() : m_matchesAllOrigins(false) {} |
124 | 74 |
125 void FeaturePolicy::Whitelist::addAll() { | 75 void FeaturePolicy::Whitelist::addAll() { |
126 m_matchesAllOrigins = true; | 76 m_matchesAllOrigins = true; |
127 } | 77 } |
128 | 78 |
129 void FeaturePolicy::Whitelist::add(RefPtr<SecurityOrigin> origin) { | 79 void FeaturePolicy::Whitelist::add(RefPtr<SecurityOrigin> origin) { |
130 m_origins.append(std::move(origin)); | 80 m_origins.append(std::move(origin)); |
131 } | 81 } |
132 | 82 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
188 } | 138 } |
189 | 139 |
190 // static | 140 // static |
191 std::unique_ptr<FeaturePolicy> FeaturePolicy::createFromParentPolicy( | 141 std::unique_ptr<FeaturePolicy> FeaturePolicy::createFromParentPolicy( |
192 const FeaturePolicy* parent, | 142 const FeaturePolicy* parent, |
193 RefPtr<SecurityOrigin> currentOrigin) { | 143 RefPtr<SecurityOrigin> currentOrigin) { |
194 return createFromParentPolicy(parent, std::move(currentOrigin), | 144 return createFromParentPolicy(parent, std::move(currentOrigin), |
195 getDefaultFeatureList()); | 145 getDefaultFeatureList()); |
196 } | 146 } |
197 | 147 |
198 void FeaturePolicy::setHeaderPolicy(const String& policy, | 148 // static |
199 Vector<String>* messages) { | 149 WebParsedFeaturePolicy FeaturePolicy::parseFeaturePolicy( |
200 DCHECK(m_headerWhitelists.isEmpty()); | 150 const String& policy, |
151 RefPtr<SecurityOrigin> origin, | |
152 Vector<String>* messages) { | |
153 Vector<WebFeaturePolicy::ParsedWhitelist> whitelists; | |
154 | |
201 // Use a reasonable parse depth limit; the actual maximum depth is only going | 155 // 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 | 156 // 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. | 157 // to report more specific errors, unless the string is really invalid. |
204 std::unique_ptr<JSONArray> policyJSON = parseJSONHeader(policy, 50); | 158 std::unique_ptr<JSONArray> policyItems = parseJSONHeader(policy, 50); |
205 if (!policyJSON) { | 159 if (!policyItems) { |
206 if (messages) | 160 if (messages) |
207 messages->append("Unable to parse header"); | 161 messages->append("Unable to parse header"); |
208 return; | 162 return whitelists; |
209 } | 163 } |
210 m_headerWhitelists = parseFeaturePolicyFromJson( | 164 |
211 std::move(policyJSON), m_origin, m_features, messages); | 165 for (size_t i = 0; i < policyItems->size(); ++i) { |
166 JSONObject* item = JSONObject::cast(policyItems->at(i)); | |
167 if (!item) { | |
168 if (messages) | |
169 messages->append("Policy is not an object"); | |
170 continue; // Array element is not an object; skip | |
171 } | |
172 | |
173 for (size_t j = 0; j < item->size(); ++j) { | |
174 JSONObject::Entry entry = item->at(j); | |
175 String featureName = entry.first; | |
176 JSONArray* targets = JSONArray::cast(entry.second); | |
177 if (!targets) { | |
178 if (messages) | |
179 messages->append("Whitelist is not an array of strings."); | |
180 continue; | |
181 } | |
182 | |
183 WebFeaturePolicy::ParsedWhitelist whitelist; | |
184 whitelist.featureName = featureName; | |
185 Vector<WebSecurityOrigin> origins; | |
186 String targetString; | |
187 for (size_t j = 0; j < targets->size(); ++j) { | |
188 if (targets->at(j)->asString(&targetString)) { | |
189 if (equalIgnoringCase(targetString, "self")) { | |
190 if (!origin->isUnique()) | |
iclelland
2016/11/30 22:13:10
This isn't strictly necessary for the policy objec
Marijn Kruisselbrink
2016/11/30 22:21:00
This is not true. isSameSchemeHostPort() starts wi
raymes
2016/11/30 23:18:23
Good point - I guess it just felt weird to add a u
iclelland
2016/12/01 03:31:25
You're absolutely right -- when I went to check to
| |
191 origins.append(origin); | |
192 } else if (targetString == "*") { | |
193 whitelist.matchesAllOrigins = true; | |
194 } else { | |
195 WebSecurityOrigin targetOrigin = | |
196 WebSecurityOrigin::createFromString(targetString); | |
197 if (!targetOrigin.isNull() && !targetOrigin.isUnique()) | |
198 origins.append(targetOrigin); | |
199 } | |
200 } else { | |
201 if (messages) | |
202 messages->append("Whitelist is not an array of strings."); | |
203 } | |
204 } | |
205 whitelist.origins = origins; | |
206 whitelists.append(whitelist); | |
207 } | |
208 } | |
209 return whitelists; | |
210 } | |
211 | |
212 void FeaturePolicy::setHeaderPolicy(const WebParsedFeaturePolicy& policy) { | |
213 DCHECK(m_headerWhitelists.isEmpty()); | |
214 for (const WebFeaturePolicy::ParsedWhitelist& parsedWhitelist : policy) { | |
215 const FeaturePolicy::Feature* feature = | |
216 featureForName(parsedWhitelist.featureName, m_features); | |
217 if (!feature) | |
218 continue; | |
219 m_headerWhitelists.set(feature, Whitelist::from(parsedWhitelist)); | |
220 } | |
212 } | 221 } |
213 | 222 |
214 bool FeaturePolicy::isFeatureEnabledForOrigin( | 223 bool FeaturePolicy::isFeatureEnabledForOrigin( |
215 const FeaturePolicy::Feature& feature, | 224 const FeaturePolicy::Feature& feature, |
216 const SecurityOrigin& origin) const { | 225 const SecurityOrigin& origin) const { |
217 DCHECK(m_inheritedFeatures.contains(&feature)); | 226 DCHECK(m_inheritedFeatures.contains(&feature)); |
218 if (!m_inheritedFeatures.get(&feature)) { | 227 if (!m_inheritedFeatures.get(&feature)) { |
219 return false; | 228 return false; |
220 } | 229 } |
221 if (m_headerWhitelists.contains(&feature)) { | 230 if (m_headerWhitelists.contains(&feature)) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 sb.append(" "); | 267 sb.append(" "); |
259 sb.append(whitelist.key->featureName); | 268 sb.append(whitelist.key->featureName); |
260 sb.append(": "); | 269 sb.append(": "); |
261 sb.append(whitelist.value->toString()); | 270 sb.append(whitelist.value->toString()); |
262 sb.append("\n"); | 271 sb.append("\n"); |
263 } | 272 } |
264 return sb.toString(); | 273 return sb.toString(); |
265 } | 274 } |
266 | 275 |
267 } // namespace blink | 276 } // namespace blink |
OLD | NEW |