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

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

Powered by Google App Engine
This is Rietveld 408576698