OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 "chrome/common/extensions/manifest.h" | |
6 | |
7 #include <algorithm> | |
8 #include <set> | |
9 #include <string> | |
10 | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "base/values.h" | |
14 #include "chrome/common/extensions/extension_constants.h" | |
15 #include "chrome/common/extensions/extension_error_utils.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 namespace keys = extension_manifest_keys; | |
19 namespace errors = extension_manifest_errors; | |
20 | |
21 namespace extensions { | |
22 | |
23 namespace { | |
24 | |
25 // Keys that define types. | |
26 const char* kTypeKeys[] = { | |
27 keys::kApp, | |
28 keys::kTheme, | |
29 keys::kPlatformApp | |
30 }; | |
31 | |
32 // Keys that are not accesible by themes. | |
33 const char* kNotThemeKeys[] = { | |
Aaron Boodman
2011/12/01 21:32:04
Instead of duplicating these lists, can you expose
jstritar
2011/12/02 16:26:33
These don't test much if we use the values from ma
| |
34 keys::kBrowserAction, | |
35 keys::kPageAction, | |
36 keys::kPageActions, | |
37 keys::kChromeURLOverrides, | |
38 keys::kPermissions, | |
39 keys::kOptionalPermissions, | |
40 keys::kOptionsPage, | |
41 keys::kBackground, | |
42 keys::kOfflineEnabled, | |
43 keys::kMinimumChromeVersion, | |
44 keys::kRequirements, | |
45 keys::kConvertedFromUserScript, | |
46 keys::kNaClModules, | |
47 keys::kPlugins, | |
48 keys::kContentScripts, | |
49 keys::kOmnibox, | |
50 keys::kDevToolsPage, | |
51 keys::kSidebar, | |
52 keys::kHomepageURL, | |
53 keys::kContentSecurityPolicy, | |
54 keys::kFileBrowserHandlers, | |
55 keys::kIncognito, | |
56 keys::kInputComponents, | |
57 keys::kTtsEngine, | |
58 keys::kIntents | |
59 }; | |
60 | |
61 // Keys that are not accessible by hosted apps. | |
62 const char* kNotHostedAppKeys[] = { | |
63 keys::kBrowserAction, | |
64 keys::kPageAction, | |
65 keys::kPageActions, | |
66 keys::kChromeURLOverrides, | |
67 keys::kContentScripts, | |
68 keys::kOmnibox, | |
69 keys::kDevToolsPage, | |
70 keys::kSidebar, | |
71 keys::kHomepageURL, | |
72 keys::kContentSecurityPolicy, | |
73 keys::kFileBrowserHandlers, | |
74 keys::kIncognito, | |
75 keys::kInputComponents, | |
76 keys::kTtsEngine, | |
77 keys::kIntents | |
78 }; | |
79 | |
80 // Keys not accessible by packaged aps. | |
81 const char* kNotPackagedAppKeys[] = { | |
82 keys::kBrowserAction, | |
83 keys::kPageAction, | |
84 keys::kPageActions, | |
85 keys::kChromeURLOverrides, | |
86 }; | |
87 | |
88 // Keys not accessible by platform apps. | |
89 const char* kNotPlatformAppKeys[] = { | |
90 keys::kBrowserAction, | |
91 keys::kPageAction, | |
92 keys::kPageActions, | |
93 keys::kChromeURLOverrides, | |
94 keys::kContentScripts, | |
95 keys::kOmnibox, | |
96 keys::kDevToolsPage, | |
97 keys::kSidebar, | |
98 keys::kHomepageURL, | |
99 }; | |
100 | |
101 // Returns all the manifest keys not including those in |filtered| or kTypeKeys. | |
102 std::set<std::string> GetAccessibleKeys(const char* filtered[], size_t length) { | |
103 std::set<std::string> all_keys = Manifest::GetAllKnownKeys(); | |
104 std::set<std::string> filtered_keys(filtered, filtered + length); | |
105 | |
106 // Starting with all possible manfiest keys, remove the keys that aren't | |
107 // accessible for the given type. | |
108 std::set<std::string> intermediate; | |
109 std::set_difference(all_keys.begin(), all_keys.end(), | |
110 filtered_keys.begin(), filtered_keys.end(), | |
111 std::insert_iterator<std::set<std::string> >( | |
112 intermediate, intermediate.begin())); | |
113 | |
114 // Then remove the keys that specify types (app, platform_app, etc.). | |
115 std::set<std::string> result; | |
116 std::set<std::string> type_keys( | |
117 kTypeKeys, kTypeKeys + ARRAYSIZE_UNSAFE(kTypeKeys)); | |
118 std::set_difference(intermediate.begin(), intermediate.end(), | |
119 type_keys.begin(), type_keys.end(), | |
120 std::insert_iterator<std::set<std::string> >( | |
121 result, result.begin())); | |
122 | |
123 return result; | |
124 } | |
125 | |
126 } // namespace | |
127 | |
128 class ManifestTest : public testing::Test { | |
129 public: | |
130 ManifestTest() : default_value_("test") {} | |
131 | |
132 protected: | |
133 void AssertType(Manifest* manifest, Manifest::Type type) { | |
134 EXPECT_EQ(type, manifest->GetType()); | |
135 EXPECT_EQ(type == Manifest::kTypeTheme, manifest->IsTheme()); | |
136 EXPECT_EQ(type == Manifest::kTypePlatformApp, manifest->IsPlatformApp()); | |
137 EXPECT_EQ(type == Manifest::kTypePackagedApp, manifest->IsPackagedApp()); | |
138 EXPECT_EQ(type == Manifest::kTypeHostedApp, manifest->IsHostedApp()); | |
139 } | |
140 | |
141 void TestRestrictedKeys(Manifest* manifest, | |
142 const char* restricted_keys[], | |
143 size_t restricted_keys_length) { | |
144 // Verify that the keys on the restricted key list for the given manifest | |
145 // fail validation and are filtered out. | |
146 DictionaryValue* value = manifest->value(); | |
147 for (size_t i = 0; i < restricted_keys_length; ++i) { | |
148 std::string error, str; | |
149 value->Set(restricted_keys[i], Value::CreateStringValue(default_value_)); | |
150 EXPECT_FALSE(manifest->ValidateManifest(&error)); | |
151 EXPECT_EQ(error, ExtensionErrorUtils::FormatErrorMessage( | |
152 errors::kFeatureNotAllowed, restricted_keys[i])); | |
153 EXPECT_FALSE(manifest->GetString(restricted_keys[i], &str)); | |
154 EXPECT_TRUE(value->Remove(restricted_keys[i], NULL)); | |
155 } | |
156 } | |
157 | |
158 std::string default_value_; | |
159 }; | |
160 | |
161 // Verifies that extensions can access the correct keys. | |
162 TEST_F(ManifestTest, Extension) { | |
163 // Generate the list of keys accessible by extensions. | |
164 std::set<std::string> extension_keys = GetAccessibleKeys(NULL, 0u); | |
165 | |
166 // Construct the underlying value using every single key other than those | |
167 // on the restricted list.. We can use the same value for every key because we | |
168 // validate only by checking the presence of the keys. | |
169 DictionaryValue* value = new DictionaryValue(); | |
170 for (std::set<std::string>::iterator i = extension_keys.begin(); | |
171 i != extension_keys.end(); ++i) | |
172 value->Set(*i, Value::CreateStringValue(default_value_)); | |
173 | |
174 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
175 std::string error; | |
176 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
177 EXPECT_EQ("", error); | |
178 AssertType(manifest.get(), Manifest::kTypeExtension); | |
179 | |
180 // Verify that all the extension keys are accessible. | |
181 for (std::set<std::string>::iterator i = extension_keys.begin(); | |
182 i != extension_keys.end(); ++i) { | |
183 std::string value; | |
184 manifest->GetString(*i, &value); | |
185 EXPECT_EQ(default_value_, value) << *i; | |
186 } | |
187 | |
188 // Test DeepCopy and Equals. | |
189 scoped_ptr<Manifest> manifest2(manifest->DeepCopy()); | |
190 EXPECT_TRUE(manifest->Equals(manifest2.get())); | |
191 EXPECT_TRUE(manifest2->Equals(manifest.get())); | |
192 value->Set("foo", Value::CreateStringValue("blah")); | |
193 EXPECT_FALSE(manifest->Equals(manifest2.get())); | |
194 } | |
195 | |
196 // Verifies that themes can access the right keys. | |
197 TEST_F(ManifestTest, Theme) { | |
198 std::set<std::string> theme_keys = | |
199 GetAccessibleKeys(kNotThemeKeys, ARRAYSIZE_UNSAFE(kNotThemeKeys)); | |
200 | |
201 DictionaryValue* value = new DictionaryValue(); | |
202 for (std::set<std::string>::iterator i = theme_keys.begin(); | |
203 i != theme_keys.end(); ++i) | |
204 value->Set(*i, Value::CreateStringValue(default_value_)); | |
205 | |
206 std::string theme_key = keys::kTheme + std::string(".test"); | |
207 value->Set(theme_key, Value::CreateStringValue(default_value_)); | |
208 | |
209 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
210 std::string error; | |
211 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
212 EXPECT_EQ("", error); | |
213 AssertType(manifest.get(), Manifest::kTypeTheme); | |
214 | |
215 // Verify that all the theme keys are accessible. | |
216 std::string str; | |
217 for (std::set<std::string>::iterator i = theme_keys.begin(); | |
218 i != theme_keys.end(); ++i) { | |
219 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
220 EXPECT_EQ(default_value_, str) << *i; | |
221 } | |
222 EXPECT_TRUE(manifest->GetString(theme_key, &str)); | |
223 EXPECT_EQ(default_value_, str) << theme_key; | |
224 | |
225 // And that all the other keys fail validation and are filtered out | |
226 TestRestrictedKeys(manifest.get(), kNotThemeKeys, | |
227 ARRAYSIZE_UNSAFE(kNotThemeKeys)); | |
228 }; | |
229 | |
230 // Verifies that platform apps can access the right keys. | |
231 TEST_F(ManifestTest, PlatformApp) { | |
232 std::set<std::string> platform_keys = GetAccessibleKeys( | |
233 kNotPlatformAppKeys, | |
234 ARRAYSIZE_UNSAFE(kNotPlatformAppKeys)); | |
235 | |
236 DictionaryValue* value = new DictionaryValue(); | |
237 for (std::set<std::string>::iterator i = platform_keys.begin(); | |
238 i != platform_keys.end(); ++i) | |
239 value->Set(*i, Value::CreateStringValue(default_value_)); | |
240 | |
241 value->Set(keys::kPlatformApp, Value::CreateStringValue(default_value_)); | |
242 | |
243 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
244 std::string error; | |
245 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
246 EXPECT_EQ("", error); | |
247 AssertType(manifest.get(), Manifest::kTypePlatformApp); | |
248 | |
249 // Verify that all the platform app keys are accessible. | |
250 std::string str; | |
251 for (std::set<std::string>::iterator i = platform_keys.begin(); | |
252 i != platform_keys.end(); ++i) { | |
253 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
254 EXPECT_EQ(default_value_, str) << *i; | |
255 } | |
256 EXPECT_TRUE(manifest->GetString(keys::kPlatformApp, &str)); | |
257 EXPECT_EQ(default_value_, str) << keys::kPlatformApp; | |
258 | |
259 // And that all the other keys fail validation and are filtered out. | |
260 TestRestrictedKeys(manifest.get(), kNotPlatformAppKeys, | |
261 ARRAYSIZE_UNSAFE(kNotPlatformAppKeys)); | |
262 }; | |
263 | |
264 // Verifies that hosted apps can access the right keys. | |
Aaron Boodman
2011/12/01 21:32:04
At least for hosted apps (maybe other types too),
jstritar
2011/12/02 16:26:33
There wasn't too much overlap, but I got rid of Di
| |
265 TEST_F(ManifestTest, HostedApp) { | |
266 std::set<std::string> keys = GetAccessibleKeys( | |
267 kNotHostedAppKeys, | |
268 ARRAYSIZE_UNSAFE(kNotHostedAppKeys)); | |
269 | |
270 DictionaryValue* value = new DictionaryValue(); | |
271 for (std::set<std::string>::iterator i = keys.begin(); | |
272 i != keys.end(); ++i) | |
273 value->Set(*i, Value::CreateStringValue(default_value_)); | |
274 | |
275 value->Set(keys::kWebURLs, Value::CreateStringValue(default_value_)); | |
276 | |
277 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
278 std::string error; | |
279 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
280 EXPECT_EQ("", error); | |
281 AssertType(manifest.get(), Manifest::kTypeHostedApp); | |
282 | |
283 // Verify that all the hosted app keys are accessible. | |
284 std::string str; | |
285 for (std::set<std::string>::iterator i = keys.begin(); | |
286 i != keys.end(); ++i) { | |
287 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
288 EXPECT_EQ(default_value_, str) << *i; | |
289 } | |
290 EXPECT_TRUE(manifest->GetString(keys::kWebURLs, &str)); | |
291 EXPECT_EQ(default_value_, str) << keys::kWebURLs; | |
292 | |
293 // And that all the other keys fail validation and are filtered out. | |
294 TestRestrictedKeys(manifest.get(), kNotHostedAppKeys, | |
295 ARRAYSIZE_UNSAFE(kNotHostedAppKeys)); | |
296 }; | |
297 | |
298 // Verifies that packaged apps can access the right keys. | |
299 TEST_F(ManifestTest, PackagedApp) { | |
300 std::set<std::string> keys = GetAccessibleKeys( | |
301 kNotPackagedAppKeys, | |
302 ARRAYSIZE_UNSAFE(kNotPackagedAppKeys)); | |
303 | |
304 DictionaryValue* value = new DictionaryValue(); | |
305 for (std::set<std::string>::iterator i = keys.begin(); | |
306 i != keys.end(); ++i) | |
307 value->Set(*i, Value::CreateStringValue(default_value_)); | |
308 value->Set(keys::kApp, Value::CreateStringValue(default_value_)); | |
309 | |
310 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
311 std::string error; | |
312 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
313 EXPECT_EQ("", error); | |
314 AssertType(manifest.get(), Manifest::kTypePackagedApp); | |
315 | |
316 // Verify that all the packaged app keys are accessible. | |
317 std::string str; | |
318 for (std::set<std::string>::iterator i = keys.begin(); | |
319 i != keys.end(); ++i) { | |
320 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
321 EXPECT_EQ(default_value_, str) << *i; | |
322 } | |
323 EXPECT_TRUE(manifest->GetString(keys::kApp, &str)); | |
324 EXPECT_EQ(default_value_, str) << keys::kApp; | |
325 | |
326 // And that all the other keys fail validation and are filtered out. | |
327 TestRestrictedKeys(manifest.get(), kNotPackagedAppKeys, | |
328 ARRAYSIZE_UNSAFE(kNotPackagedAppKeys)); | |
329 }; | |
330 | |
331 // Verifies that the various getters filter unknown and restricted keys. | |
332 TEST_F(ManifestTest, Getters) { | |
333 DictionaryValue* value = new DictionaryValue(); | |
334 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
335 std::string unknown_key = "asdfaskldjf"; | |
336 | |
337 // Verify that the key filtering works for each of the getters. | |
338 // Get and GetBoolean | |
339 bool expected_bool = true, actual_bool = false; | |
340 value->Set(unknown_key, Value::CreateBooleanValue(expected_bool)); | |
341 EXPECT_FALSE(manifest->HasKey(unknown_key)); | |
342 EXPECT_FALSE(manifest->GetBoolean(unknown_key, &actual_bool)); | |
343 EXPECT_FALSE(actual_bool); | |
344 Value* actual_value = NULL; | |
345 EXPECT_FALSE(manifest->Get(unknown_key, &actual_value)); | |
346 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
347 | |
348 // GetInteger | |
349 int expected_int = 5, actual_int = 0; | |
350 value->Set(unknown_key, Value::CreateIntegerValue(expected_int)); | |
351 EXPECT_FALSE(manifest->GetInteger(unknown_key, &actual_int)); | |
352 EXPECT_NE(expected_int, actual_int); | |
353 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
354 | |
355 // GetString | |
356 std::string expected_str = "hello", actual_str; | |
357 value->Set(unknown_key, Value::CreateStringValue(expected_str)); | |
358 EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str)); | |
359 EXPECT_NE(expected_str, actual_str); | |
360 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
361 | |
362 // GetString (string16) | |
363 string16 expected_str16(UTF8ToUTF16("hello")), actual_str16; | |
364 value->Set(unknown_key, Value::CreateStringValue(expected_str16)); | |
365 EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str16)); | |
366 EXPECT_NE(expected_str16, actual_str16); | |
367 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
368 | |
369 // GetDictionary | |
370 DictionaryValue* expected_dict = new DictionaryValue(); | |
371 DictionaryValue* actual_dict = NULL; | |
372 expected_dict->Set("foo", Value::CreateStringValue("bar")); | |
373 value->Set(unknown_key, expected_dict); | |
374 EXPECT_FALSE(manifest->GetDictionary(unknown_key, &actual_dict)); | |
375 EXPECT_EQ(NULL, actual_dict); | |
376 std::string path = unknown_key + ".foo"; | |
377 EXPECT_FALSE(manifest->GetString(path, &actual_str)); | |
378 EXPECT_NE("bar", actual_str); | |
379 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
380 | |
381 // GetList | |
382 ListValue* expected_list = new ListValue(); | |
383 ListValue* actual_list = NULL; | |
384 expected_list->Append(Value::CreateStringValue("blah")); | |
385 value->Set(unknown_key, expected_list); | |
386 EXPECT_FALSE(manifest->GetList(unknown_key, &actual_list)); | |
387 EXPECT_EQ(NULL, actual_list); | |
388 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
389 } | |
390 | |
391 } // namespace extensions | |
OLD | NEW |