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.
4
5 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
6
7 #include <memory>
8 #include <vector>
9
10 #include "base/macros.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "extensions/common/permissions/permission_set.h"
17 #include "extensions/common/permissions/permissions_data.h"
18 #include "extensions/common/permissions/permissions_info.h"
19 #include "extensions/common/permissions/settings_override_permission.h"
20 #include "extensions/common/permissions/usb_device_permission.h"
21 #include "extensions/common/url_pattern_set.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/base/l10n/l10n_util.h"
24
25 namespace extensions {
26
27 // Tests that ChromePermissionMessageProvider provides correct permission
28 // messages for given permissions.
29 // NOTE: No extensions are created as part of these tests. Integration tests
30 // that test the messages are generated properly for extensions can be found in
31 // chrome/browser/extensions/permission_messages_unittest.cc.
32 class ChromePermissionMessageProviderUnittest : public ChromeManifestTest {
33 public:
ChromePermissionMessageProviderUnittest()34 ChromePermissionMessageProviderUnittest()
35 : message_provider_(new ChromePermissionMessageProvider()) {}
~ChromePermissionMessageProviderUnittest()36 ~ChromePermissionMessageProviderUnittest() override {}
37
38 protected:
GetMessages(const APIPermissionSet & permissions,Manifest::Type type)39 PermissionMessages GetMessages(const APIPermissionSet& permissions,
40 Manifest::Type type) {
41 return message_provider_->GetPermissionMessages(
42 message_provider_->GetAllPermissionIDs(
43 PermissionSet(permissions.Clone(), ManifestPermissionSet(),
44 URLPatternSet(), URLPatternSet()),
45 type));
46 }
47
GetManagementUIPermissionIDs(const APIPermissionSet & api_permissions,const ManifestPermissionSet & manifest_permissions,Manifest::Type type)48 PermissionMessages GetManagementUIPermissionIDs(
49 const APIPermissionSet& api_permissions,
50 const ManifestPermissionSet& manifest_permissions,
51 Manifest::Type type) {
52 return message_provider_->GetPermissionMessages(
53 message_provider_->GetManagementUIPermissionIDs(
54 PermissionSet(api_permissions.Clone(), manifest_permissions.Clone(),
55 URLPatternSet(), URLPatternSet()),
56 type));
57 }
58
IsPrivilegeIncrease(const APIPermissionSet & granted_permissions,const URLPatternSet & granted_hosts,const APIPermissionSet & requested_permissions,const URLPatternSet & requested_hosts)59 bool IsPrivilegeIncrease(const APIPermissionSet& granted_permissions,
60 const URLPatternSet& granted_hosts,
61 const APIPermissionSet& requested_permissions,
62 const URLPatternSet& requested_hosts) {
63 return message_provider_->IsPrivilegeIncrease(
64 PermissionSet(granted_permissions.Clone(), ManifestPermissionSet(),
65 granted_hosts.Clone(), URLPatternSet()),
66 PermissionSet(requested_permissions.Clone(), ManifestPermissionSet(),
67 requested_hosts.Clone(), URLPatternSet()),
68 Manifest::TYPE_EXTENSION);
69 }
70
message_provider()71 ChromePermissionMessageProvider* message_provider() {
72 return message_provider_.get();
73 }
74
75 private:
76 std::unique_ptr<ChromePermissionMessageProvider> message_provider_;
77
78 DISALLOW_COPY_AND_ASSIGN(ChromePermissionMessageProviderUnittest);
79 };
80
81 // Checks that if an app has a superset and a subset permission, only the
82 // superset permission message is displayed if they are both present.
TEST_F(ChromePermissionMessageProviderUnittest,SupersetOverridesSubsetPermission)83 TEST_F(ChromePermissionMessageProviderUnittest,
84 SupersetOverridesSubsetPermission) {
85 {
86 APIPermissionSet permissions;
87 permissions.insert(APIPermission::kTab);
88 PermissionMessages messages =
89 GetMessages(permissions, Manifest::TYPE_PLATFORM_APP);
90 ASSERT_EQ(1U, messages.size());
91 EXPECT_EQ(
92 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ),
93 messages.front().message());
94 }
95 {
96 APIPermissionSet permissions;
97 permissions.insert(APIPermission::kTopSites);
98 PermissionMessages messages =
99 GetMessages(permissions, Manifest::TYPE_PLATFORM_APP);
100 ASSERT_EQ(1U, messages.size());
101 EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_TOPSITES),
102 messages.front().message());
103 }
104 {
105 APIPermissionSet permissions;
106 permissions.insert(APIPermission::kTab);
107 permissions.insert(APIPermission::kTopSites);
108 PermissionMessages messages =
109 GetMessages(permissions, Manifest::TYPE_PLATFORM_APP);
110 ASSERT_EQ(1U, messages.size());
111 EXPECT_EQ(
112 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ),
113 messages.front().message());
114 }
115 }
116
117 // Checks that when permissions are merged into a single message, their details
118 // are merged as well.
TEST_F(ChromePermissionMessageProviderUnittest,WarningsAndDetailsCoalesceTogether)119 TEST_F(ChromePermissionMessageProviderUnittest,
120 WarningsAndDetailsCoalesceTogether) {
121 // kTab and kTopSites should be merged into a single message.
122 APIPermissionSet permissions;
123 permissions.insert(APIPermission::kTab);
124 permissions.insert(APIPermission::kTopSites);
125 // The USB device permission message has a non-empty details string.
126 std::unique_ptr<UsbDevicePermission> usb(new UsbDevicePermission(
127 PermissionsInfo::GetInstance()->GetByID(APIPermission::kUsbDevice)));
128 std::unique_ptr<base::ListValue> devices_list(new base::ListValue());
129 devices_list->Append(
130 UsbDevicePermissionData(0x02ad, 0x138c, -1, -1).ToValue());
131 devices_list->Append(
132 UsbDevicePermissionData(0x02ad, 0x138d, -1, -1).ToValue());
133 ASSERT_TRUE(usb->FromValue(devices_list.get(), nullptr, nullptr));
134 permissions.insert(std::move(usb));
135
136 PermissionMessages messages =
137 GetMessages(permissions, Manifest::TYPE_EXTENSION);
138
139 ASSERT_EQ(2U, messages.size());
140 auto it = messages.begin();
141 const PermissionMessage& message0 = *it++;
142 EXPECT_EQ(
143 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ),
144 message0.message());
145 EXPECT_TRUE(message0.submessages().empty());
146 const PermissionMessage& message1 = *it++;
147 EXPECT_EQ(
148 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST),
149 message1.message());
150 EXPECT_FALSE(message1.submessages().empty());
151 }
152
153 // Check that if IDN domains are provided in host permissions, then those
154 // domains are converted to punycode.
TEST_F(ChromePermissionMessageProviderUnittest,IDNDomainsInHostPermissionsArePunycoded)155 TEST_F(ChromePermissionMessageProviderUnittest,
156 IDNDomainsInHostPermissionsArePunycoded) {
157 extensions::URLPatternSet explicit_hosts;
158
159 explicit_hosts.AddPattern(
160 URLPattern(URLPattern::SCHEME_ALL, "https://ɡoogle.com/"));
161 explicit_hosts.AddPattern(
162 URLPattern(URLPattern::SCHEME_ALL, "https://*.ɡoogle.com/"));
163 extensions::PermissionSet permissions(
164 APIPermissionSet(), ManifestPermissionSet(), std::move(explicit_hosts),
165 URLPatternSet());
166
167 PermissionMessages messages = message_provider()->GetPermissionMessages(
168 message_provider()->GetAllPermissionIDs(permissions,
169 Manifest::TYPE_EXTENSION));
170
171 ASSERT_EQ(1U, messages.size());
172 EXPECT_EQ(l10n_util::GetStringFUTF16(
173 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
174 base::ASCIIToUTF16("all xn--oogle-qmc.com sites"),
175 base::ASCIIToUTF16("xn--oogle-qmc.com")),
176 messages.front().message());
177 }
178
179 // Checks whether powerful permissions are returned correctly.
TEST_F(ChromePermissionMessageProviderUnittest,PowerfulPermissions)180 TEST_F(ChromePermissionMessageProviderUnittest, PowerfulPermissions) {
181 {
182 APIPermissionSet permissions;
183 permissions.insert(APIPermission::kTab);
184 PermissionMessages messages = GetManagementUIPermissionIDs(
185 permissions, ManifestPermissionSet(), Manifest::TYPE_EXTENSION);
186 ASSERT_EQ(1U, messages.size());
187 EXPECT_EQ(
188 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ),
189 messages.front().message());
190 }
191 {
192 APIPermissionSet permissions;
193 permissions.insert(APIPermission::kBookmark);
194 PermissionMessages messages = GetManagementUIPermissionIDs(
195 permissions, ManifestPermissionSet(), Manifest::TYPE_EXTENSION);
196 ASSERT_EQ(0U, messages.size());
197 }
198 {
199 APIPermissionSet permissions;
200 permissions.insert(APIPermission::kTab);
201 permissions.insert(APIPermission::kBookmark);
202 PermissionMessages messages = GetManagementUIPermissionIDs(
203 permissions, ManifestPermissionSet(), Manifest::TYPE_EXTENSION);
204 ASSERT_EQ(1U, messages.size());
205 EXPECT_EQ(
206 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ),
207 messages.front().message());
208 }
209 {
210 scoped_refptr<Extension> extension =
211 ManifestTest::LoadAndExpectSuccess("automation_desktop_true.json");
212 ASSERT_TRUE(extension.get());
213 ManifestPermissionSet manifest_permissions = extension->permissions_data()
214 ->active_permissions()
215 .manifest_permissions()
216 .Clone();
217 APIPermissionSet permissions;
218 permissions.insert(APIPermission::kTab);
219 permissions.insert(APIPermission::kBookmark);
220 permissions.insert(APIPermission::kDebugger);
221 PermissionMessages messages = GetManagementUIPermissionIDs(
222 permissions, manifest_permissions, Manifest::TYPE_EXTENSION);
223 ASSERT_EQ(2U, messages.size());
224 EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_DEBUGGER),
225 messages.front().message());
226 EXPECT_EQ(
227 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS),
228 messages[1].message());
229 }
230 {
231 scoped_refptr<Extension> extension = ManifestTest::LoadAndExpectSuccess(
232 "automation_all_hosts_interact_true.json");
233 ASSERT_TRUE(extension.get());
234 ManifestPermissionSet manifest_permissions = extension->permissions_data()
235 ->active_permissions()
236 .manifest_permissions()
237 .Clone();
238 APIPermissionSet permissions;
239 permissions.insert(APIPermission::kTab);
240 PermissionMessages messages = GetManagementUIPermissionIDs(
241 permissions, manifest_permissions, Manifest::TYPE_EXTENSION);
242 ASSERT_EQ(1U, messages.size());
243 EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS),
244 messages.front().message());
245 }
246 }
247
248 // Checks that granted hosts that may cause API permission messages are
249 // processed as part of IsPrivilegeIncrease. Regression test for
250 // crbug.com/1014505.
TEST_F(ChromePermissionMessageProviderUnittest,PrivilegeIncreaseAllUrls)251 TEST_F(ChromePermissionMessageProviderUnittest, PrivilegeIncreaseAllUrls) {
252 APIPermissionSet granted_permissions;
253 granted_permissions.insert(APIPermission::kWebRequest);
254
255 extensions::URLPatternSet granted_hosts;
256 granted_hosts.AddPattern(URLPattern(URLPattern::SCHEME_ALL, "<all_urls>"));
257
258 APIPermissionSet requested_permissions;
259 requested_permissions.insert(APIPermission::kWebRequest);
260 requested_permissions.insert(APIPermission::kDeclarativeNetRequest);
261
262 extensions::URLPatternSet requested_hosts;
263 requested_hosts.AddPattern(URLPattern(URLPattern::SCHEME_ALL, "<all_urls>"));
264
265 // While |kDeclarativeNetRequest| would cause a permission message, the
266 // inclusion of <all_urls> for both granted and request permissions should
267 // subsume the permission message for |kDeclarativeNetRequest| with its own
268 // message. Since this message would be identical between
269 // |granted_permissions| and |requested_permissions|, there should not be a
270 // privilege increase.
271 EXPECT_FALSE(IsPrivilegeIncrease(granted_permissions, granted_hosts,
272 requested_permissions, requested_hosts));
273 }
274
275 } // namespace extensions
276