1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/pepper_permission_util.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <set>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <string>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/extensions/features/feature_channel.h"
1103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension_builder.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension_set.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using chrome::IsExtensionOrSharedModuleWhitelisted;
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace extensions {
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Return an extension with |id| which imports a module with the given
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// |import_id|.
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_refptr<Extension> CreateExtensionImportingModule(
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& import_id,
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& id) {
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> manifest =
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DictionaryBuilder()
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("name", "Has Dependent Modules")
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("version", "1.0")
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("manifest_version", 2)
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("import",
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               ListBuilder().Append(DictionaryBuilder().Set("id", import_id)))
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Build();
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return ExtensionBuilder()
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      .SetManifest(manifest.Pass())
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      .AddFlags(Extension::FROM_WEBSTORE)
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      .SetID(id)
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      .Build();
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(PepperPermissionUtilTest, ExtensionWhitelisting) {
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ScopedCurrentChannel current_channel(chrome::VersionInfo::CHANNEL_UNKNOWN);
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ExtensionSet extensions;
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string whitelisted_id =
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      crx_file::id_util::GenerateId("whitelisted_extension");
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> manifest =
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DictionaryBuilder()
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("name", "Whitelisted Extension")
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("version", "1.0")
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("manifest_version", 2)
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Build();
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<Extension> ext = ExtensionBuilder()
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     .SetManifest(manifest.Pass())
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     .SetID(whitelisted_id)
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     .Build();
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  extensions.Insert(ext);
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::set<std::string> whitelist;
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string url = std::string("chrome-extension://") + whitelisted_id +
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                    std::string("/manifest.nmf");
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string bad_scheme_url =
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::string("http://") + whitelisted_id + std::string("/manifest.nmf");
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string bad_host_url = std::string("chrome-extension://") +
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             crx_file::id_util::GenerateId("bad_host");
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string("/manifest.nmf");
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      IsExtensionOrSharedModuleWhitelisted(GURL(url), &extensions, whitelist));
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  whitelist.insert(whitelisted_id);
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      IsExtensionOrSharedModuleWhitelisted(GURL(url), &extensions, whitelist));
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GURL(bad_scheme_url), &extensions, whitelist));
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GURL(bad_host_url), &extensions, whitelist));
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(PepperPermissionUtilTest, SharedModuleWhitelisting) {
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ScopedCurrentChannel current_channel(chrome::VersionInfo::CHANNEL_UNKNOWN);
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ExtensionSet extensions;
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string whitelisted_id = crx_file::id_util::GenerateId("extension_id");
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string bad_id = crx_file::id_util::GenerateId("bad_id");
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> shared_module_manifest =
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DictionaryBuilder()
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("name", "Whitelisted Shared Module")
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("version", "1.0")
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("manifest_version", 2)
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Set("export",
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               DictionaryBuilder()
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   .Set("resources", ListBuilder().Append("*"))
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   // Add the extension to the whitelist.  This
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   // restricts import to |whitelisted_id| only.
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   .Set("whitelist", ListBuilder().Append(whitelisted_id)))
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          .Build();
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<Extension> shared_module =
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionBuilder().SetManifest(shared_module_manifest.Pass()).Build();
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<Extension> ext =
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      CreateExtensionImportingModule(shared_module->id(), whitelisted_id);
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string extension_url =
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::string("chrome-extension://") + ext->id() + std::string("/foo.html");
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::set<std::string> whitelist;
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Important: whitelist *only* the shared module.
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  whitelist.insert(shared_module->id());
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  extensions.Insert(ext);
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // This should fail because shared_module is not in the set of extensions.
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GURL(extension_url), &extensions, whitelist));
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  extensions.Insert(shared_module);
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(IsExtensionOrSharedModuleWhitelisted(
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GURL(extension_url), &extensions, whitelist));
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<Extension> not_in_sm_whitelist =
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      CreateExtensionImportingModule(shared_module->id(), bad_id);
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string not_in_sm_whitelist_url = std::string("chrome-extension://") +
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                        not_in_sm_whitelist->id() +
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                        std::string("/foo.html");
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions.Insert(not_in_sm_whitelist);
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // This should succeed, even though |not_in_sm_whitelist| is not whitelisted
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // to use shared_module, because the pepper permission utility does not care
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // about that whitelist.  It is possible to install against the whitelist as
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // an unpacked extension.
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(IsExtensionOrSharedModuleWhitelisted(
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GURL(not_in_sm_whitelist_url), &extensions, whitelist));
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Note that the whitelist should be empty after this call, so tests checking
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // for failure to import will fail because of this.
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  whitelist.erase(shared_module->id());
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GURL(extension_url), &extensions, whitelist));
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace extensions
140