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[] = { | |
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::CreateBooleanValue(true)); | |
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 bool is_platform_app = false; | |
257 EXPECT_TRUE(manifest->GetBoolean(keys::kPlatformApp, &is_platform_app)); | |
258 EXPECT_TRUE(is_platform_app) << keys::kPlatformApp; | |
259 | |
260 // And that all the other keys fail validation and are filtered out. | |
261 TestRestrictedKeys(manifest.get(), kNotPlatformAppKeys, | |
262 ARRAYSIZE_UNSAFE(kNotPlatformAppKeys)); | |
263 }; | |
264 | |
265 // Verifies that hosted apps can access the right keys. | |
266 TEST_F(ManifestTest, HostedApp) { | |
267 std::set<std::string> keys = GetAccessibleKeys( | |
268 kNotHostedAppKeys, | |
269 ARRAYSIZE_UNSAFE(kNotHostedAppKeys)); | |
270 | |
271 DictionaryValue* value = new DictionaryValue(); | |
272 for (std::set<std::string>::iterator i = keys.begin(); | |
273 i != keys.end(); ++i) | |
274 value->Set(*i, Value::CreateStringValue(default_value_)); | |
275 | |
276 value->Set(keys::kWebURLs, Value::CreateStringValue(default_value_)); | |
277 | |
278 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
279 std::string error; | |
280 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
281 EXPECT_EQ("", error); | |
282 AssertType(manifest.get(), Manifest::kTypeHostedApp); | |
283 | |
284 // Verify that all the hosted app keys are accessible. | |
285 std::string str; | |
286 for (std::set<std::string>::iterator i = keys.begin(); | |
287 i != keys.end(); ++i) { | |
288 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
289 EXPECT_EQ(default_value_, str) << *i; | |
290 } | |
291 EXPECT_TRUE(manifest->GetString(keys::kWebURLs, &str)); | |
292 EXPECT_EQ(default_value_, str) << keys::kWebURLs; | |
293 | |
294 // And that all the other keys fail validation and are filtered out. | |
295 TestRestrictedKeys(manifest.get(), kNotHostedAppKeys, | |
296 ARRAYSIZE_UNSAFE(kNotHostedAppKeys)); | |
297 }; | |
298 | |
299 // Verifies that packaged apps can access the right keys. | |
300 TEST_F(ManifestTest, PackagedApp) { | |
301 std::set<std::string> keys = GetAccessibleKeys( | |
302 kNotPackagedAppKeys, | |
303 ARRAYSIZE_UNSAFE(kNotPackagedAppKeys)); | |
304 | |
305 DictionaryValue* value = new DictionaryValue(); | |
306 for (std::set<std::string>::iterator i = keys.begin(); | |
307 i != keys.end(); ++i) | |
308 value->Set(*i, Value::CreateStringValue(default_value_)); | |
309 value->Set(keys::kApp, Value::CreateStringValue(default_value_)); | |
310 | |
311 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
312 std::string error; | |
313 EXPECT_TRUE(manifest->ValidateManifest(&error)); | |
314 EXPECT_EQ("", error); | |
315 AssertType(manifest.get(), Manifest::kTypePackagedApp); | |
316 | |
317 // Verify that all the packaged app keys are accessible. | |
318 std::string str; | |
319 for (std::set<std::string>::iterator i = keys.begin(); | |
320 i != keys.end(); ++i) { | |
321 EXPECT_TRUE(manifest->GetString(*i, &str)); | |
322 EXPECT_EQ(default_value_, str) << *i; | |
323 } | |
324 EXPECT_TRUE(manifest->GetString(keys::kApp, &str)); | |
325 EXPECT_EQ(default_value_, str) << keys::kApp; | |
326 | |
327 // And that all the other keys fail validation and are filtered out. | |
328 TestRestrictedKeys(manifest.get(), kNotPackagedAppKeys, | |
329 ARRAYSIZE_UNSAFE(kNotPackagedAppKeys)); | |
330 }; | |
331 | |
332 // Verifies that the various getters filter unknown and restricted keys. | |
333 TEST_F(ManifestTest, Getters) { | |
334 DictionaryValue* value = new DictionaryValue(); | |
335 scoped_ptr<Manifest> manifest(new Manifest(value)); | |
336 std::string unknown_key = "asdfaskldjf"; | |
337 | |
338 // Verify that the key filtering works for each of the getters. | |
339 // Get and GetBoolean | |
340 bool expected_bool = true, actual_bool = false; | |
341 value->Set(unknown_key, Value::CreateBooleanValue(expected_bool)); | |
342 EXPECT_FALSE(manifest->HasKey(unknown_key)); | |
343 EXPECT_FALSE(manifest->GetBoolean(unknown_key, &actual_bool)); | |
344 EXPECT_FALSE(actual_bool); | |
345 Value* actual_value = NULL; | |
346 EXPECT_FALSE(manifest->Get(unknown_key, &actual_value)); | |
347 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
348 | |
349 // GetInteger | |
350 int expected_int = 5, actual_int = 0; | |
351 value->Set(unknown_key, Value::CreateIntegerValue(expected_int)); | |
352 EXPECT_FALSE(manifest->GetInteger(unknown_key, &actual_int)); | |
353 EXPECT_NE(expected_int, actual_int); | |
354 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
355 | |
356 // GetString | |
357 std::string expected_str = "hello", actual_str; | |
358 value->Set(unknown_key, Value::CreateStringValue(expected_str)); | |
359 EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str)); | |
360 EXPECT_NE(expected_str, actual_str); | |
361 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
362 | |
363 // GetString (string16) | |
364 string16 expected_str16(UTF8ToUTF16("hello")), actual_str16; | |
365 value->Set(unknown_key, Value::CreateStringValue(expected_str16)); | |
366 EXPECT_FALSE(manifest->GetString(unknown_key, &actual_str16)); | |
367 EXPECT_NE(expected_str16, actual_str16); | |
368 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
369 | |
370 // GetDictionary | |
371 DictionaryValue* expected_dict = new DictionaryValue(); | |
372 DictionaryValue* actual_dict = NULL; | |
373 expected_dict->Set("foo", Value::CreateStringValue("bar")); | |
374 value->Set(unknown_key, expected_dict); | |
375 EXPECT_FALSE(manifest->GetDictionary(unknown_key, &actual_dict)); | |
376 EXPECT_EQ(NULL, actual_dict); | |
377 std::string path = unknown_key + ".foo"; | |
378 EXPECT_FALSE(manifest->GetString(path, &actual_str)); | |
379 EXPECT_NE("bar", actual_str); | |
380 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
381 | |
382 // GetList | |
383 ListValue* expected_list = new ListValue(); | |
384 ListValue* actual_list = NULL; | |
385 expected_list->Append(Value::CreateStringValue("blah")); | |
386 value->Set(unknown_key, expected_list); | |
387 EXPECT_FALSE(manifest->GetList(unknown_key, &actual_list)); | |
388 EXPECT_EQ(NULL, actual_list); | |
389 EXPECT_TRUE(value->Remove(unknown_key, NULL)); | |
390 } | |
391 | |
392 } // namespace extensions | |
OLD | NEW |