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