1 // Copyright 2014 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.
8 #include "base/command_line.h"
9 #include "base/files/file_util.h"
10 #include "base/path_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "chrome/browser/extensions/extension_apitest.h"
15 #include "chrome/browser/extensions/test_extension_dir.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "components/crx_file/id_util.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "extensions/common/extension_builder.h"
23 #include "extensions/common/manifest_handlers/content_capabilities_handler.h"
24 #include "extensions/common/switches.h"
25 #include "extensions/common/url_pattern.h"
26 #include "net/dns/mock_host_resolver.h"
27 #include "net/test/embedded_test_server/embedded_test_server.h"
28 #include "storage/browser/quota/special_storage_policy.h"
30 using extensions::DictionaryBuilder
;
31 using extensions::Extension
;
32 using extensions::ExtensionBuilder
;
33 using extensions::ListBuilder
;
35 class ContentCapabilitiesTest
: public ExtensionApiTest
{
37 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
38 ExtensionApiTest::SetUpCommandLine(command_line
);
39 command_line
->AppendSwitchASCII(
40 extensions::switches::kWhitelistedExtensionID
,
41 crx_file::id_util::GenerateIdForPath(
42 base::MakeAbsoluteFilePath(test_extension_dir_
.unpacked_path())));
45 // Builds an extension manifest with the given content_capabilities matches
46 // and permissions. The extension always has the same (whitelisted) ID.
47 scoped_refptr
<const Extension
> LoadExtensionWithCapabilities(
48 const std::string
& matches
,
49 const std::string
& permissions
,
50 const std::string
& extension_permissions
= "[]") {
51 std::string manifest
= base::StringPrintf(
53 " \"name\": \"content_capabilities test extensions\",\n"
54 " \"version\": \"1\",\n"
55 " \"manifest_version\": 2,\n"
56 " \"content_capabilities\": {\n"
58 " \"permissions\": %s\n"
60 " \"permissions\": %s\n"
62 matches
.c_str(), permissions
.c_str(), extension_permissions
.c_str());
63 test_extension_dir_
.WriteManifest(manifest
);
64 return LoadExtension(test_extension_dir_
.unpacked_path());
67 std::string
MakeJSONList(const std::string
& s0
= "",
68 const std::string
& s1
= "",
69 const std::string
& s2
= "") {
70 std::vector
<std::string
> v
;
77 std::string list
= base::JoinString(v
, "\",\"");
79 list
= "\"" + list
+ "\"";
80 return "[" + list
+ "]";
83 content::WebContents
* web_contents() {
84 return browser()->tab_strip_model()->GetActiveWebContents();
87 GURL
GetTestURLFor(const std::string
& host
) {
88 std::string port
= base::IntToString(embedded_test_server()->port());
89 GURL::Replacements replacements
;
90 replacements
.SetHostStr(host
);
91 replacements
.SetPortStr(port
);
92 return embedded_test_server()
93 ->GetURL("/" + host
+ ".html")
94 .ReplaceComponents(replacements
);
97 void InitializeTestServer() {
98 base::FilePath test_data
;
99 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &test_data
));
100 embedded_test_server()->ServeFilesFromDirectory(
101 test_data
.AppendASCII("extensions/content_capabilities"));
102 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
103 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
106 // Run some script in the context of the given origin and in the presence of
107 // the given extension. This is used to wrap calls into the JS test functions
109 // $(DIR_TEST_DATA)/extensions/content_capabilities/capability_tests.js.
110 testing::AssertionResult
TestScriptResult(const Extension
* extension
,
113 ui_test_utils::NavigateToURL(browser(), url
);
115 if (!content::ExecuteScriptAndExtractBool(web_contents(), code
, &result
))
116 return testing::AssertionFailure() << "Could not execute test script.";
118 return testing::AssertionFailure();
119 return testing::AssertionSuccess();
122 testing::AssertionResult
CanReadClipboard(const Extension
* extension
,
124 return TestScriptResult(extension
, url
, "tests.canReadClipboard()");
127 testing::AssertionResult
CanWriteClipboard(const Extension
* extension
,
129 return TestScriptResult(extension
, url
, "tests.canWriteClipboard()");
132 testing::AssertionResult
HasUnlimitedStorage(const Extension
* extension
,
134 if (profile()->GetSpecialStoragePolicy()->IsStorageUnlimited(url
))
135 return testing::AssertionSuccess();
136 return testing::AssertionFailure();
140 extensions::TestExtensionDir test_extension_dir_
;
143 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
, NoCapabilities
) {
144 InitializeTestServer();
145 scoped_refptr
<const Extension
> extension
= LoadExtensionWithCapabilities(
146 MakeJSONList("http://foo.example.com/*"), MakeJSONList());
148 CanReadClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
149 // TODO(dcheng): This should be false, but we cannot currently execute testing
150 // script without a user gesture.
152 CanWriteClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
154 HasUnlimitedStorage(extension
.get(), GetTestURLFor("foo.example.com")));
157 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
, ClipboardRead
) {
158 InitializeTestServer();
159 scoped_refptr
<const Extension
> extension
= LoadExtensionWithCapabilities(
160 MakeJSONList("http://foo.example.com/*"), MakeJSONList("clipboardRead"));
162 CanReadClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
164 CanReadClipboard(extension
.get(), GetTestURLFor("bar.example.com")));
165 // TODO(dcheng): This should be false, but we cannot currently execute testing
166 // script without a user gesture.
168 CanWriteClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
171 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
, ClipboardWrite
) {
172 InitializeTestServer();
173 scoped_refptr
<const Extension
> extension
= LoadExtensionWithCapabilities(
174 MakeJSONList("http://foo.example.com/*"), MakeJSONList("clipboardWrite"));
176 CanWriteClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
177 // TODO(dcheng): This should be false, but we cannot currently execute testing
178 // script without a user gesture.
180 CanWriteClipboard(extension
.get(), GetTestURLFor("bar.example.com")));
182 CanReadClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
185 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
, ClipboardReadWrite
) {
186 InitializeTestServer();
187 scoped_refptr
<const Extension
> extension
= LoadExtensionWithCapabilities(
188 MakeJSONList("http://foo.example.com/*"),
189 MakeJSONList("clipboardRead", "clipboardWrite"));
191 CanReadClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
193 CanWriteClipboard(extension
.get(), GetTestURLFor("foo.example.com")));
195 CanReadClipboard(extension
.get(), GetTestURLFor("bar.example.com")));
196 // TODO(dcheng): This should be false, but we cannot currently execute testing
197 // script without a user gesture.
199 CanWriteClipboard(extension
.get(), GetTestURLFor("bar.example.com")));
202 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
, UnlimitedStorage
) {
203 InitializeTestServer();
204 scoped_refptr
<const Extension
> extension
=
205 LoadExtensionWithCapabilities(MakeJSONList("http://foo.example.com/*"),
206 MakeJSONList("unlimitedStorage"));
208 HasUnlimitedStorage(extension
.get(), GetTestURLFor("foo.example.com")));
210 HasUnlimitedStorage(extension
.get(), GetTestURLFor("bar.example.com")));
213 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
, WebUnlimitedStorageIsIsolated
) {
214 InitializeTestServer();
215 // This extension grants unlimited storage to bar.example.com but does not
216 // have unlimitedStorage itself.
217 scoped_refptr
<const Extension
> extension
= LoadExtensionWithCapabilities(
218 MakeJSONList("http://bar.example.com/*"),
219 MakeJSONList("unlimitedStorage"), MakeJSONList("storage"));
221 HasUnlimitedStorage(extension
.get(), extension
->GetResourceURL("")));
223 HasUnlimitedStorage(extension
.get(), GetTestURLFor("bar.example.com")));
226 IN_PROC_BROWSER_TEST_F(ContentCapabilitiesTest
,
227 ExtensionUnlimitedStorageIsIsolated
) {
228 InitializeTestServer();
229 // This extension has unlimitedStorage but doesn't grant it to foo.example.com
230 scoped_refptr
<const Extension
> extension
= LoadExtensionWithCapabilities(
231 MakeJSONList("http://foo.example.com/*"), MakeJSONList("clipboardRead"),
232 MakeJSONList("unlimitedStorage"));
235 HasUnlimitedStorage(extension
.get(), extension
->GetResourceURL("")));
237 HasUnlimitedStorage(extension
.get(), GetTestURLFor("foo.example.com")));