| 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/RuntimeEnabledFeatures.h" | 7 #include "platform/RuntimeEnabledFeatures.h" |
| 8 #include "platform/json/JSONValues.h" | 8 #include "platform/json/JSONValues.h" |
| 9 #include "platform/network/HTTPParsers.h" | 9 #include "platform/network/HTTPParsers.h" |
| 10 #include "platform/weborigin/KURL.h" | |
| 11 #include "platform/weborigin/SecurityOrigin.h" | 10 #include "platform/weborigin/SecurityOrigin.h" |
| 12 #include "wtf/PtrUtil.h" | 11 #include "wtf/PtrUtil.h" |
| 13 #include "wtf/text/StringBuilder.h" | |
| 14 | 12 |
| 15 namespace blink { | 13 namespace blink { |
| 16 | 14 |
| 17 namespace { | 15 WebFeaturePolicyFeature getWebFeaturePolicyFeature(const String& feature) { |
| 18 | |
| 19 // Given a string name, return the matching feature struct, or nullptr if it is | |
| 20 // not the name of a policy-controlled feature. | |
| 21 const FeaturePolicy::Feature* featureForName( | |
| 22 const String& featureName, | |
| 23 FeaturePolicy::FeatureList& features) { | |
| 24 for (const FeaturePolicy::Feature* feature : features) { | |
| 25 if (featureName == feature->featureName) | |
| 26 return feature; | |
| 27 } | |
| 28 return nullptr; | |
| 29 } | |
| 30 | |
| 31 } // namespace | |
| 32 | |
| 33 // Definitions of all features controlled by Feature Policy should appear here. | |
| 34 const FeaturePolicy::Feature kDocumentCookie{ | |
| 35 "cookie", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 36 const FeaturePolicy::Feature kDocumentDomain{ | |
| 37 "domain", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 38 const FeaturePolicy::Feature kDocumentWrite{ | |
| 39 "docwrite", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 40 const FeaturePolicy::Feature kFullscreenFeature{ | |
| 41 "fullscreen", FeaturePolicy::FeatureDefault::EnableForSelf}; | |
| 42 const FeaturePolicy::Feature kGeolocationFeature{ | |
| 43 "geolocation", FeaturePolicy::FeatureDefault::EnableForSelf}; | |
| 44 const FeaturePolicy::Feature kMidiFeature{ | |
| 45 "midi", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 46 const FeaturePolicy::Feature kNotificationsFeature{ | |
| 47 "notifications", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 48 const FeaturePolicy::Feature kPaymentFeature{ | |
| 49 "payment", FeaturePolicy::FeatureDefault::EnableForSelf}; | |
| 50 const FeaturePolicy::Feature kPushFeature{ | |
| 51 "push", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 52 const FeaturePolicy::Feature kSyncScript{ | |
| 53 "sync-script", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 54 const FeaturePolicy::Feature kSyncXHR{ | |
| 55 "sync-xhr", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 56 const FeaturePolicy::Feature kUsermedia{ | |
| 57 "usermedia", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 58 const FeaturePolicy::Feature kVibrateFeature{ | |
| 59 "vibrate", FeaturePolicy::FeatureDefault::EnableForSelf}; | |
| 60 const FeaturePolicy::Feature kWebRTC{ | |
| 61 "webrtc", FeaturePolicy::FeatureDefault::EnableForAll}; | |
| 62 | |
| 63 WebFeaturePolicyFeature FeaturePolicy::getWebFeaturePolicyFeature( | |
| 64 const String& feature) { | |
| 65 if (feature == "fullscreen") | 16 if (feature == "fullscreen") |
| 66 return WebFeaturePolicyFeature::Fullscreen; | 17 return WebFeaturePolicyFeature::Fullscreen; |
| 67 if (feature == "payment") | 18 if (feature == "payment") |
| 68 return WebFeaturePolicyFeature::Payment; | 19 return WebFeaturePolicyFeature::Payment; |
| 69 if (feature == "vibrate") | 20 if (feature == "vibrate") |
| 70 return WebFeaturePolicyFeature::Vibrate; | 21 return WebFeaturePolicyFeature::Vibrate; |
| 71 if (feature == "usermedia") | 22 if (feature == "usermedia") |
| 72 return WebFeaturePolicyFeature::Usermedia; | 23 return WebFeaturePolicyFeature::Usermedia; |
| 73 if (RuntimeEnabledFeatures::featurePolicyExperimentalFeaturesEnabled()) { | 24 if (RuntimeEnabledFeatures::featurePolicyExperimentalFeaturesEnabled()) { |
| 74 if (feature == "cookie") | 25 if (feature == "cookie") |
| (...skipping 13 matching lines...) Expand all Loading... |
| 88 if (feature == "sync-script") | 39 if (feature == "sync-script") |
| 89 return WebFeaturePolicyFeature::SyncScript; | 40 return WebFeaturePolicyFeature::SyncScript; |
| 90 if (feature == "sync-xhr") | 41 if (feature == "sync-xhr") |
| 91 return WebFeaturePolicyFeature::SyncXHR; | 42 return WebFeaturePolicyFeature::SyncXHR; |
| 92 if (feature == "webrtc") | 43 if (feature == "webrtc") |
| 93 return WebFeaturePolicyFeature::WebRTC; | 44 return WebFeaturePolicyFeature::WebRTC; |
| 94 } | 45 } |
| 95 return WebFeaturePolicyFeature::NotFound; | 46 return WebFeaturePolicyFeature::NotFound; |
| 96 } | 47 } |
| 97 | 48 |
| 98 // static | 49 WebParsedFeaturePolicyHeader parseFeaturePolicy(const String& policy, |
| 99 std::unique_ptr<FeaturePolicy::Whitelist> FeaturePolicy::Whitelist::from( | 50 RefPtr<SecurityOrigin> origin, |
| 100 const WebParsedFeaturePolicyDeclaration& parsedDeclaration) { | 51 Vector<String>* messages) { |
| 101 std::unique_ptr<Whitelist> whitelist(new FeaturePolicy::Whitelist); | |
| 102 if (parsedDeclaration.matchesAllOrigins) { | |
| 103 whitelist->addAll(); | |
| 104 } else { | |
| 105 for (const WebSecurityOrigin& origin : parsedDeclaration.origins) | |
| 106 whitelist->add(static_cast<WTF::PassRefPtr<SecurityOrigin>>(origin)); | |
| 107 } | |
| 108 return whitelist; | |
| 109 } | |
| 110 | |
| 111 FeaturePolicy::Whitelist::Whitelist() : m_matchesAllOrigins(false) {} | |
| 112 | |
| 113 void FeaturePolicy::Whitelist::addAll() { | |
| 114 m_matchesAllOrigins = true; | |
| 115 } | |
| 116 | |
| 117 void FeaturePolicy::Whitelist::add(RefPtr<SecurityOrigin> origin) { | |
| 118 m_origins.push_back(std::move(origin)); | |
| 119 } | |
| 120 | |
| 121 bool FeaturePolicy::Whitelist::contains(const SecurityOrigin& origin) const { | |
| 122 if (m_matchesAllOrigins) | |
| 123 return true; | |
| 124 for (const auto& targetOrigin : m_origins) { | |
| 125 if (targetOrigin->isSameSchemeHostPortAndSuborigin(&origin)) | |
| 126 return true; | |
| 127 } | |
| 128 return false; | |
| 129 } | |
| 130 | |
| 131 String FeaturePolicy::Whitelist::toString() { | |
| 132 StringBuilder sb; | |
| 133 sb.append("["); | |
| 134 if (m_matchesAllOrigins) { | |
| 135 sb.append("*"); | |
| 136 } else { | |
| 137 for (size_t i = 0; i < m_origins.size(); ++i) { | |
| 138 if (i > 0) { | |
| 139 sb.append(", "); | |
| 140 } | |
| 141 sb.append(m_origins[i]->toString()); | |
| 142 } | |
| 143 } | |
| 144 sb.append("]"); | |
| 145 return sb.toString(); | |
| 146 } | |
| 147 | |
| 148 // static | |
| 149 const FeaturePolicy::FeatureList& FeaturePolicy::getDefaultFeatureList() { | |
| 150 DEFINE_STATIC_LOCAL( | |
| 151 Vector<const FeaturePolicy::Feature*>, defaultFeatureList, | |
| 152 ({&kDocumentCookie, &kDocumentDomain, &kDocumentWrite, | |
| 153 &kGeolocationFeature, &kFullscreenFeature, &kMidiFeature, | |
| 154 &kNotificationsFeature, &kPaymentFeature, &kPushFeature, &kSyncScript, | |
| 155 &kSyncXHR, &kUsermedia, &kVibrateFeature, &kWebRTC})); | |
| 156 return defaultFeatureList; | |
| 157 } | |
| 158 | |
| 159 // static | |
| 160 std::unique_ptr<FeaturePolicy> FeaturePolicy::createFromParentPolicy( | |
| 161 const FeaturePolicy* parent, | |
| 162 const WebParsedFeaturePolicyHeader* containerPolicy, | |
| 163 RefPtr<SecurityOrigin> currentOrigin, | |
| 164 FeaturePolicy::FeatureList& features) { | |
| 165 DCHECK(currentOrigin); | |
| 166 std::unique_ptr<FeaturePolicy> newPolicy = | |
| 167 WTF::wrapUnique(new FeaturePolicy(currentOrigin, features)); | |
| 168 for (const FeaturePolicy::Feature* feature : features) { | |
| 169 if (!parent || | |
| 170 parent->isFeatureEnabledForOrigin(*feature, *currentOrigin)) { | |
| 171 newPolicy->m_inheritedFeatures.set(feature, true); | |
| 172 } else { | |
| 173 newPolicy->m_inheritedFeatures.set(feature, false); | |
| 174 } | |
| 175 } | |
| 176 if (containerPolicy) | |
| 177 newPolicy->addContainerPolicy(containerPolicy, parent); | |
| 178 return newPolicy; | |
| 179 } | |
| 180 | |
| 181 // static | |
| 182 std::unique_ptr<FeaturePolicy> FeaturePolicy::createFromParentPolicy( | |
| 183 const FeaturePolicy* parent, | |
| 184 const WebParsedFeaturePolicyHeader* containerPolicy, | |
| 185 RefPtr<SecurityOrigin> currentOrigin) { | |
| 186 return createFromParentPolicy(parent, containerPolicy, | |
| 187 std::move(currentOrigin), | |
| 188 getDefaultFeatureList()); | |
| 189 } | |
| 190 | |
| 191 void FeaturePolicy::addContainerPolicy( | |
| 192 const WebParsedFeaturePolicyHeader* containerPolicy, | |
| 193 const FeaturePolicy* parent) { | |
| 194 DCHECK(containerPolicy); | |
| 195 DCHECK(parent); | |
| 196 for (const WebParsedFeaturePolicyDeclaration& parsedDeclaration : | |
| 197 *containerPolicy) { | |
| 198 // If a feature is enabled in the parent frame, and the parent chooses to | |
| 199 // delegate it to the child frame, using the iframe attribute, then the | |
| 200 // feature should be enabled in the child frame. | |
| 201 const FeaturePolicy::Feature* feature = | |
| 202 featureForName(parsedDeclaration.featureName, m_features); | |
| 203 if (!feature) | |
| 204 continue; | |
| 205 if (Whitelist::from(parsedDeclaration)->contains(*m_origin) && | |
| 206 parent->isFeatureEnabled(*feature)) { | |
| 207 m_inheritedFeatures.set(feature, true); | |
| 208 } else { | |
| 209 m_inheritedFeatures.set(feature, false); | |
| 210 } | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 // static | |
| 215 WebParsedFeaturePolicyHeader FeaturePolicy::parseFeaturePolicy( | |
| 216 const String& policy, | |
| 217 RefPtr<SecurityOrigin> origin, | |
| 218 Vector<String>* messages) { | |
| 219 Vector<WebParsedFeaturePolicyDeclaration> whitelists; | 52 Vector<WebParsedFeaturePolicyDeclaration> whitelists; |
| 220 | 53 |
| 221 // Use a reasonable parse depth limit; the actual maximum depth is only going | 54 // Use a reasonable parse depth limit; the actual maximum depth is only going |
| 222 // to be 4 for a valid policy, but we'll give the featurePolicyParser a chance | 55 // to be 4 for a valid policy, but we'll give the featurePolicyParser a chance |
| 223 // to report more specific errors, unless the string is really invalid. | 56 // to report more specific errors, unless the string is really invalid. |
| 224 std::unique_ptr<JSONArray> policyItems = parseJSONHeader(policy, 50); | 57 std::unique_ptr<JSONArray> policyItems = parseJSONHeader(policy, 50); |
| 225 if (!policyItems) { | 58 if (!policyItems) { |
| 226 if (messages) | 59 if (messages) |
| 227 messages->push_back("Unable to parse header"); | 60 messages->push_back("Unable to parse header"); |
| 228 return whitelists; | 61 return whitelists; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 messages->push_back("Whitelist is not an array of strings."); | 101 messages->push_back("Whitelist is not an array of strings."); |
| 269 } | 102 } |
| 270 } | 103 } |
| 271 whitelist.origins = origins; | 104 whitelist.origins = origins; |
| 272 whitelists.push_back(whitelist); | 105 whitelists.push_back(whitelist); |
| 273 } | 106 } |
| 274 } | 107 } |
| 275 return whitelists; | 108 return whitelists; |
| 276 } | 109 } |
| 277 | 110 |
| 278 void FeaturePolicy::setHeaderPolicy( | |
| 279 const WebParsedFeaturePolicyHeader& policy) { | |
| 280 DCHECK(m_headerWhitelists.isEmpty()); | |
| 281 for (const WebParsedFeaturePolicyDeclaration& parsedDeclaration : policy) { | |
| 282 const FeaturePolicy::Feature* feature = | |
| 283 featureForName(parsedDeclaration.featureName, m_features); | |
| 284 if (!feature) | |
| 285 continue; | |
| 286 m_headerWhitelists.set(feature, Whitelist::from(parsedDeclaration)); | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 bool FeaturePolicy::isFeatureEnabledForOrigin( | |
| 291 const FeaturePolicy::Feature& feature, | |
| 292 const SecurityOrigin& origin) const { | |
| 293 DCHECK(m_inheritedFeatures.contains(&feature)); | |
| 294 if (!m_inheritedFeatures.at(&feature)) { | |
| 295 return false; | |
| 296 } | |
| 297 if (m_headerWhitelists.contains(&feature)) { | |
| 298 return m_headerWhitelists.at(&feature)->contains(origin); | |
| 299 } | |
| 300 if (feature.defaultPolicy == FeaturePolicy::FeatureDefault::EnableForAll) { | |
| 301 return true; | |
| 302 } | |
| 303 if (feature.defaultPolicy == FeaturePolicy::FeatureDefault::EnableForSelf) { | |
| 304 return m_origin->isSameSchemeHostPortAndSuborigin(&origin); | |
| 305 } | |
| 306 return false; | |
| 307 } | |
| 308 | |
| 309 bool FeaturePolicy::isFeatureEnabled( | |
| 310 const FeaturePolicy::Feature& feature) const { | |
| 311 DCHECK(m_origin); | |
| 312 return isFeatureEnabledForOrigin(feature, *m_origin); | |
| 313 } | |
| 314 | |
| 315 FeaturePolicy::FeaturePolicy(RefPtr<SecurityOrigin> currentOrigin, | |
| 316 FeaturePolicy::FeatureList& features) | |
| 317 : m_origin(std::move(currentOrigin)), m_features(features) {} | |
| 318 | |
| 319 String FeaturePolicy::toString() { | |
| 320 StringBuilder sb; | |
| 321 sb.append("Feature Policy for frame in origin: "); | |
| 322 sb.append(m_origin->toString()); | |
| 323 sb.append("\n"); | |
| 324 sb.append("Inherited features:\n"); | |
| 325 for (const auto& inheritedFeature : m_inheritedFeatures) { | |
| 326 sb.append(" "); | |
| 327 sb.append(inheritedFeature.key->featureName); | |
| 328 sb.append(": "); | |
| 329 sb.append(inheritedFeature.value ? "true" : "false"); | |
| 330 sb.append("\n"); | |
| 331 } | |
| 332 sb.append("Header whitelists:\n"); | |
| 333 for (const auto& whitelist : m_headerWhitelists) { | |
| 334 sb.append(" "); | |
| 335 sb.append(whitelist.key->featureName); | |
| 336 sb.append(": "); | |
| 337 sb.append(whitelist.value->toString()); | |
| 338 sb.append("\n"); | |
| 339 } | |
| 340 return sb.toString(); | |
| 341 } | |
| 342 | |
| 343 } // namespace blink | 111 } // namespace blink |
| OLD | NEW |