permission_set_unittest.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1// Copyright (c) 2012 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 "base/command_line.h"
6#include "base/json/json_file_value_serializer.h"
7#include "base/logging.h"
8#include "base/path_service.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/common/chrome_paths.h"
11#include "chrome/common/chrome_switches.h"
12#include "chrome/common/extensions/extension.h"
13#include "chrome/common/extensions/extension_test_util.h"
14#include "chrome/common/extensions/features/feature_channel.h"
15#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
16#include "chrome/common/extensions/permissions/permission_message_util.h"
17#include "chrome/common/extensions/permissions/permissions_data.h"
18#include "chrome/common/extensions/permissions/socket_permission.h"
19#include "extensions/common/error_utils.h"
20#include "extensions/common/permissions/permission_message_provider.h"
21#include "extensions/common/permissions/permission_set.h"
22#include "extensions/common/permissions/permissions_info.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
25using extension_test_util::LoadManifest;
26
27namespace extensions {
28
29namespace {
30
31static void AddPattern(URLPatternSet* extent, const std::string& pattern) {
32  int schemes = URLPattern::SCHEME_ALL;
33  extent->AddPattern(URLPattern(schemes, pattern));
34}
35
36size_t IndexOf(const std::vector<string16>& warnings,
37               const std::string& warning) {
38  for (size_t i = 0; i < warnings.size(); ++i) {
39    if (warnings[i] == ASCIIToUTF16(warning))
40      return i;
41  }
42
43  return warnings.size();
44}
45
46bool Contains(const std::vector<string16>& warnings,
47              const std::string& warning) {
48  return IndexOf(warnings, warning) != warnings.size();
49}
50
51}  // namespace
52
53// Tests GetByID.
54TEST(PermissionsTest, GetByID) {
55  PermissionsInfo* info = PermissionsInfo::GetInstance();
56  APIPermissionSet apis = info->GetAll();
57  for (APIPermissionSet::const_iterator i = apis.begin();
58       i != apis.end(); ++i) {
59    EXPECT_EQ(i->id(), i->info()->id());
60  }
61}
62
63// Tests that GetByName works with normal permission names and aliases.
64TEST(PermissionsTest, GetByName) {
65  PermissionsInfo* info = PermissionsInfo::GetInstance();
66  EXPECT_EQ(APIPermission::kTab, info->GetByName("tabs")->id());
67  EXPECT_EQ(APIPermission::kManagement,
68            info->GetByName("management")->id());
69  EXPECT_FALSE(info->GetByName("alsdkfjasldkfj"));
70}
71
72TEST(PermissionsTest, GetAll) {
73  size_t count = 0;
74  PermissionsInfo* info = PermissionsInfo::GetInstance();
75  APIPermissionSet apis = info->GetAll();
76  for (APIPermissionSet::const_iterator api = apis.begin();
77       api != apis.end(); ++api) {
78    // Make sure only the valid permission IDs get returned.
79    EXPECT_NE(APIPermission::kInvalid, api->id());
80    EXPECT_NE(APIPermission::kUnknown, api->id());
81    count++;
82  }
83  EXPECT_EQ(count, info->get_permission_count());
84}
85
86TEST(PermissionsTest, GetAllByName) {
87  std::set<std::string> names;
88  names.insert("background");
89  names.insert("management");
90
91  // This is an alias of kTab
92  names.insert("windows");
93
94  // This unknown name should get dropped.
95  names.insert("sdlkfjasdlkfj");
96
97  APIPermissionSet expected;
98  expected.insert(APIPermission::kBackground);
99  expected.insert(APIPermission::kManagement);
100  expected.insert(APIPermission::kTab);
101
102  EXPECT_EQ(expected,
103            PermissionsInfo::GetInstance()->GetAllByName(names));
104}
105
106// Tests that the aliases are properly mapped.
107TEST(PermissionsTest, Aliases) {
108  PermissionsInfo* info = PermissionsInfo::GetInstance();
109  // tabs: tabs, windows
110  std::string tabs_name = "tabs";
111  EXPECT_EQ(tabs_name, info->GetByID(APIPermission::kTab)->name());
112  EXPECT_EQ(APIPermission::kTab, info->GetByName("tabs")->id());
113  EXPECT_EQ(APIPermission::kTab, info->GetByName("windows")->id());
114
115  // unlimitedStorage: unlimitedStorage, unlimited_storage
116  std::string storage_name = "unlimitedStorage";
117  EXPECT_EQ(storage_name, info->GetByID(
118      APIPermission::kUnlimitedStorage)->name());
119  EXPECT_EQ(APIPermission::kUnlimitedStorage,
120            info->GetByName("unlimitedStorage")->id());
121  EXPECT_EQ(APIPermission::kUnlimitedStorage,
122            info->GetByName("unlimited_storage")->id());
123}
124
125TEST(PermissionsTest, EffectiveHostPermissions) {
126  scoped_refptr<Extension> extension;
127  scoped_refptr<const PermissionSet> permissions;
128
129  extension = LoadManifest("effective_host_permissions", "empty.json");
130  permissions = extension->GetActivePermissions();
131  EXPECT_EQ(0u,
132            PermissionsData::GetEffectiveHostPermissions(extension.get())
133                .patterns().size());
134  EXPECT_FALSE(
135      permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
136  EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
137
138  extension = LoadManifest("effective_host_permissions", "one_host.json");
139  permissions = extension->GetActivePermissions();
140  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
141      GURL("http://www.google.com")));
142  EXPECT_FALSE(permissions->HasEffectiveAccessToURL(
143      GURL("https://www.google.com")));
144  EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
145
146  extension = LoadManifest("effective_host_permissions",
147                           "one_host_wildcard.json");
148  permissions = extension->GetActivePermissions();
149  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://google.com")));
150  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
151      GURL("http://foo.google.com")));
152  EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
153
154  extension = LoadManifest("effective_host_permissions", "two_hosts.json");
155  permissions = extension->GetActivePermissions();
156  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
157      GURL("http://www.google.com")));
158  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
159      GURL("http://www.reddit.com")));
160  EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
161
162  extension = LoadManifest("effective_host_permissions",
163                           "https_not_considered.json");
164  permissions = extension->GetActivePermissions();
165  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://google.com")));
166  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("https://google.com")));
167  EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
168
169  extension = LoadManifest("effective_host_permissions",
170                           "two_content_scripts.json");
171  permissions = extension->GetActivePermissions();
172  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://google.com")));
173  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
174      GURL("http://www.reddit.com")));
175  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
176      GURL("http://news.ycombinator.com")));
177  EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
178
179  extension = LoadManifest("effective_host_permissions", "all_hosts.json");
180  permissions = extension->GetActivePermissions();
181  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://test/")));
182  EXPECT_FALSE(permissions->HasEffectiveAccessToURL(GURL("https://test/")));
183  EXPECT_TRUE(
184      permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
185  EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
186
187  extension = LoadManifest("effective_host_permissions", "all_hosts2.json");
188  permissions = extension->GetActivePermissions();
189  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://test/")));
190  EXPECT_TRUE(
191      permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
192  EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
193
194  extension = LoadManifest("effective_host_permissions", "all_hosts3.json");
195  permissions = extension->GetActivePermissions();
196  EXPECT_FALSE(permissions->HasEffectiveAccessToURL(GURL("http://test/")));
197  EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("https://test/")));
198  EXPECT_TRUE(
199      permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
200  EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
201}
202
203TEST(PermissionsTest, ExplicitAccessToOrigin) {
204  APIPermissionSet apis;
205  URLPatternSet explicit_hosts;
206  URLPatternSet scriptable_hosts;
207
208  AddPattern(&explicit_hosts, "http://*.google.com/*");
209  // The explicit host paths should get set to /*.
210  AddPattern(&explicit_hosts, "http://www.example.com/a/particular/path/*");
211
212  scoped_refptr<PermissionSet> perm_set = new PermissionSet(
213      apis, explicit_hosts, scriptable_hosts);
214  ASSERT_TRUE(perm_set->HasExplicitAccessToOrigin(
215      GURL("http://www.google.com/")));
216  ASSERT_TRUE(perm_set->HasExplicitAccessToOrigin(
217      GURL("http://test.google.com/")));
218  ASSERT_TRUE(perm_set->HasExplicitAccessToOrigin(
219      GURL("http://www.example.com")));
220  ASSERT_TRUE(perm_set->HasEffectiveAccessToURL(
221      GURL("http://www.example.com")));
222  ASSERT_FALSE(perm_set->HasExplicitAccessToOrigin(
223      GURL("http://test.example.com")));
224}
225
226TEST(PermissionsTest, CreateUnion) {
227  APIPermission* permission = NULL;
228
229  APIPermissionSet apis1;
230  APIPermissionSet apis2;
231  APIPermissionSet expected_apis;
232
233  URLPatternSet explicit_hosts1;
234  URLPatternSet explicit_hosts2;
235  URLPatternSet expected_explicit_hosts;
236
237  URLPatternSet scriptable_hosts1;
238  URLPatternSet scriptable_hosts2;
239  URLPatternSet expected_scriptable_hosts;
240
241  URLPatternSet effective_hosts;
242
243  scoped_refptr<PermissionSet> set1;
244  scoped_refptr<PermissionSet> set2;
245  scoped_refptr<PermissionSet> union_set;
246
247  const APIPermissionInfo* permission_info =
248    PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
249  permission = permission_info->CreateAPIPermission();
250  {
251    scoped_ptr<base::ListValue> value(new base::ListValue());
252    value->Append(
253        base::Value::CreateStringValue("tcp-connect:*.example.com:80"));
254    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
255    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
256    if (!permission->FromValue(value.get())) {
257      NOTREACHED();
258    }
259  }
260
261  // Union with an empty set.
262  apis1.insert(APIPermission::kTab);
263  apis1.insert(APIPermission::kBackground);
264  apis1.insert(permission->Clone());
265  expected_apis.insert(APIPermission::kTab);
266  expected_apis.insert(APIPermission::kBackground);
267  expected_apis.insert(permission);
268
269  AddPattern(&explicit_hosts1, "http://*.google.com/*");
270  AddPattern(&expected_explicit_hosts, "http://*.google.com/*");
271  AddPattern(&effective_hosts, "http://*.google.com/*");
272
273  set1 = new PermissionSet(apis1, explicit_hosts1, scriptable_hosts1);
274  set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
275  union_set = PermissionSet::CreateUnion(set1.get(), set2.get());
276  EXPECT_TRUE(set1->Contains(*set2.get()));
277  EXPECT_TRUE(set1->Contains(*union_set.get()));
278  EXPECT_FALSE(set2->Contains(*set1.get()));
279  EXPECT_FALSE(set2->Contains(*union_set.get()));
280  EXPECT_TRUE(union_set->Contains(*set1.get()));
281  EXPECT_TRUE(union_set->Contains(*set2.get()));
282
283  EXPECT_FALSE(union_set->HasEffectiveFullAccess());
284  EXPECT_EQ(expected_apis, union_set->apis());
285  EXPECT_EQ(expected_explicit_hosts, union_set->explicit_hosts());
286  EXPECT_EQ(expected_scriptable_hosts, union_set->scriptable_hosts());
287  EXPECT_EQ(expected_explicit_hosts, union_set->effective_hosts());
288
289  // Now use a real second set.
290  apis2.insert(APIPermission::kTab);
291  apis2.insert(APIPermission::kProxy);
292  apis2.insert(APIPermission::kClipboardWrite);
293  apis2.insert(APIPermission::kPlugin);
294
295  permission = permission_info->CreateAPIPermission();
296  {
297    scoped_ptr<base::ListValue> value(new base::ListValue());
298    value->Append(
299        base::Value::CreateStringValue("tcp-connect:*.example.com:80"));
300    value->Append(base::Value::CreateStringValue("udp-send-to::8899"));
301    if (!permission->FromValue(value.get())) {
302      NOTREACHED();
303    }
304  }
305  apis2.insert(permission);
306
307  expected_apis.insert(APIPermission::kTab);
308  expected_apis.insert(APIPermission::kProxy);
309  expected_apis.insert(APIPermission::kClipboardWrite);
310  expected_apis.insert(APIPermission::kPlugin);
311
312  permission = permission_info->CreateAPIPermission();
313  {
314    scoped_ptr<base::ListValue> value(new base::ListValue());
315    value->Append(
316        base::Value::CreateStringValue("tcp-connect:*.example.com:80"));
317    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
318    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
319    value->Append(base::Value::CreateStringValue("udp-send-to::8899"));
320    if (!permission->FromValue(value.get())) {
321      NOTREACHED();
322    }
323  }
324  // Insert a new permission socket permisssion which will replace the old one.
325  expected_apis.insert(permission);
326
327  AddPattern(&explicit_hosts2, "http://*.example.com/*");
328  AddPattern(&scriptable_hosts2, "http://*.google.com/*");
329  AddPattern(&expected_explicit_hosts, "http://*.example.com/*");
330  AddPattern(&expected_scriptable_hosts, "http://*.google.com/*");
331
332  URLPatternSet::CreateUnion(
333      explicit_hosts2, scriptable_hosts2, &effective_hosts);
334
335  set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
336  union_set = PermissionSet::CreateUnion(set1.get(), set2.get());
337
338  EXPECT_FALSE(set1->Contains(*set2.get()));
339  EXPECT_FALSE(set1->Contains(*union_set.get()));
340  EXPECT_FALSE(set2->Contains(*set1.get()));
341  EXPECT_FALSE(set2->Contains(*union_set.get()));
342  EXPECT_TRUE(union_set->Contains(*set1.get()));
343  EXPECT_TRUE(union_set->Contains(*set2.get()));
344
345  EXPECT_TRUE(union_set->HasEffectiveFullAccess());
346  EXPECT_TRUE(union_set->HasEffectiveAccessToAllHosts());
347  EXPECT_EQ(expected_apis, union_set->apis());
348  EXPECT_EQ(expected_explicit_hosts, union_set->explicit_hosts());
349  EXPECT_EQ(expected_scriptable_hosts, union_set->scriptable_hosts());
350  EXPECT_EQ(effective_hosts, union_set->effective_hosts());
351}
352
353TEST(PermissionsTest, CreateIntersection) {
354  APIPermission* permission = NULL;
355
356  APIPermissionSet apis1;
357  APIPermissionSet apis2;
358  APIPermissionSet expected_apis;
359
360  URLPatternSet explicit_hosts1;
361  URLPatternSet explicit_hosts2;
362  URLPatternSet expected_explicit_hosts;
363
364  URLPatternSet scriptable_hosts1;
365  URLPatternSet scriptable_hosts2;
366  URLPatternSet expected_scriptable_hosts;
367
368  URLPatternSet effective_hosts;
369
370  scoped_refptr<PermissionSet> set1;
371  scoped_refptr<PermissionSet> set2;
372  scoped_refptr<PermissionSet> new_set;
373
374  const APIPermissionInfo* permission_info =
375    PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
376
377  // Intersection with an empty set.
378  apis1.insert(APIPermission::kTab);
379  apis1.insert(APIPermission::kBackground);
380  permission = permission_info->CreateAPIPermission();
381  {
382    scoped_ptr<base::ListValue> value(new base::ListValue());
383    value->Append(
384        base::Value::CreateStringValue("tcp-connect:*.example.com:80"));
385    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
386    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
387    if (!permission->FromValue(value.get())) {
388      NOTREACHED();
389    }
390  }
391  apis1.insert(permission);
392
393  AddPattern(&explicit_hosts1, "http://*.google.com/*");
394  AddPattern(&scriptable_hosts1, "http://www.reddit.com/*");
395
396  set1 = new PermissionSet(apis1, explicit_hosts1, scriptable_hosts1);
397  set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
398  new_set = PermissionSet::CreateIntersection(set1.get(), set2.get());
399  EXPECT_TRUE(set1->Contains(*new_set.get()));
400  EXPECT_TRUE(set2->Contains(*new_set.get()));
401  EXPECT_TRUE(set1->Contains(*set2.get()));
402  EXPECT_FALSE(set2->Contains(*set1.get()));
403  EXPECT_FALSE(new_set->Contains(*set1.get()));
404  EXPECT_TRUE(new_set->Contains(*set2.get()));
405
406  EXPECT_TRUE(new_set->IsEmpty());
407  EXPECT_FALSE(new_set->HasEffectiveFullAccess());
408  EXPECT_EQ(expected_apis, new_set->apis());
409  EXPECT_EQ(expected_explicit_hosts, new_set->explicit_hosts());
410  EXPECT_EQ(expected_scriptable_hosts, new_set->scriptable_hosts());
411  EXPECT_EQ(expected_explicit_hosts, new_set->effective_hosts());
412
413  // Now use a real second set.
414  apis2.insert(APIPermission::kTab);
415  apis2.insert(APIPermission::kProxy);
416  apis2.insert(APIPermission::kClipboardWrite);
417  apis2.insert(APIPermission::kPlugin);
418  permission = permission_info->CreateAPIPermission();
419  {
420    scoped_ptr<base::ListValue> value(new base::ListValue());
421    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
422    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
423    value->Append(base::Value::CreateStringValue("udp-send-to::8899"));
424    if (!permission->FromValue(value.get())) {
425      NOTREACHED();
426    }
427  }
428  apis2.insert(permission);
429
430  expected_apis.insert(APIPermission::kTab);
431  permission = permission_info->CreateAPIPermission();
432  {
433    scoped_ptr<base::ListValue> value(new base::ListValue());
434    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
435    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
436    if (!permission->FromValue(value.get())) {
437      NOTREACHED();
438    }
439  }
440  expected_apis.insert(permission);
441
442  AddPattern(&explicit_hosts2, "http://*.example.com/*");
443  AddPattern(&explicit_hosts2, "http://*.google.com/*");
444  AddPattern(&scriptable_hosts2, "http://*.google.com/*");
445  AddPattern(&expected_explicit_hosts, "http://*.google.com/*");
446
447  effective_hosts.ClearPatterns();
448  AddPattern(&effective_hosts, "http://*.google.com/*");
449
450  set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
451  new_set = PermissionSet::CreateIntersection(set1.get(), set2.get());
452
453  EXPECT_TRUE(set1->Contains(*new_set.get()));
454  EXPECT_TRUE(set2->Contains(*new_set.get()));
455  EXPECT_FALSE(set1->Contains(*set2.get()));
456  EXPECT_FALSE(set2->Contains(*set1.get()));
457  EXPECT_FALSE(new_set->Contains(*set1.get()));
458  EXPECT_FALSE(new_set->Contains(*set2.get()));
459
460  EXPECT_FALSE(new_set->HasEffectiveFullAccess());
461  EXPECT_FALSE(new_set->HasEffectiveAccessToAllHosts());
462  EXPECT_EQ(expected_apis, new_set->apis());
463  EXPECT_EQ(expected_explicit_hosts, new_set->explicit_hosts());
464  EXPECT_EQ(expected_scriptable_hosts, new_set->scriptable_hosts());
465  EXPECT_EQ(effective_hosts, new_set->effective_hosts());
466}
467
468TEST(PermissionsTest, CreateDifference) {
469  APIPermission* permission = NULL;
470
471  APIPermissionSet apis1;
472  APIPermissionSet apis2;
473  APIPermissionSet expected_apis;
474
475  URLPatternSet explicit_hosts1;
476  URLPatternSet explicit_hosts2;
477  URLPatternSet expected_explicit_hosts;
478
479  URLPatternSet scriptable_hosts1;
480  URLPatternSet scriptable_hosts2;
481  URLPatternSet expected_scriptable_hosts;
482
483  URLPatternSet effective_hosts;
484
485  scoped_refptr<PermissionSet> set1;
486  scoped_refptr<PermissionSet> set2;
487  scoped_refptr<PermissionSet> new_set;
488
489  const APIPermissionInfo* permission_info =
490    PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
491
492  // Difference with an empty set.
493  apis1.insert(APIPermission::kTab);
494  apis1.insert(APIPermission::kBackground);
495  permission = permission_info->CreateAPIPermission();
496  {
497    scoped_ptr<base::ListValue> value(new base::ListValue());
498    value->Append(
499       base::Value::CreateStringValue("tcp-connect:*.example.com:80"));
500    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
501    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
502    if (!permission->FromValue(value.get())) {
503      NOTREACHED();
504    }
505  }
506  apis1.insert(permission);
507
508  AddPattern(&explicit_hosts1, "http://*.google.com/*");
509  AddPattern(&scriptable_hosts1, "http://www.reddit.com/*");
510
511  set1 = new PermissionSet(apis1, explicit_hosts1, scriptable_hosts1);
512  set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
513  new_set = PermissionSet::CreateDifference(set1.get(), set2.get());
514  EXPECT_EQ(*set1.get(), *new_set.get());
515
516  // Now use a real second set.
517  apis2.insert(APIPermission::kTab);
518  apis2.insert(APIPermission::kProxy);
519  apis2.insert(APIPermission::kClipboardWrite);
520  apis2.insert(APIPermission::kPlugin);
521  permission = permission_info->CreateAPIPermission();
522  {
523    scoped_ptr<base::ListValue> value(new base::ListValue());
524    value->Append(
525        base::Value::CreateStringValue("tcp-connect:*.example.com:80"));
526    value->Append(base::Value::CreateStringValue("udp-send-to::8899"));
527    if (!permission->FromValue(value.get())) {
528      NOTREACHED();
529    }
530  }
531  apis2.insert(permission);
532
533  expected_apis.insert(APIPermission::kBackground);
534  permission = permission_info->CreateAPIPermission();
535  {
536    scoped_ptr<base::ListValue> value(new base::ListValue());
537    value->Append(base::Value::CreateStringValue("udp-bind::8080"));
538    value->Append(base::Value::CreateStringValue("udp-send-to::8888"));
539    if (!permission->FromValue(value.get())) {
540      NOTREACHED();
541    }
542  }
543  expected_apis.insert(permission);
544
545  AddPattern(&explicit_hosts2, "http://*.example.com/*");
546  AddPattern(&explicit_hosts2, "http://*.google.com/*");
547  AddPattern(&scriptable_hosts2, "http://*.google.com/*");
548  AddPattern(&expected_scriptable_hosts, "http://www.reddit.com/*");
549
550  effective_hosts.ClearPatterns();
551  AddPattern(&effective_hosts, "http://www.reddit.com/*");
552
553  set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
554  new_set = PermissionSet::CreateDifference(set1.get(), set2.get());
555
556  EXPECT_TRUE(set1->Contains(*new_set.get()));
557  EXPECT_FALSE(set2->Contains(*new_set.get()));
558
559  EXPECT_FALSE(new_set->HasEffectiveFullAccess());
560  EXPECT_FALSE(new_set->HasEffectiveAccessToAllHosts());
561  EXPECT_EQ(expected_apis, new_set->apis());
562  EXPECT_EQ(expected_explicit_hosts, new_set->explicit_hosts());
563  EXPECT_EQ(expected_scriptable_hosts, new_set->scriptable_hosts());
564  EXPECT_EQ(effective_hosts, new_set->effective_hosts());
565
566  // |set3| = |set1| - |set2| --> |set3| intersect |set2| == empty_set
567  set1 = PermissionSet::CreateIntersection(new_set.get(), set2.get());
568  EXPECT_TRUE(set1->IsEmpty());
569}
570
571TEST(PermissionsTest, IsPrivilegeIncrease) {
572  const struct {
573    const char* base_name;
574    bool expect_increase;
575  } kTests[] = {
576    { "allhosts1", false },  // all -> all
577    { "allhosts2", false },  // all -> one
578    { "allhosts3", true },  // one -> all
579    { "hosts1", false },  // http://a,http://b -> http://a,http://b
580    { "hosts2", true },  // http://a,http://b -> https://a,http://*.b
581    { "hosts3", false },  // http://a,http://b -> http://a
582    { "hosts4", true },  // http://a -> http://a,http://b
583    { "hosts5", false },  // http://a,b,c -> http://a,b,c + https://a,b,c
584    { "hosts6", false },  // http://a.com -> http://a.com + http://a.co.uk
585    { "permissions1", false },  // tabs -> tabs
586    { "permissions2", true },  // tabs -> tabs,bookmarks
587    { "permissions3", true },  // http://a -> http://a,tabs
588    { "permissions5", true },  // bookmarks -> bookmarks,history
589    { "equivalent_warnings", false },  // tabs --> tabs, webNavigation
590#if !defined(OS_CHROMEOS)  // plugins aren't allowed in ChromeOS
591    { "permissions4", false },  // plugin -> plugin,tabs
592    { "plugin1", false },  // plugin -> plugin
593    { "plugin2", false },  // plugin -> none
594    { "plugin3", true },  // none -> plugin
595#endif
596    { "storage", false },  // none -> storage
597    { "notifications", false },  // none -> notifications
598    { "platformapp1", false },  // host permissions for platform apps
599    { "platformapp2", true },  // API permissions for platform apps
600    { "media_galleries1", true },  // all -> read|all
601    { "media_galleries2", true },  // read|all -> read|copyTo|all
602    { "media_galleries3", true },  // all -> read|copyTo|all
603    { "media_galleries4", false },  // read|all -> all
604    { "media_galleries5", false },  // read|copyTo|all -> read|all
605    { "media_galleries6", false },  // read|all -> read|all
606  };
607
608  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
609    scoped_refptr<Extension> old_extension(
610        LoadManifest("allow_silent_upgrade",
611                     std::string(kTests[i].base_name) + "_old.json"));
612    scoped_refptr<Extension> new_extension(
613        LoadManifest("allow_silent_upgrade",
614                     std::string(kTests[i].base_name) + "_new.json"));
615
616    EXPECT_TRUE(new_extension.get()) << kTests[i].base_name << "_new.json";
617    if (!new_extension.get())
618      continue;
619
620    scoped_refptr<const PermissionSet> old_p(
621        old_extension->GetActivePermissions());
622    scoped_refptr<const PermissionSet> new_p(
623        new_extension->GetActivePermissions());
624    Manifest::Type extension_type = old_extension->GetType();
625
626    EXPECT_EQ(kTests[i].expect_increase,
627              PermissionMessageProvider::Get()->IsPrivilegeIncrease(
628                  old_p.get(), new_p.get(), extension_type))
629        << kTests[i].base_name;
630  }
631}
632
633TEST(PermissionsTest, PermissionMessages) {
634  // Ensure that all permissions that needs to show install UI actually have
635  // strings associated with them.
636  APIPermissionSet skip;
637
638  // These are considered "nuisance" or "trivial" permissions that don't need
639  // a prompt.
640  skip.insert(APIPermission::kActiveTab);
641  skip.insert(APIPermission::kAdView);
642  skip.insert(APIPermission::kAlarms);
643  skip.insert(APIPermission::kAppCurrentWindowInternal);
644  skip.insert(APIPermission::kAppRuntime);
645  skip.insert(APIPermission::kAppWindow);
646  skip.insert(APIPermission::kAudio);
647  skip.insert(APIPermission::kBrowsingData);
648  skip.insert(APIPermission::kContextMenus);
649  skip.insert(APIPermission::kDiagnostics);
650  skip.insert(APIPermission::kDns);
651  skip.insert(APIPermission::kDownloadsShelf);
652  skip.insert(APIPermission::kFontSettings);
653  skip.insert(APIPermission::kFullscreen);
654  skip.insert(APIPermission::kIdle);
655  skip.insert(APIPermission::kIdltest);
656  skip.insert(APIPermission::kLogPrivate);
657  skip.insert(APIPermission::kNotification);
658  skip.insert(APIPermission::kPointerLock);
659  skip.insert(APIPermission::kPower);
660  skip.insert(APIPermission::kPushMessaging);
661  skip.insert(APIPermission::kSessions);
662  skip.insert(APIPermission::kStorage);
663  skip.insert(APIPermission::kSystemCpu);
664  skip.insert(APIPermission::kSystemDisplay);
665  skip.insert(APIPermission::kSystemMemory);
666  skip.insert(APIPermission::kSystemStorage);
667  skip.insert(APIPermission::kTts);
668  skip.insert(APIPermission::kUnlimitedStorage);
669  skip.insert(APIPermission::kWebRtc);
670  skip.insert(APIPermission::kWebView);
671
672  // TODO(erikkay) add a string for this permission.
673  skip.insert(APIPermission::kBackground);
674
675  skip.insert(APIPermission::kClipboardWrite);
676
677  // The cookie permission does nothing unless you have associated host
678  // permissions.
679  skip.insert(APIPermission::kCookie);
680
681  // These are warned as part of host permission checks.
682  skip.insert(APIPermission::kDeclarativeContent);
683  skip.insert(APIPermission::kPageCapture);
684  skip.insert(APIPermission::kProxy);
685  skip.insert(APIPermission::kTabCapture);
686  skip.insert(APIPermission::kWebRequest);
687  skip.insert(APIPermission::kWebRequestBlocking);
688
689  // This permission requires explicit user action (context menu handler)
690  // so we won't prompt for it for now.
691  skip.insert(APIPermission::kFileBrowserHandler);
692
693  // These permissions require explicit user action (configuration dialog)
694  // so we don't prompt for them at install time.
695  skip.insert(APIPermission::kMediaGalleries);
696
697  // If you've turned on the experimental command-line flag, we don't need
698  // to warn you further.
699  skip.insert(APIPermission::kExperimental);
700
701  // The Identity API has its own server-driven permission prompts.
702  skip.insert(APIPermission::kIdentity);
703
704  // These are private.
705  skip.insert(APIPermission::kAutoTestPrivate);
706  skip.insert(APIPermission::kBookmarkManagerPrivate);
707  skip.insert(APIPermission::kBrailleDisplayPrivate);
708  skip.insert(APIPermission::kCast);
709  skip.insert(APIPermission::kChromeosInfoPrivate);
710  skip.insert(APIPermission::kCloudPrintPrivate);
711  skip.insert(APIPermission::kCommandLinePrivate);
712  skip.insert(APIPermission::kDeveloperPrivate);
713  skip.insert(APIPermission::kDial);
714  skip.insert(APIPermission::kDownloadsInternal);
715  skip.insert(APIPermission::kEchoPrivate);
716  skip.insert(APIPermission::kEnterprisePlatformKeysPrivate);
717  skip.insert(APIPermission::kFeedbackPrivate);
718  skip.insert(APIPermission::kFileBrowserHandlerInternal);
719  skip.insert(APIPermission::kFileBrowserPrivate);
720  skip.insert(APIPermission::kIdentityPrivate);
721  skip.insert(APIPermission::kInfobars);
722  skip.insert(APIPermission::kInputMethodPrivate);
723  skip.insert(APIPermission::kMediaGalleriesPrivate);
724  skip.insert(APIPermission::kMediaPlayerPrivate);
725  skip.insert(APIPermission::kMetricsPrivate);
726  skip.insert(APIPermission::kMDns);
727  skip.insert(APIPermission::kPreferencesPrivate);
728  skip.insert(APIPermission::kPrincipalsPrivate);
729  skip.insert(APIPermission::kImageWriterPrivate);
730  skip.insert(APIPermission::kRtcPrivate);
731  skip.insert(APIPermission::kStreamsPrivate);
732  skip.insert(APIPermission::kSystemPrivate);
733  skip.insert(APIPermission::kTabCaptureForTab);
734  skip.insert(APIPermission::kTerminalPrivate);
735  skip.insert(APIPermission::kVirtualKeyboardPrivate);
736  skip.insert(APIPermission::kWallpaperPrivate);
737  skip.insert(APIPermission::kWebRequestInternal);
738  skip.insert(APIPermission::kWebrtcAudioPrivate);
739  skip.insert(APIPermission::kWebrtcLoggingPrivate);
740  skip.insert(APIPermission::kWebstorePrivate);
741
742  // Warned as part of host permissions.
743  skip.insert(APIPermission::kDevtools);
744
745  // Platform apps.
746  skip.insert(APIPermission::kBluetooth);
747  skip.insert(APIPermission::kFileSystem);
748  skip.insert(APIPermission::kFileSystemRetainEntries);
749  skip.insert(APIPermission::kSocket);
750  skip.insert(APIPermission::kSocketsUdp);
751  skip.insert(APIPermission::kUsbDevice);
752
753  PermissionsInfo* info = PermissionsInfo::GetInstance();
754  APIPermissionSet permissions = info->GetAll();
755  for (APIPermissionSet::const_iterator i = permissions.begin();
756       i != permissions.end(); ++i) {
757    const APIPermissionInfo* permission_info = i->info();
758    EXPECT_TRUE(permission_info != NULL);
759
760    if (skip.count(i->id())) {
761      EXPECT_EQ(PermissionMessage::kNone, permission_info->message_id())
762          << "unexpected message_id for " << permission_info->name();
763    } else {
764      EXPECT_NE(PermissionMessage::kNone, permission_info->message_id())
765          << "missing message_id for " << permission_info->name();
766    }
767  }
768}
769
770TEST(PermissionsTest, FileSystemPermissionMessages) {
771  APIPermissionSet api_permissions;
772  api_permissions.insert(APIPermission::kFileSystemWrite);
773  api_permissions.insert(APIPermission::kFileSystemDirectory);
774  scoped_refptr<PermissionSet> permissions(
775      new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet()));
776  PermissionMessages messages =
777      PermissionMessageProvider::Get()->GetPermissionMessages(
778          permissions, Manifest::TYPE_PLATFORM_APP);
779  ASSERT_EQ(2u, messages.size());
780  std::sort(messages.begin(), messages.end());
781  std::set<PermissionMessage::ID> ids;
782  for (PermissionMessages::const_iterator it = messages.begin();
783       it != messages.end(); ++it) {
784    ids.insert(it->id());
785  }
786  EXPECT_TRUE(ContainsKey(ids, PermissionMessage::kFileSystemDirectory));
787  EXPECT_TRUE(ContainsKey(ids, PermissionMessage::kFileSystemWrite));
788}
789
790TEST(PermissionsTest, HiddenFileSystemPermissionMessages) {
791  APIPermissionSet api_permissions;
792  api_permissions.insert(APIPermission::kFileSystemWrite);
793  api_permissions.insert(APIPermission::kFileSystemDirectory);
794  api_permissions.insert(APIPermission::kFileSystemWriteDirectory);
795  scoped_refptr<PermissionSet> permissions(
796      new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet()));
797  PermissionMessages messages =
798      PermissionMessageProvider::Get()->GetPermissionMessages(
799          permissions, Manifest::TYPE_PLATFORM_APP);
800  ASSERT_EQ(1u, messages.size());
801  EXPECT_EQ(PermissionMessage::kFileSystemWriteDirectory, messages[0].id());
802}
803
804TEST(PermissionsTest, MergedFileSystemPermissionComparison) {
805  APIPermissionSet write_api_permissions;
806  write_api_permissions.insert(APIPermission::kFileSystemWrite);
807  scoped_refptr<PermissionSet> write_permissions(new PermissionSet(
808      write_api_permissions, URLPatternSet(), URLPatternSet()));
809
810  APIPermissionSet directory_api_permissions;
811  directory_api_permissions.insert(APIPermission::kFileSystemDirectory);
812  scoped_refptr<PermissionSet> directory_permissions(new PermissionSet(
813      directory_api_permissions, URLPatternSet(), URLPatternSet()));
814
815  APIPermissionSet write_directory_api_permissions;
816  write_directory_api_permissions.insert(
817      APIPermission::kFileSystemWriteDirectory);
818  scoped_refptr<PermissionSet> write_directory_permissions(new PermissionSet(
819      write_directory_api_permissions, URLPatternSet(), URLPatternSet()));
820
821  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
822  EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions,
823                                             write_permissions,
824                                             Manifest::TYPE_PLATFORM_APP));
825  EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions,
826                                             directory_permissions,
827                                             Manifest::TYPE_PLATFORM_APP));
828  EXPECT_TRUE(provider->IsPrivilegeIncrease(write_permissions,
829                                            directory_permissions,
830                                            Manifest::TYPE_PLATFORM_APP));
831  EXPECT_TRUE(provider->IsPrivilegeIncrease(write_permissions,
832                                            write_directory_permissions,
833                                            Manifest::TYPE_PLATFORM_APP));
834  EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions,
835                                            write_permissions,
836                                            Manifest::TYPE_PLATFORM_APP));
837  EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions,
838                                            write_directory_permissions,
839                                            Manifest::TYPE_PLATFORM_APP));
840}
841
842TEST(PermissionsTest, GetWarningMessages_ManyHosts) {
843  scoped_refptr<Extension> extension;
844
845  extension = LoadManifest("permissions", "many-hosts.json");
846  std::vector<string16> warnings =
847      PermissionsData::GetPermissionMessageStrings(extension.get());
848  ASSERT_EQ(1u, warnings.size());
849  EXPECT_EQ("Access your data on encrypted.google.com and www.google.com",
850            UTF16ToUTF8(warnings[0]));
851}
852
853TEST(PermissionsTest, GetWarningMessages_Plugins) {
854  scoped_refptr<Extension> extension;
855  scoped_refptr<PermissionSet> permissions;
856
857  extension = LoadManifest("permissions", "plugins.json");
858  std::vector<string16> warnings =
859      PermissionsData::GetPermissionMessageStrings(extension.get());
860// We don't parse the plugins key on Chrome OS, so it should not ask for any
861  // permissions.
862#if defined(OS_CHROMEOS)
863  ASSERT_EQ(0u, warnings.size());
864#else
865  ASSERT_EQ(1u, warnings.size());
866  EXPECT_EQ("Access all data on your computer and the websites you visit",
867            UTF16ToUTF8(warnings[0]));
868#endif
869}
870
871TEST(PermissionsTest, GetWarningMessages_AudioVideo) {
872  // Both audio and video present.
873  scoped_refptr<Extension> extension =
874      LoadManifest("permissions", "audio-video.json");
875  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
876  PermissionSet* set =
877      const_cast<PermissionSet*>(
878          extension->GetActivePermissions().get());
879  std::vector<string16> warnings =
880      provider->GetWarningMessages(set, extension->GetType());
881  EXPECT_FALSE(Contains(warnings, "Use your microphone"));
882  EXPECT_FALSE(Contains(warnings, "Use your camera"));
883  EXPECT_TRUE(Contains(warnings, "Use your microphone and camera"));
884  size_t combined_index = IndexOf(warnings, "Use your microphone and camera");
885  size_t combined_size = warnings.size();
886
887  // Just audio present.
888  set->apis_.erase(APIPermission::kVideoCapture);
889  warnings = provider->GetWarningMessages(set, extension->GetType());
890  EXPECT_EQ(combined_size, warnings.size());
891  EXPECT_EQ(combined_index, IndexOf(warnings, "Use your microphone"));
892  EXPECT_FALSE(Contains(warnings, "Use your camera"));
893  EXPECT_FALSE(Contains(warnings, "Use your microphone and camera"));
894
895  // Just video present.
896  set->apis_.erase(APIPermission::kAudioCapture);
897  set->apis_.insert(APIPermission::kVideoCapture);
898  warnings = provider->GetWarningMessages(set, extension->GetType());
899  EXPECT_EQ(combined_size, warnings.size());
900  EXPECT_FALSE(Contains(warnings, "Use your microphone"));
901  EXPECT_FALSE(Contains(warnings, "Use your microphone and camera"));
902  EXPECT_TRUE(Contains(warnings, "Use your camera"));
903}
904
905TEST(PermissionsTest, GetWarningMessages_DeclarativeWebRequest) {
906  // Test that if the declarativeWebRequest permission is present
907  // in combination with all hosts permission, then only the warning
908  // for host permissions is shown, because that covers the use of
909  // declarativeWebRequest.
910
911  // Until Declarative Web Request is in stable, let's make sure it is enabled
912  // on the current channel.
913  ScopedCurrentChannel sc(chrome::VersionInfo::CHANNEL_CANARY);
914
915  // First verify that declarativeWebRequest produces a message when host
916  // permissions do not cover all hosts.
917  scoped_refptr<Extension> extension =
918      LoadManifest("permissions", "web_request_com_host_permissions.json");
919  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
920  const PermissionSet* set = extension->GetActivePermissions().get();
921  std::vector<string16> warnings =
922      provider->GetWarningMessages(set, extension->GetType());
923  EXPECT_TRUE(Contains(warnings, "Block parts of web pages"));
924  EXPECT_FALSE(Contains(warnings, "Access your data on all websites"));
925
926  // Now verify that declarativeWebRequest does not produce a message when host
927  // permissions do cover all hosts.
928  extension =
929      LoadManifest("permissions", "web_request_all_host_permissions.json");
930  set = extension->GetActivePermissions().get();
931  warnings = provider->GetWarningMessages(set, extension->GetType());
932  EXPECT_FALSE(Contains(warnings, "Block parts of web pages"));
933  EXPECT_TRUE(Contains(warnings, "Access your data on all websites"));
934}
935
936TEST(PermissionsTest, GetWarningMessages_Serial) {
937  scoped_refptr<Extension> extension =
938      LoadManifest("permissions", "serial.json");
939
940  EXPECT_TRUE(extension->is_platform_app());
941  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kSerial));
942  std::vector<string16> warnings =
943      PermissionsData::GetPermissionMessageStrings(extension.get());
944  EXPECT_TRUE(
945      Contains(warnings, "Use serial devices attached to your computer"));
946  ASSERT_EQ(1u, warnings.size());
947}
948
949TEST(PermissionsTest, GetWarningMessages_Socket_AnyHost) {
950  ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV);
951
952  scoped_refptr<Extension> extension =
953      LoadManifest("permissions", "socket_any_host.json");
954  EXPECT_TRUE(extension->is_platform_app());
955  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kSocket));
956  std::vector<string16> warnings =
957      PermissionsData::GetPermissionMessageStrings(extension.get());
958  EXPECT_EQ(1u, warnings.size());
959  EXPECT_TRUE(Contains(warnings, "Exchange data with any computer "
960                                 "on the local network or internet"));
961}
962
963TEST(PermissionsTest, GetWarningMessages_Socket_OneDomainTwoHostnames) {
964  ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV);
965
966  scoped_refptr<Extension> extension =
967      LoadManifest("permissions", "socket_one_domain_two_hostnames.json");
968  EXPECT_TRUE(extension->is_platform_app());
969  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kSocket));
970  std::vector<string16> warnings =
971      PermissionsData::GetPermissionMessageStrings(extension.get());
972
973  // Verify the warnings, including support for unicode characters, the fact
974  // that domain host warnings come before specific host warnings, and the fact
975  // that domains and hostnames are in alphabetical order regardless of the
976  // order in the manifest file.
977  EXPECT_EQ(2u, warnings.size());
978  if (warnings.size() > 0)
979    EXPECT_EQ(warnings[0],
980              UTF8ToUTF16("Exchange data with any computer in the domain "
981                          "example.org"));
982  if (warnings.size() > 1)
983    EXPECT_EQ(warnings[1],
984              UTF8ToUTF16("Exchange data with the computers named: "
985                          "b\xC3\xA5r.example.com foo.example.com"));
986                          // "\xC3\xA5" = UTF-8 for lowercase A with ring above
987}
988
989TEST(PermissionsTest, GetWarningMessages_Socket_TwoDomainsOneHostname) {
990  ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV);
991
992  scoped_refptr<Extension> extension =
993      LoadManifest("permissions", "socket_two_domains_one_hostname.json");
994  EXPECT_TRUE(extension->is_platform_app());
995  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kSocket));
996  std::vector<string16> warnings =
997      PermissionsData::GetPermissionMessageStrings(extension.get());
998
999  // Verify the warnings, including the fact that domain host warnings come
1000  // before specific host warnings and the fact that domains and hostnames are
1001  // in alphabetical order regardless of the order in the manifest file.
1002  EXPECT_EQ(2u, warnings.size());
1003  if (warnings.size() > 0)
1004    EXPECT_EQ(warnings[0],
1005              UTF8ToUTF16("Exchange data with any computer in the domains: "
1006                           "example.com foo.example.org"));
1007  if (warnings.size() > 1)
1008    EXPECT_EQ(warnings[1],
1009              UTF8ToUTF16("Exchange data with the computer named "
1010                           "bar.example.org"));
1011}
1012
1013TEST(PermissionsTest, GetWarningMessages_PlatformApppHosts) {
1014  scoped_refptr<Extension> extension;
1015
1016  extension = LoadManifest("permissions", "platform_app_hosts.json");
1017  EXPECT_TRUE(extension->is_platform_app());
1018  std::vector<string16> warnings =
1019      PermissionsData::GetPermissionMessageStrings(extension.get());
1020  ASSERT_EQ(0u, warnings.size());
1021
1022  extension = LoadManifest("permissions", "platform_app_all_urls.json");
1023  EXPECT_TRUE(extension->is_platform_app());
1024  warnings = PermissionsData::GetPermissionMessageStrings(extension.get());
1025  ASSERT_EQ(0u, warnings.size());
1026}
1027
1028TEST(PermissionsTest, GetDistinctHosts) {
1029  URLPatternSet explicit_hosts;
1030  std::set<std::string> expected;
1031  expected.insert("www.foo.com");
1032  expected.insert("www.bar.com");
1033  expected.insert("www.baz.com");
1034
1035  {
1036    SCOPED_TRACE("no dupes");
1037
1038    // Simple list with no dupes.
1039    explicit_hosts.AddPattern(
1040        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1041    explicit_hosts.AddPattern(
1042        URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/path"));
1043    explicit_hosts.AddPattern(
1044        URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
1045    EXPECT_EQ(expected,
1046              permission_message_util::GetDistinctHosts(
1047                  explicit_hosts, true, true));
1048  }
1049
1050  {
1051    SCOPED_TRACE("two dupes");
1052
1053    // Add some dupes.
1054    explicit_hosts.AddPattern(
1055        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1056    explicit_hosts.AddPattern(
1057        URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
1058    EXPECT_EQ(expected,
1059              permission_message_util::GetDistinctHosts(
1060                  explicit_hosts, true, true));
1061  }
1062
1063  {
1064    SCOPED_TRACE("schemes differ");
1065
1066    // Add a pattern that differs only by scheme. This should be filtered out.
1067    explicit_hosts.AddPattern(
1068        URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path"));
1069    EXPECT_EQ(expected,
1070              permission_message_util::GetDistinctHosts(
1071                  explicit_hosts, true, true));
1072  }
1073
1074  {
1075    SCOPED_TRACE("paths differ");
1076
1077    // Add some dupes by path.
1078    explicit_hosts.AddPattern(
1079        URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath"));
1080    EXPECT_EQ(expected,
1081              permission_message_util::GetDistinctHosts(
1082                  explicit_hosts, true, true));
1083  }
1084
1085  {
1086    SCOPED_TRACE("subdomains differ");
1087
1088    // We don't do anything special for subdomains.
1089    explicit_hosts.AddPattern(
1090        URLPattern(URLPattern::SCHEME_HTTP, "http://monkey.www.bar.com/path"));
1091    explicit_hosts.AddPattern(
1092        URLPattern(URLPattern::SCHEME_HTTP, "http://bar.com/path"));
1093
1094    expected.insert("monkey.www.bar.com");
1095    expected.insert("bar.com");
1096
1097    EXPECT_EQ(expected,
1098              permission_message_util::GetDistinctHosts(
1099                  explicit_hosts, true, true));
1100  }
1101
1102  {
1103    SCOPED_TRACE("RCDs differ");
1104
1105    // Now test for RCD uniquing.
1106    explicit_hosts.AddPattern(
1107        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1108    explicit_hosts.AddPattern(
1109        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1110    explicit_hosts.AddPattern(
1111        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.de/path"));
1112    explicit_hosts.AddPattern(
1113        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca.us/path"));
1114    explicit_hosts.AddPattern(
1115        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
1116    explicit_hosts.AddPattern(
1117        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com.my/path"));
1118
1119    // This is an unknown RCD, which shouldn't be uniqued out.
1120    explicit_hosts.AddPattern(
1121        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
1122    // But it should only occur once.
1123    explicit_hosts.AddPattern(
1124        URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
1125
1126    expected.insert("www.foo.xyzzy");
1127
1128    EXPECT_EQ(expected,
1129              permission_message_util::GetDistinctHosts(
1130                  explicit_hosts, true, true));
1131  }
1132
1133  {
1134    SCOPED_TRACE("wildcards");
1135
1136    explicit_hosts.AddPattern(
1137        URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*"));
1138
1139    expected.insert("*.google.com");
1140
1141    EXPECT_EQ(expected,
1142              permission_message_util::GetDistinctHosts(
1143                  explicit_hosts, true, true));
1144  }
1145
1146  {
1147    SCOPED_TRACE("scriptable hosts");
1148
1149    APIPermissionSet empty_perms;
1150    explicit_hosts.ClearPatterns();
1151    URLPatternSet scriptable_hosts;
1152    expected.clear();
1153
1154    explicit_hosts.AddPattern(
1155        URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*"));
1156    scriptable_hosts.AddPattern(
1157        URLPattern(URLPattern::SCHEME_HTTP, "http://*.example.com/*"));
1158
1159    expected.insert("*.google.com");
1160    expected.insert("*.example.com");
1161
1162    scoped_refptr<PermissionSet> perm_set(new PermissionSet(
1163        empty_perms, explicit_hosts, scriptable_hosts));
1164    EXPECT_EQ(expected,
1165              permission_message_util::GetDistinctHosts(
1166                  perm_set->effective_hosts(), true, true));
1167  }
1168
1169  {
1170    // We don't display warnings for file URLs because they are off by default.
1171    SCOPED_TRACE("file urls");
1172
1173    explicit_hosts.ClearPatterns();
1174    expected.clear();
1175
1176    explicit_hosts.AddPattern(
1177        URLPattern(URLPattern::SCHEME_FILE, "file:///*"));
1178
1179    EXPECT_EQ(expected,
1180              permission_message_util::GetDistinctHosts(
1181                  explicit_hosts, true, true));
1182  }
1183}
1184
1185TEST(PermissionsTest, GetDistinctHosts_ComIsBestRcd) {
1186  URLPatternSet explicit_hosts;
1187  explicit_hosts.AddPattern(
1188      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1189  explicit_hosts.AddPattern(
1190      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
1191  explicit_hosts.AddPattern(
1192      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1193  explicit_hosts.AddPattern(
1194      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
1195  explicit_hosts.AddPattern(
1196      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1197  explicit_hosts.AddPattern(
1198      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
1199
1200  std::set<std::string> expected;
1201  expected.insert("www.foo.com");
1202  EXPECT_EQ(expected,
1203            permission_message_util::GetDistinctHosts(
1204                explicit_hosts, true, true));
1205}
1206
1207TEST(PermissionsTest, GetDistinctHosts_NetIs2ndBestRcd) {
1208  URLPatternSet explicit_hosts;
1209  explicit_hosts.AddPattern(
1210      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1211  explicit_hosts.AddPattern(
1212      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
1213  explicit_hosts.AddPattern(
1214      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1215  explicit_hosts.AddPattern(
1216      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
1217  explicit_hosts.AddPattern(
1218      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1219  // No http://www.foo.com/path
1220
1221  std::set<std::string> expected;
1222  expected.insert("www.foo.net");
1223  EXPECT_EQ(expected,
1224            permission_message_util::GetDistinctHosts(
1225                explicit_hosts, true, true));
1226}
1227
1228TEST(PermissionsTest, GetDistinctHosts_OrgIs3rdBestRcd) {
1229  URLPatternSet explicit_hosts;
1230  explicit_hosts.AddPattern(
1231      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1232  explicit_hosts.AddPattern(
1233      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
1234  explicit_hosts.AddPattern(
1235      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1236  // No http://www.foo.net/path
1237  explicit_hosts.AddPattern(
1238      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1239  // No http://www.foo.com/path
1240
1241  std::set<std::string> expected;
1242  expected.insert("www.foo.org");
1243  EXPECT_EQ(expected,
1244            permission_message_util::GetDistinctHosts(
1245                explicit_hosts, true, true));
1246}
1247
1248TEST(PermissionsTest, GetDistinctHosts_FirstInListIs4thBestRcd) {
1249  URLPatternSet explicit_hosts;
1250  explicit_hosts.AddPattern(
1251      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
1252  // No http://www.foo.org/path
1253  explicit_hosts.AddPattern(
1254      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
1255  // No http://www.foo.net/path
1256  explicit_hosts.AddPattern(
1257      URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
1258  // No http://www.foo.com/path
1259
1260  std::set<std::string> expected;
1261  expected.insert("www.foo.ca");
1262  EXPECT_EQ(expected,
1263            permission_message_util::GetDistinctHosts(
1264                explicit_hosts, true, true));
1265}
1266
1267TEST(PermissionsTest, IsHostPrivilegeIncrease) {
1268  Manifest::Type type = Manifest::TYPE_EXTENSION;
1269  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
1270  URLPatternSet elist1;
1271  URLPatternSet elist2;
1272  URLPatternSet slist1;
1273  URLPatternSet slist2;
1274  scoped_refptr<PermissionSet> set1;
1275  scoped_refptr<PermissionSet> set2;
1276  APIPermissionSet empty_perms;
1277  elist1.AddPattern(
1278      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
1279  elist1.AddPattern(
1280      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
1281
1282  // Test that the host order does not matter.
1283  elist2.AddPattern(
1284      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
1285  elist2.AddPattern(
1286      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
1287
1288  set1 = new PermissionSet(empty_perms, elist1, slist1);
1289  set2 = new PermissionSet(empty_perms, elist2, slist2);
1290
1291  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
1292  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
1293
1294  // Test that paths are ignored.
1295  elist2.ClearPatterns();
1296  elist2.AddPattern(
1297      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*"));
1298  set2 = new PermissionSet(empty_perms, elist2, slist2);
1299  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
1300  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
1301
1302  // Test that RCDs are ignored.
1303  elist2.ClearPatterns();
1304  elist2.AddPattern(
1305      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*"));
1306  set2 = new PermissionSet(empty_perms, elist2, slist2);
1307  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
1308  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
1309
1310  // Test that subdomain wildcards are handled properly.
1311  elist2.ClearPatterns();
1312  elist2.AddPattern(
1313      URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*"));
1314  set2 = new PermissionSet(empty_perms, elist2, slist2);
1315  EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
1316  // TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337
1317  // EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
1318
1319  // Test that different domains count as different hosts.
1320  elist2.ClearPatterns();
1321  elist2.AddPattern(
1322      URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
1323  elist2.AddPattern(
1324      URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path"));
1325  set2 = new PermissionSet(empty_perms, elist2, slist2);
1326  EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
1327  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
1328
1329  // Test that different subdomains count as different hosts.
1330  elist2.ClearPatterns();
1331  elist2.AddPattern(
1332      URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*"));
1333  set2 = new PermissionSet(empty_perms, elist2, slist2);
1334  EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
1335  EXPECT_TRUE(provider->IsPrivilegeIncrease(set2, set1, type));
1336
1337  // Test that platform apps do not have host permissions increases.
1338  type = Manifest::TYPE_PLATFORM_APP;
1339  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
1340  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
1341}
1342
1343TEST(PermissionsTest, GetAPIsAsStrings) {
1344  APIPermissionSet apis;
1345  URLPatternSet empty_set;
1346
1347  apis.insert(APIPermission::kProxy);
1348  apis.insert(APIPermission::kBackground);
1349  apis.insert(APIPermission::kNotification);
1350  apis.insert(APIPermission::kTab);
1351
1352  scoped_refptr<PermissionSet> perm_set = new PermissionSet(
1353      apis, empty_set, empty_set);
1354  std::set<std::string> api_names = perm_set->GetAPIsAsStrings();
1355
1356  // The result is correct if it has the same number of elements
1357  // and we can convert it back to the id set.
1358  EXPECT_EQ(4u, api_names.size());
1359  EXPECT_EQ(apis,
1360            PermissionsInfo::GetInstance()->GetAllByName(api_names));
1361}
1362
1363TEST(PermissionsTest, IsEmpty) {
1364  APIPermissionSet empty_apis;
1365  URLPatternSet empty_extent;
1366
1367  scoped_refptr<PermissionSet> empty = new PermissionSet();
1368  EXPECT_TRUE(empty->IsEmpty());
1369  scoped_refptr<PermissionSet> perm_set;
1370
1371  perm_set = new PermissionSet(empty_apis, empty_extent, empty_extent);
1372  EXPECT_TRUE(perm_set->IsEmpty());
1373
1374  APIPermissionSet non_empty_apis;
1375  non_empty_apis.insert(APIPermission::kBackground);
1376  perm_set = new PermissionSet(
1377      non_empty_apis, empty_extent, empty_extent);
1378  EXPECT_FALSE(perm_set->IsEmpty());
1379
1380  // Try non standard host
1381  URLPatternSet non_empty_extent;
1382  AddPattern(&non_empty_extent, "http://www.google.com/*");
1383
1384  perm_set = new PermissionSet(
1385      empty_apis, non_empty_extent, empty_extent);
1386  EXPECT_FALSE(perm_set->IsEmpty());
1387
1388  perm_set = new PermissionSet(
1389      empty_apis, empty_extent, non_empty_extent);
1390  EXPECT_FALSE(perm_set->IsEmpty());
1391}
1392
1393TEST(PermissionsTest, ImpliedPermissions) {
1394  URLPatternSet empty_extent;
1395  APIPermissionSet apis;
1396  apis.insert(APIPermission::kWebRequest);
1397  apis.insert(APIPermission::kFileBrowserHandler);
1398  EXPECT_EQ(2U, apis.size());
1399
1400  scoped_refptr<PermissionSet> perm_set;
1401  perm_set = new PermissionSet(apis, empty_extent, empty_extent);
1402  EXPECT_EQ(4U, perm_set->apis().size());
1403}
1404
1405TEST(PermissionsTest, SyncFileSystemPermission) {
1406  scoped_refptr<Extension> extension = LoadManifest(
1407      "permissions", "sync_file_system.json");
1408  APIPermissionSet apis;
1409  apis.insert(APIPermission::kSyncFileSystem);
1410  EXPECT_TRUE(extension->is_platform_app());
1411  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kSyncFileSystem));
1412  std::vector<string16> warnings =
1413      PermissionsData::GetPermissionMessageStrings(extension.get());
1414  EXPECT_TRUE(Contains(warnings, "Store data in your Google Drive account"));
1415  ASSERT_EQ(1u, warnings.size());
1416}
1417
1418// Make sure that we don't crash when we're trying to show the permissions
1419// even though chrome://thumb (and everything that's not chrome://favicon with
1420// a chrome:// scheme) is not a valid permission.
1421// More details here: crbug/246314.
1422TEST(PermissionsTest, ChromeURLs) {
1423  URLPatternSet allowed_hosts;
1424  allowed_hosts.AddPattern(
1425      URLPattern(URLPattern::SCHEME_ALL, "http://www.google.com/"));
1426  allowed_hosts.AddPattern(
1427      URLPattern(URLPattern::SCHEME_ALL, "chrome://favicon/"));
1428  allowed_hosts.AddPattern(
1429      URLPattern(URLPattern::SCHEME_ALL, "chrome://thumb/"));
1430  scoped_refptr<PermissionSet> permissions(
1431      new PermissionSet(APIPermissionSet(), allowed_hosts, URLPatternSet()));
1432  PermissionMessageProvider::Get()->
1433      GetPermissionMessages(permissions, Manifest::TYPE_EXTENSION);
1434}
1435
1436TEST(PermissionsTest, IsPrivilegeIncrease_DeclarativeWebRequest) {
1437  scoped_refptr<Extension> extension(
1438      LoadManifest("permissions", "permissions_all_urls.json"));
1439  scoped_refptr<const PermissionSet> permissions(
1440      extension->GetActivePermissions());
1441
1442  scoped_refptr<Extension> extension_dwr(
1443      LoadManifest("permissions", "web_request_all_host_permissions.json"));
1444  scoped_refptr<const PermissionSet> permissions_dwr(
1445      extension_dwr->GetActivePermissions());
1446
1447  EXPECT_FALSE(PermissionMessageProvider::Get()->
1448                   IsPrivilegeIncrease(permissions.get(),
1449                                       permissions_dwr.get(),
1450                                       extension->GetType()));
1451}
1452
1453}  // namespace extensions
1454