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