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

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

Powered by Google App Engine
This is Rietveld 408576698