Chromium Code Reviews| 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 |