1 // Copyright 2020 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/browser/permissions/abusive_origin_permission_revocation_request.h"
6
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/test/mock_callback.h"
9 #include "base/test/scoped_feature_list.h"
10 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
11 #include "chrome/browser/history/history_service_factory.h"
12 #include "chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h"
13 #include "chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h"
14 #include "chrome/browser/permissions/crowd_deny_preload_data.h"
15 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
16 #include "chrome/common/chrome_features.h"
17 #include "chrome/test/base/testing_browser_process.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "components/content_settings/core/browser/host_content_settings_map.h"
20 #include "components/prefs/pref_service.h"
21 #include "content/public/test/browser_task_environment.h"
22
23 class AbusiveOriginPermissionRevocationRequestTestBase : public testing::Test {
24 public:
25 using Outcome = AbusiveOriginPermissionRevocationRequest::Outcome;
26 using SiteReputation = CrowdDenyPreloadData::SiteReputation;
27
28 AbusiveOriginPermissionRevocationRequestTestBase() = default;
29
30 ~AbusiveOriginPermissionRevocationRequestTestBase() override = default;
31
32 protected:
SetUp()33 void SetUp() override {
34 testing::Test::SetUp();
35
36 DCHECK(profile_dir_.CreateUniqueTempDir());
37 TestingProfile::Builder profile_builder;
38 profile_builder.SetPath(profile_dir_.GetPath());
39 profile_builder.AddTestingFactory(
40 HistoryServiceFactory::GetInstance(),
41 HistoryServiceFactory::GetDefaultFactory());
42 testing_profile_ = profile_builder.Build();
43
44 fake_database_manager_ =
45 base::MakeRefCounted<CrowdDenyFakeSafeBrowsingDatabaseManager>();
46 safe_browsing_factory_ =
47 std::make_unique<safe_browsing::TestSafeBrowsingServiceFactory>();
48 safe_browsing_factory_->SetTestDatabaseManager(
49 fake_database_manager_.get());
50 TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
51 safe_browsing_factory_->CreateSafeBrowsingService());
52 }
53
TearDown()54 void TearDown() override {
55 TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
56 testing::Test::TearDown();
57 }
58
AddToSafeBrowsingBlocklist(const GURL & url)59 void AddToSafeBrowsingBlocklist(const GURL& url) {
60 safe_browsing::ThreatMetadata test_metadata;
61 test_metadata.api_permissions.emplace("NOTIFICATIONS");
62 fake_database_manager_->SetSimulatedMetadataForUrl(url, test_metadata);
63 }
64
ClearSafeBrowsingBlocklist()65 void ClearSafeBrowsingBlocklist() {
66 fake_database_manager_->RemoveAllBlacklistedUrls();
67 }
68
AddToPreloadDataBlocklist(const GURL & origin,chrome_browser_crowd_deny::SiteReputation_NotificationUserExperienceQuality reputation_type,bool has_warning)69 void AddToPreloadDataBlocklist(
70 const GURL& origin,
71 chrome_browser_crowd_deny::
72 SiteReputation_NotificationUserExperienceQuality reputation_type,
73 bool has_warning) {
74 SiteReputation reputation;
75 reputation.set_notification_ux_quality(reputation_type);
76 reputation.set_warning_only(has_warning);
77 testing_preload_data_.SetOriginReputation(url::Origin::Create(origin),
78 std::move(reputation));
79 }
80
QueryAndExpectDecisionForUrl(const GURL & origin,Outcome expected_result)81 void QueryAndExpectDecisionForUrl(const GURL& origin,
82 Outcome expected_result) {
83 base::MockOnceCallback<void(Outcome)> mock_callback_receiver;
84 permission_revocation_ =
85 std::make_unique<AbusiveOriginPermissionRevocationRequest>(
86 testing_profile_.get(), origin, mock_callback_receiver.Get());
87 EXPECT_CALL(mock_callback_receiver, Run(expected_result));
88 task_environment_.RunUntilIdle();
89 permission_revocation_.reset();
90 }
91
SetPermission(const GURL & origin,const ContentSetting value)92 void SetPermission(const GURL& origin, const ContentSetting value) {
93 HostContentSettingsMap* host_content_settings_map =
94 HostContentSettingsMapFactory::GetForProfile(testing_profile_.get());
95 host_content_settings_map->SetContentSettingDefaultScope(
96 origin, GURL(), ContentSettingsType::NOTIFICATIONS, value);
97 }
98
VerifyNotificationsPermission(const GURL & origin,const ContentSetting value)99 void VerifyNotificationsPermission(const GURL& origin,
100 const ContentSetting value) {
101 HostContentSettingsMap* host_content_settings_map =
102 HostContentSettingsMapFactory::GetForProfile(testing_profile_.get());
103
104 ContentSetting result = host_content_settings_map->GetContentSetting(
105 origin, GURL(), ContentSettingsType::NOTIFICATIONS);
106
107 EXPECT_EQ(value, result);
108 }
109
GetTestingProfile()110 TestingProfile* GetTestingProfile() { return testing_profile_.get(); }
111
112 private:
113 base::ScopedTempDir profile_dir_;
114 content::BrowserTaskEnvironment task_environment_;
115 testing::ScopedCrowdDenyPreloadDataOverride testing_preload_data_;
116 std::unique_ptr<TestingProfile> testing_profile_;
117 std::unique_ptr<AbusiveOriginPermissionRevocationRequest>
118 permission_revocation_;
119 scoped_refptr<CrowdDenyFakeSafeBrowsingDatabaseManager>
120 fake_database_manager_;
121 std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory>
122 safe_browsing_factory_;
123
124 DISALLOW_COPY_AND_ASSIGN(AbusiveOriginPermissionRevocationRequestTestBase);
125 };
126
127 class AbusiveOriginPermissionRevocationRequestTest
128 : public AbusiveOriginPermissionRevocationRequestTestBase {
129 public:
AbusiveOriginPermissionRevocationRequestTest()130 AbusiveOriginPermissionRevocationRequestTest() {
131 feature_list_.InitAndEnableFeature(
132 features::kAbusiveNotificationPermissionRevocation);
133 }
134
135 ~AbusiveOriginPermissionRevocationRequestTest() override = default;
136
137 private:
138 base::test::ScopedFeatureList feature_list_;
139 };
140
TEST_F(AbusiveOriginPermissionRevocationRequestTest,OriginIsNotOnBlockingLists)141 TEST_F(AbusiveOriginPermissionRevocationRequestTest,
142 OriginIsNotOnBlockingLists) {
143 const GURL origin_to_revoke = GURL("https://origin.com/");
144
145 SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
146
147 QueryAndExpectDecisionForUrl(origin_to_revoke,
148 Outcome::PERMISSION_NOT_REVOKED);
149 VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
150 }
151
TEST_F(AbusiveOriginPermissionRevocationRequestTest,SafeBrowsingTest)152 TEST_F(AbusiveOriginPermissionRevocationRequestTest, SafeBrowsingTest) {
153 const GURL origin_to_revoke = GURL("https://origin.com/");
154
155 SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
156
157 // The origin is not on any blocking lists. Notifications permission is not
158 // revoked.
159 QueryAndExpectDecisionForUrl(origin_to_revoke,
160 Outcome::PERMISSION_NOT_REVOKED);
161
162 AddToSafeBrowsingBlocklist(origin_to_revoke);
163 // Origin is not on CrowdDeny blocking lists.
164 QueryAndExpectDecisionForUrl(origin_to_revoke,
165 Outcome::PERMISSION_NOT_REVOKED);
166 VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
167 EXPECT_FALSE(
168 AbusiveOriginPermissionRevocationRequest::HasPreviouslyRevokedPermission(
169 GetTestingProfile(), origin_to_revoke));
170
171 AddToPreloadDataBlocklist(origin_to_revoke, SiteReputation::ABUSIVE_CONTENT,
172 /*has_warning=*/false);
173 QueryAndExpectDecisionForUrl(origin_to_revoke,
174 Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE);
175 VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ASK);
176 EXPECT_TRUE(
177 AbusiveOriginPermissionRevocationRequest::HasPreviouslyRevokedPermission(
178 GetTestingProfile(), origin_to_revoke));
179 }
180
TEST_F(AbusiveOriginPermissionRevocationRequestTest,PreloadDataTest)181 TEST_F(AbusiveOriginPermissionRevocationRequestTest, PreloadDataTest) {
182 const GURL abusive_content_origin_to_revoke =
183 GURL("https://abusive-content.com/");
184 const GURL abusive_prompts_origin_to_revoke =
185 GURL("https://abusive-prompts.com/");
186 const GURL unsolicited_prompts_origin =
187 GURL("https://unsolicited-prompts.com/");
188 const GURL acceptable_origin = GURL("https://acceptable-origin.com/");
189 const GURL unknown_origin = GURL("https://unknown-origin.com/");
190
191 auto origins = {abusive_content_origin_to_revoke,
192 abusive_prompts_origin_to_revoke, unsolicited_prompts_origin,
193 acceptable_origin, unknown_origin};
194
195 for (auto origin : origins)
196 SetPermission(origin, CONTENT_SETTING_ALLOW);
197
198 // The origins are not on any blocking lists.
199 for (auto origin : origins)
200 QueryAndExpectDecisionForUrl(origin, Outcome::PERMISSION_NOT_REVOKED);
201
202 AddToPreloadDataBlocklist(abusive_content_origin_to_revoke,
203 SiteReputation::ABUSIVE_CONTENT,
204 /*has_warning=*/false);
205 AddToPreloadDataBlocklist(abusive_prompts_origin_to_revoke,
206 SiteReputation::ABUSIVE_PROMPTS,
207 /*has_warning=*/false);
208 AddToPreloadDataBlocklist(unsolicited_prompts_origin,
209 SiteReputation::UNSOLICITED_PROMPTS,
210 /*has_warning=*/false);
211 AddToPreloadDataBlocklist(acceptable_origin, SiteReputation::ACCEPTABLE,
212 /*has_warning=*/false);
213 AddToPreloadDataBlocklist(unknown_origin, SiteReputation::UNKNOWN,
214 /*has_warning=*/false);
215
216 // The origins are on CrowdDeny blocking lists, but not on SafeBrowsing.
217 for (auto origin : origins)
218 QueryAndExpectDecisionForUrl(origin, Outcome::PERMISSION_NOT_REVOKED);
219
220 for (auto origin : origins)
221 AddToSafeBrowsingBlocklist(origin);
222
223 QueryAndExpectDecisionForUrl(abusive_content_origin_to_revoke,
224 Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE);
225 QueryAndExpectDecisionForUrl(abusive_prompts_origin_to_revoke,
226 Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE);
227 QueryAndExpectDecisionForUrl(unsolicited_prompts_origin,
228 Outcome::PERMISSION_NOT_REVOKED);
229 QueryAndExpectDecisionForUrl(acceptable_origin,
230 Outcome::PERMISSION_NOT_REVOKED);
231 QueryAndExpectDecisionForUrl(unknown_origin, Outcome::PERMISSION_NOT_REVOKED);
232 }
233
TEST_F(AbusiveOriginPermissionRevocationRequestTest,PreloadDataTestWithWarning)234 TEST_F(AbusiveOriginPermissionRevocationRequestTest,
235 PreloadDataTestWithWarning) {
236 const GURL abusive_content_origin_to_revoke =
237 GURL("https://abusive-content.com/");
238 const GURL abusive_prompts_origin_to_revoke =
239 GURL("https://abusive-prompts.com/");
240 const GURL unsolicited_prompts_origin =
241 GURL("https://unsolicited-prompts.com/");
242 const GURL acceptable_origin = GURL("https://acceptable-origin.com/");
243 const GURL unknown_origin = GURL("https://unknown-origin.com/");
244
245 auto origins = {abusive_content_origin_to_revoke,
246 abusive_prompts_origin_to_revoke, unsolicited_prompts_origin,
247 acceptable_origin, unknown_origin};
248
249 for (auto origin : origins)
250 SetPermission(origin, CONTENT_SETTING_ALLOW);
251
252 // The origins are not on any blocking lists.
253 for (auto origin : origins)
254 QueryAndExpectDecisionForUrl(origin, Outcome::PERMISSION_NOT_REVOKED);
255
256 AddToPreloadDataBlocklist(abusive_content_origin_to_revoke,
257 SiteReputation::ABUSIVE_CONTENT,
258 /*has_warning=*/true);
259 AddToPreloadDataBlocklist(abusive_prompts_origin_to_revoke,
260 SiteReputation::ABUSIVE_PROMPTS,
261 /*has_warning=*/true);
262 AddToPreloadDataBlocklist(unsolicited_prompts_origin,
263 SiteReputation::UNSOLICITED_PROMPTS,
264 /*has_warning=*/true);
265 AddToPreloadDataBlocklist(acceptable_origin, SiteReputation::ACCEPTABLE,
266 /*has_warning=*/true);
267 AddToPreloadDataBlocklist(unknown_origin, SiteReputation::UNKNOWN,
268 /*has_warning=*/true);
269
270 // The origins are on CrowdDeny blocking lists, but not on SafeBrowsing.
271 for (auto origin : origins)
272 QueryAndExpectDecisionForUrl(origin, Outcome::PERMISSION_NOT_REVOKED);
273
274 for (auto origin : origins)
275 AddToSafeBrowsingBlocklist(origin);
276
277 // The warning is enabled for all origin, permission should not be revoked.
278 for (auto origin : origins)
279 QueryAndExpectDecisionForUrl(origin, Outcome::PERMISSION_NOT_REVOKED);
280 }
281
TEST_F(AbusiveOriginPermissionRevocationRequestTest,ExemptAbusiveOriginTest)282 TEST_F(AbusiveOriginPermissionRevocationRequestTest, ExemptAbusiveOriginTest) {
283 const GURL origin_to_exempt = GURL("https://origin-allow.com/");
284 const GURL origin_to_revoke = GURL("https://origin.com/");
285
286 AbusiveOriginPermissionRevocationRequest::ExemptOriginFromFutureRevocations(
287 GetTestingProfile(), origin_to_exempt);
288
289 SetPermission(origin_to_exempt, CONTENT_SETTING_ALLOW);
290
291 AddToPreloadDataBlocklist(origin_to_exempt, SiteReputation::ABUSIVE_CONTENT,
292 /*has_warning=*/false);
293 AddToSafeBrowsingBlocklist(origin_to_exempt);
294
295 SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
296 AddToPreloadDataBlocklist(origin_to_revoke, SiteReputation::ABUSIVE_CONTENT,
297 /*has_warning=*/false);
298 AddToSafeBrowsingBlocklist(origin_to_revoke);
299
300 // The origin added to the exempt list will not be revoked.
301 QueryAndExpectDecisionForUrl(origin_to_exempt,
302 Outcome::PERMISSION_NOT_REVOKED);
303 VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
304
305 QueryAndExpectDecisionForUrl(origin_to_revoke,
306 Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE);
307 VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ASK);
308 }
309
TEST_F(AbusiveOriginPermissionRevocationRequestTest,SafeBrowsingDisabledTest)310 TEST_F(AbusiveOriginPermissionRevocationRequestTest, SafeBrowsingDisabledTest) {
311 const GURL origin_to_revoke = GURL("https://origin.com/");
312
313 SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
314
315 AddToSafeBrowsingBlocklist(origin_to_revoke);
316 AddToPreloadDataBlocklist(origin_to_revoke, SiteReputation::ABUSIVE_CONTENT,
317 /*has_warning=*/false);
318 QueryAndExpectDecisionForUrl(origin_to_revoke,
319 Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE);
320
321 GetTestingProfile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled,
322 false);
323
324 // Permission should not be revoked because Safe Browsing is disabled.
325 const GURL origin_to_not_revoke = GURL("https://origin-not_revoked.com/");
326
327 SetPermission(origin_to_not_revoke, CONTENT_SETTING_ALLOW);
328
329 AddToSafeBrowsingBlocklist(origin_to_not_revoke);
330 AddToPreloadDataBlocklist(origin_to_not_revoke,
331 SiteReputation::ABUSIVE_CONTENT,
332 /*has_warning=*/false);
333
334 QueryAndExpectDecisionForUrl(origin_to_not_revoke,
335 Outcome::PERMISSION_NOT_REVOKED);
336 VerifyNotificationsPermission(origin_to_not_revoke, CONTENT_SETTING_ALLOW);
337 }
338
339 class AbusiveOriginPermissionRevocationRequestDisabledTest
340 : public AbusiveOriginPermissionRevocationRequestTestBase {
341 public:
342 AbusiveOriginPermissionRevocationRequestDisabledTest() = default;
343 ~AbusiveOriginPermissionRevocationRequestDisabledTest() override = default;
344 };
345
TEST_F(AbusiveOriginPermissionRevocationRequestDisabledTest,PermissionRevocationFeatureDisabled)346 TEST_F(AbusiveOriginPermissionRevocationRequestDisabledTest,
347 PermissionRevocationFeatureDisabled) {
348 const GURL origin_to_revoke = GURL("https://origin.com/");
349
350 SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
351 QueryAndExpectDecisionForUrl(origin_to_revoke,
352 Outcome::PERMISSION_NOT_REVOKED);
353 VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ALLOW);
354 }
355