Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Side by Side Diff: third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp

Issue 2254533002: [FeaturePolicy] Initial implementation of Feature Policy (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fp-flag
Patch Set: Clean up; add remaining policy-controlled features Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "platform/feature_policy/FeaturePolicy.h"
6
7 #include "platform/json/JSONParser.h"
8 #include "platform/json/JSONValues.h"
9 #include "platform/weborigin/KURL.h"
10 #include "platform/weborigin/SecurityOrigin.h"
11 #include "wtf/text/StringBuilder.h"
12
13 namespace blink {
14
15 namespace {
16
17 // Given a string name, return the matching feature struct, or nullptr if it is
18 // not the name of a policy-controlled feature.
19 const FeaturePolicyFeature* featureForName(const String& featureName) {
20 for (const FeaturePolicyFeature* feature :
21 FeaturePolicy::getFeatureRegistry()) {
22 if (featureName == feature->featureName)
23 return feature;
24 }
25 return nullptr;
26 }
27
28 } // namespace
29
30 // Definitions of all features controlled by Feature Policy should appear here.
31 const FeaturePolicyFeature kDocumentCookie{"cookie",
32 kEnableFeatureForAllOrigins};
33 const FeaturePolicyFeature kDocumentDomain{"domain",
34 kEnableFeatureForAllOrigins};
35 const FeaturePolicyFeature kDocumentWrite{"docwrite",
36 kEnableFeatureForAllOrigins};
37 const FeaturePolicyFeature kGeolocationFeature{"geolocation",
38 kEnableFeatureForSelf};
39 const FeaturePolicyFeature kMidiFeature{"midi", kEnableFeatureForAllOrigins};
40 const FeaturePolicyFeature kNotificationsFeature{"notifications",
41 kEnableFeatureForAllOrigins};
42 const FeaturePolicyFeature kPaymentFeature{"payment", kEnableFeatureForSelf};
43 const FeaturePolicyFeature kPushFeature{"push", kEnableFeatureForAllOrigins};
44 const FeaturePolicyFeature kSyncScript{"sync-script",
45 kEnableFeatureForAllOrigins};
46 const FeaturePolicyFeature kSyncXHR{"sync-xhr", kEnableFeatureForAllOrigins};
47 const FeaturePolicyFeature kUsermedia{"usermedia", kEnableFeatureForAllOrigins};
48 const FeaturePolicyFeature kVibrateFeature{"vibrate", kEnableFeatureForSelf};
49 const FeaturePolicyFeature kWebRTC{"webrtc", kEnableFeatureForAllOrigins};
50
51 FeaturePolicy::Whitelist::Whitelist() : m_matchesAllOrigins(false) {}
52
53 void FeaturePolicy::Whitelist::addAll() {
54 m_matchesAllOrigins = true;
55 }
56
57 void FeaturePolicy::Whitelist::add(RefPtr<SecurityOrigin> origin) {
58 m_origins.append(origin);
dcheng 2016/10/14 20:33:17 Nit: std::move()
iclelland 2016/10/19 12:51:55 Done.
59 }
60
61 bool FeaturePolicy::Whitelist::contains(const SecurityOrigin* origin) const {
dcheng 2016/10/14 20:33:17 Nit: const ref if we never expect this to be null.
iclelland 2016/10/19 12:51:55 Done.
62 if (m_matchesAllOrigins)
63 return true;
64 for (const auto& targetOrigin : m_origins) {
65 if (targetOrigin->isSameSchemeHostPortAndSuborigin(origin))
66 return true;
67 }
68 return false;
69 }
70
71 String FeaturePolicy::Whitelist::toString() {
72 StringBuilder sb;
73 sb.append("[");
74 if (m_matchesAllOrigins) {
75 sb.append("*");
76 } else {
77 for (size_t i = 0; i < m_origins.size(); ++i) {
78 if (i > 0) {
79 sb.append(", ");
80 }
81 sb.append(m_origins[i]->toString());
82 }
83 }
84 sb.append("]");
85 return sb.toString();
86 }
87
88 // static
89 Vector<const FeaturePolicyFeature*>& FeaturePolicy::getFeatureRegistry() {
90 DEFINE_STATIC_LOCAL(
dcheng 2016/10/14 20:33:17 No need to use a Vector here; range-based for loop
iclelland 2016/10/15 01:55:34 It's mostly a vector so that it can be appended to
91 Vector<const FeaturePolicyFeature*>, featureRegistry,
92 ({&kDocumentCookie, &kDocumentDomain, &kDocumentWrite,
93 &kGeolocationFeature, &kMidiFeature, &kNotificationsFeature,
94 &kPaymentFeature, &kPushFeature, &kSyncScript, &kSyncXHR, &kUsermedia,
95 &kVibrateFeature, &kWebRTC}));
96 return featureRegistry;
97 }
98
99 // static
100 FeaturePolicy* FeaturePolicy::createFromParentPolicy(
101 const FeaturePolicy* parent,
102 RefPtr<SecurityOrigin> currentOrigin) {
103 FeaturePolicy* newPolicy = new FeaturePolicy(currentOrigin);
104 if (parent) {
105 for (const FeaturePolicyFeature* feature : getFeatureRegistry()) {
106 if (parent->isFeatureEnabledForOrigin(feature, currentOrigin.get())) {
107 newPolicy->m_inheritedFeatures.set(feature, true);
108 } else {
109 newPolicy->m_inheritedFeatures.set(feature, false);
110 }
111 }
112 }
113 return newPolicy;
114 }
115
116 void FeaturePolicy::addPolicyFromString(const String& policy) {
raymes 2016/10/18 02:42:31 I don't like the "addPolicyFromString" name/approa
iclelland 2016/10/19 12:51:55 Done. Changed to setHeaderPolicy.
117 if (policy.isEmpty())
118 return;
raymes 2016/10/18 02:42:31 Can we have a check: DCHECK(m_declaredWhitelists.e
iclelland 2016/10/19 12:51:55 Done.
119 for (const auto& whitelist : parse(policy)) {
120 if (isFeatureEnabled(whitelist.key)) {
raymes 2016/10/18 02:42:31 I think this check is complex and hard to verify c
121 m_declaredWhitelists.set(whitelist.key, whitelist.value);
raymes 2016/10/18 02:42:30 nit: Could we just call this m_headerWhitelists fo
iclelland 2016/10/19 12:51:55 Done.
122 }
123 }
124 }
125
126 bool FeaturePolicy::isFeatureEnabledForOrigin(
127 const FeaturePolicyFeature* feature,
128 const SecurityOrigin* origin) const {
raymes 2016/10/18 02:42:31 It would be nice to link to an algorithm here but
iclelland 2016/10/19 12:51:55 Acknowledged.
129 if (m_inheritedFeatures.contains(feature)) {
raymes 2016/10/18 02:42:31 I think the behavior if a feature isn't in the map
iclelland 2016/10/19 12:51:55 Done. That matches the current text in the explain
130 if (!m_inheritedFeatures.get(feature)) {
131 return false;
132 }
133 }
134 if (m_declaredWhitelists.contains(feature)) {
135 return m_declaredWhitelists.get(feature)->contains(origin);
136 }
137 if (feature->defaultPolicy == kEnableFeatureForAllOrigins) {
138 return true;
139 }
140 if (feature->defaultPolicy == kEnableFeatureForSelf) {
141 return m_origin->isSameSchemeHostPortAndSuborigin(origin);
142 }
143 return false;
144 }
145
146 bool FeaturePolicy::isFeatureEnabled(
147 const FeaturePolicyFeature* feature) const {
148 return isFeatureEnabledForOrigin(feature, m_origin.get());
149 }
150
151 FeaturePolicy::FeaturePolicy(PassRefPtr<SecurityOrigin> currentOrigin)
dcheng 2016/10/14 20:33:17 Nit: PassRefPtr is on the way out. Just use RefPtr
iclelland 2016/10/19 12:51:55 Done.
152 : m_origin(currentOrigin) {}
153
154 // Parses a feature policy string into a mapping of features to whitelists. The
155 // parse algorithm is deliberately very lenient, and will return as much as it
156 // can recognize. Unrecognized features are simply ignored, as are invalid
157 // policy items and invalid origins inside of whitelists.
158 HeapHashMap<const FeaturePolicyFeature*, Member<FeaturePolicy::Whitelist>>
159 FeaturePolicy::parse(const String& policy) {
raymes 2016/10/18 02:42:31 I think parsing code tends to fit better not as a
iclelland 2016/10/19 12:51:55 Done. Renamed and moved to the anonymous namespace
160 HeapHashMap<const FeaturePolicyFeature*, Member<Whitelist>> whitelists;
161 std::unique_ptr<JSONValue> policyJSON = parseJSON(policy);
162
163 if (!policyJSON)
164 return whitelists; // Policy string is not valid JSON
165
166 std::unique_ptr<JSONArray> items = JSONArray::cast(std::move(policyJSON));
167 if (!items)
168 return whitelists; // Policy string is not an array
169
170 for (size_t i = 0; i < items->size(); ++i) {
171 JSONObject* item = JSONObject::cast(items->at(i));
172 if (!item)
173 continue; // Array element is not an object; skip
raymes 2016/10/18 02:42:31 Hmm, should we just give up at each of these failu
iclelland 2016/10/19 12:51:55 We can't fail at "Feature not recognized", as that
raymes 2016/10/19 23:47:36 That all sounds good to me :) I'm happy if you wan
174
175 for (size_t j = 0; j < item->size(); ++j) {
176 JSONObject::Entry entry = item->at(j);
177 String featureName = entry.first;
178 const FeaturePolicyFeature* feature = featureForName(featureName);
179 if (!feature)
180 continue; // Feature is not recognized; skip
181
182 JSONArray* targets = JSONArray::cast(entry.second);
183 if (!targets)
184 continue; // Whitelist is not an array; skip
185
186 Whitelist* whitelist = new Whitelist;
187 String targetString;
188 for (size_t j = 0; j < targets->size(); ++j) {
189 if (targets->at(j)->asString(&targetString)) {
190 if (equalIgnoringCase(targetString, "self")) {
191 whitelist->add(m_origin);
192 } else if (targetString == "*") {
193 whitelist->addAll();
194 } else {
195 KURL originUrl = KURL(KURL(), targetString);
196 if (originUrl.isValid()) {
197 whitelist->add(SecurityOrigin::create(originUrl));
198 }
199 }
200 }
201 }
202 whitelists.set(feature, whitelist);
203 }
204 }
205 return whitelists;
206 }
207
208 String FeaturePolicy::toString() {
209 StringBuilder sb;
210 sb.append("Feature Policy for frame in origin: ");
211 sb.append(m_origin->toString());
212 sb.append("\n");
213 sb.append("Inherited features:\n");
214 for (const auto& inheritedFeature : m_inheritedFeatures) {
raymes 2016/10/18 02:42:30 nit, optional: should we indent the string here fo
iclelland 2016/10/19 12:51:55 Done. This code is currently just so I can log the
215 sb.append(inheritedFeature.key->featureName);
216 sb.append(": ");
217 sb.append(inheritedFeature.value ? "true" : "false");
218 sb.append("\n");
219 }
220 sb.append("Declared whitelists:\n");
221 for (const auto& whitelist : m_declaredWhitelists) {
raymes 2016/10/18 02:42:31 nit: same here
iclelland 2016/10/19 12:51:55 Done.
222 sb.append(whitelist.key->featureName);
223 sb.append(": ");
224 sb.append(whitelist.value->toString());
225 sb.append("\n");
226 }
227 return sb.toString();
228 }
229
230 DEFINE_TRACE(FeaturePolicy) {
231 visitor->trace(m_declaredWhitelists);
232 }
233
234 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698