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

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: Addressing review comments from PS#13 and #15 Created 4 years, 1 month 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/JSONValues.h"
8 #include "platform/network/HTTPParsers.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 FeatureList& features) {
21 for (const FeaturePolicyFeature* feature : features) {
22 if (featureName == feature->featureName)
23 return feature;
24 }
25 return nullptr;
26 }
27
28 // Converts a list of JSON feature policy items into a mapping of features to
29 // whitelists. For future compatibility, unrecognized features are simply
30 // ignored, as are unparseable origins. Any errors in the input will cause an
31 // error message appended to |messages|.
32 HashMap<const FeaturePolicyFeature*, std::unique_ptr<FeaturePolicy::Whitelist>>
33 parseFeaturePolicyString(std::unique_ptr<JSONArray> policyItems,
34 RefPtr<SecurityOrigin> origin,
35 FeatureList& features,
36 Vector<String>& messages) {
37 HashMap<const FeaturePolicyFeature*,
38 std::unique_ptr<FeaturePolicy::Whitelist>>
39 whitelists;
40
41 for (size_t i = 0; i < policyItems->size(); ++i) {
42 JSONObject* item = JSONObject::cast(policyItems->at(i));
43 if (!item) {
44 messages.append("Policy is not an object");
45 continue; // Array element is not an object; skip
46 }
47
48 for (size_t j = 0; j < item->size(); ++j) {
49 JSONObject::Entry entry = item->at(j);
50 String featureName = entry.first;
51 JSONArray* targets = JSONArray::cast(entry.second);
52 if (!targets) {
53 messages.append("Whitelist is not an array of strings");
54 continue; // Whitelist is not an array; skip
raymes 2016/10/23 23:31:05 nit: I think this comment is redundant now
iclelland 2016/10/24 05:14:32 Yes, it is :)
55 }
56
57 const FeaturePolicyFeature* feature =
58 featureForName(featureName, features);
59 if (!feature)
60 continue; // Feature is not recognized; skip
61
62 std::unique_ptr<FeaturePolicy::Whitelist> whitelist(
63 new FeaturePolicy::Whitelist);
64 String targetString;
65 for (size_t j = 0; j < targets->size(); ++j) {
66 if (targets->at(j)->asString(&targetString)) {
67 if (equalIgnoringCase(targetString, "self")) {
68 whitelist->add(origin);
69 } else if (targetString == "*") {
70 whitelist->addAll();
71 } else {
72 KURL originUrl = KURL(KURL(), targetString);
73 if (originUrl.isValid()) {
74 whitelist->add(SecurityOrigin::create(originUrl));
75 }
76 }
77 } else {
78 messages.append("Whitelist is not an array of strings");
79 }
80 }
81 whitelists.set(feature, std::move(whitelist));
82 }
83 }
84 return whitelists;
85 }
86
87 } // namespace
88
89 // Definitions of all features controlled by Feature Policy should appear here.
90 const FeaturePolicyFeature kDocumentCookie{
91 "cookie", FeaturePolicyFeatureDefault::EnableForAll};
92 const FeaturePolicyFeature kDocumentDomain{
93 "domain", FeaturePolicyFeatureDefault::EnableForAll};
94 const FeaturePolicyFeature kDocumentWrite{
95 "docwrite", FeaturePolicyFeatureDefault::EnableForAll};
96 const FeaturePolicyFeature kGeolocationFeature{
97 "geolocation", FeaturePolicyFeatureDefault::EnableForSelf};
98 const FeaturePolicyFeature kMidiFeature{
99 "midi", FeaturePolicyFeatureDefault::EnableForAll};
100 const FeaturePolicyFeature kNotificationsFeature{
101 "notifications", FeaturePolicyFeatureDefault::EnableForAll};
102 const FeaturePolicyFeature kPaymentFeature{
103 "payment", FeaturePolicyFeatureDefault::EnableForSelf};
104 const FeaturePolicyFeature kPushFeature{
105 "push", FeaturePolicyFeatureDefault::EnableForAll};
106 const FeaturePolicyFeature kSyncScript{
107 "sync-script", FeaturePolicyFeatureDefault::EnableForAll};
108 const FeaturePolicyFeature kSyncXHR{"sync-xhr",
109 FeaturePolicyFeatureDefault::EnableForAll};
110 const FeaturePolicyFeature kUsermedia{
111 "usermedia", FeaturePolicyFeatureDefault::EnableForAll};
112 const FeaturePolicyFeature kVibrateFeature{
113 "vibrate", FeaturePolicyFeatureDefault::EnableForSelf};
114 const FeaturePolicyFeature kWebRTC{"webrtc",
115 FeaturePolicyFeatureDefault::EnableForAll};
116
117 FeaturePolicy::Whitelist::Whitelist() : m_matchesAllOrigins(false) {}
118
119 void FeaturePolicy::Whitelist::addAll() {
120 m_matchesAllOrigins = true;
121 }
122
123 void FeaturePolicy::Whitelist::add(RefPtr<SecurityOrigin> origin) {
124 m_origins.append(std::move(origin));
125 }
126
127 bool FeaturePolicy::Whitelist::contains(const SecurityOrigin& origin) const {
128 if (m_matchesAllOrigins)
129 return true;
130 for (const auto& targetOrigin : m_origins) {
131 if (targetOrigin->isSameSchemeHostPortAndSuborigin(&origin))
132 return true;
133 }
134 return false;
135 }
136
137 String FeaturePolicy::Whitelist::toString() {
138 StringBuilder sb;
139 sb.append("[");
140 if (m_matchesAllOrigins) {
141 sb.append("*");
142 } else {
143 for (size_t i = 0; i < m_origins.size(); ++i) {
144 if (i > 0) {
145 sb.append(", ");
146 }
147 sb.append(m_origins[i]->toString());
148 }
149 }
150 sb.append("]");
151 return sb.toString();
152 }
153
154 // static
155 const FeatureList& FeaturePolicy::getDefaultFeatureList() {
156 DEFINE_STATIC_LOCAL(
157 Vector<const FeaturePolicyFeature*>, defaultFeatureList,
158 ({&kDocumentCookie, &kDocumentDomain, &kDocumentWrite,
159 &kGeolocationFeature, &kMidiFeature, &kNotificationsFeature,
160 &kPaymentFeature, &kPushFeature, &kSyncScript, &kSyncXHR, &kUsermedia,
161 &kVibrateFeature, &kWebRTC}));
162 return defaultFeatureList;
163 }
164
165 // static
166 FeaturePolicy* FeaturePolicy::createFromParentPolicy(
167 const FeaturePolicy* parent,
168 RefPtr<SecurityOrigin> currentOrigin,
169 FeatureList& features) {
170 DCHECK(currentOrigin);
171 FeaturePolicy* newPolicy = new FeaturePolicy(currentOrigin, features);
172 for (const FeaturePolicyFeature* feature : features) {
173 if (!parent || parent->isFeatureEnabledForOrigin(feature, *currentOrigin)) {
174 newPolicy->m_inheritedFeatures.set(feature, true);
175 } else {
176 newPolicy->m_inheritedFeatures.set(feature, false);
177 }
178 }
179 return newPolicy;
180 }
181
182 // static
183 FeaturePolicy* FeaturePolicy::createFromParentPolicy(
184 const FeaturePolicy* parent,
185 RefPtr<SecurityOrigin> currentOrigin) {
186 return createFromParentPolicy(parent, currentOrigin, getDefaultFeatureList());
187 }
188
189 void FeaturePolicy::setHeaderPolicy(const String& policy,
190 Vector<String>& messages) {
191 DCHECK(m_headerWhitelists.isEmpty());
192 std::unique_ptr<JSONArray> policyJSON = parseJSONHeader(policy);
193 if (!policyJSON) {
194 messages.append("Unable to parse header");
195 return;
196 }
197 m_headerWhitelists = parseFeaturePolicyString(std::move(policyJSON), m_origin,
198 m_features, messages);
199 }
200
201 bool FeaturePolicy::isFeatureEnabledForOrigin(
202 const FeaturePolicyFeature* feature,
203 const SecurityOrigin& origin) const {
204 DCHECK(m_inheritedFeatures.contains(feature));
205 if (!m_inheritedFeatures.get(feature)) {
206 return false;
207 }
208 if (m_headerWhitelists.contains(feature)) {
209 return m_headerWhitelists.get(feature)->contains(origin);
210 }
211 if (feature->defaultPolicy == FeaturePolicyFeatureDefault::EnableForAll) {
212 return true;
213 }
214 if (feature->defaultPolicy == FeaturePolicyFeatureDefault::EnableForSelf) {
215 return m_origin->isSameSchemeHostPortAndSuborigin(&origin);
216 }
217 return false;
218 }
219
220 bool FeaturePolicy::isFeatureEnabled(
221 const FeaturePolicyFeature* feature) const {
222 DCHECK(m_origin);
223 return isFeatureEnabledForOrigin(feature, *m_origin);
224 }
225
226 FeaturePolicy::FeaturePolicy(RefPtr<SecurityOrigin> currentOrigin,
227 FeatureList& features)
228 : m_origin(std::move(currentOrigin)), m_features(features) {}
229
230 String FeaturePolicy::toString() {
231 StringBuilder sb;
232 sb.append("Feature Policy for frame in origin: ");
233 sb.append(m_origin->toString());
234 sb.append("\n");
235 sb.append("Inherited features:\n");
236 for (const auto& inheritedFeature : m_inheritedFeatures) {
237 sb.append(" ");
238 sb.append(inheritedFeature.key->featureName);
239 sb.append(": ");
240 sb.append(inheritedFeature.value ? "true" : "false");
241 sb.append("\n");
242 }
243 sb.append("Header whitelists:\n");
244 for (const auto& whitelist : m_headerWhitelists) {
245 sb.append(" ");
246 sb.append(whitelist.key->featureName);
247 sb.append(": ");
248 sb.append(whitelist.value->toString());
249 sb.append("\n");
250 }
251 return sb.toString();
252 }
253
254 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698