OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/permissions/permission_context_base.h" | 5 #include "chrome/browser/permissions/permission_context_base.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | |
9 #include <set> | |
10 #include <string> | |
8 #include <utility> | 11 #include <utility> |
9 | 12 |
10 #include "base/callback.h" | 13 #include "base/callback.h" |
11 #include "base/logging.h" | 14 #include "base/logging.h" |
12 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
13 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "base/timer/timer.h" | |
14 #include "build/build_config.h" | 18 #include "build/build_config.h" |
19 #include "chrome/browser/browser_process.h" | |
15 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 20 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
16 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" | 21 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" |
17 #include "chrome/browser/permissions/permission_request.h" | 22 #include "chrome/browser/permissions/permission_request.h" |
18 #include "chrome/browser/permissions/permission_request_id.h" | 23 #include "chrome/browser/permissions/permission_request_id.h" |
19 #include "chrome/browser/permissions/permission_request_impl.h" | 24 #include "chrome/browser/permissions/permission_request_impl.h" |
20 #include "chrome/browser/permissions/permission_request_manager.h" | 25 #include "chrome/browser/permissions/permission_request_manager.h" |
21 #include "chrome/browser/permissions/permission_uma_util.h" | 26 #include "chrome/browser/permissions/permission_uma_util.h" |
22 #include "chrome/browser/permissions/permission_util.h" | 27 #include "chrome/browser/permissions/permission_util.h" |
23 #include "chrome/browser/profiles/profile.h" | 28 #include "chrome/browser/profiles/profile.h" |
29 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | |
30 #include "chrome/common/chrome_features.h" | |
24 #include "chrome/common/pref_names.h" | 31 #include "chrome/common/pref_names.h" |
25 #include "components/content_settings/core/browser/host_content_settings_map.h" | 32 #include "components/content_settings/core/browser/host_content_settings_map.h" |
26 #include "components/content_settings/core/browser/website_settings_registry.h" | 33 #include "components/content_settings/core/browser/website_settings_registry.h" |
27 #include "components/prefs/pref_service.h" | 34 #include "components/prefs/pref_service.h" |
35 #include "components/safe_browsing_db/database_manager.h" | |
28 #include "components/variations/variations_associated_data.h" | 36 #include "components/variations/variations_associated_data.h" |
29 #include "content/public/browser/browser_thread.h" | 37 #include "content/public/browser/browser_thread.h" |
30 #include "content/public/browser/render_frame_host.h" | 38 #include "content/public/browser/render_frame_host.h" |
31 #include "content/public/browser/web_contents.h" | 39 #include "content/public/browser/web_contents.h" |
40 #include "content/public/browser/web_contents_observer.h" | |
32 #include "content/public/common/origin_util.h" | 41 #include "content/public/common/origin_util.h" |
33 #include "url/gurl.h" | 42 #include "url/gurl.h" |
34 | 43 |
35 #if defined(OS_ANDROID) | 44 #if defined(OS_ANDROID) |
36 #include "chrome/browser/permissions/permission_queue_controller.h" | 45 #include "chrome/browser/permissions/permission_queue_controller.h" |
37 #endif | 46 #endif |
38 | 47 |
39 // static | 48 // static |
40 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = | 49 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = |
41 "PermissionsKillSwitch"; | 50 "PermissionsKillSwitch"; |
42 // static | 51 // static |
43 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = | 52 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = |
44 "blocked"; | 53 "blocked"; |
54 // Maximum time in milliseconds to wait for safe browsing service to check a | |
55 // url for blacklisting. After this amount of time, the check will be aborted | |
56 // and the url will be treated as not blacklisted. | |
57 // TODO(meredithl): Revisit this once UMA metrics have data about request time. | |
58 const int kCheckUrlTimeoutMs = 2000; | |
59 | |
60 // The client used when checking whether a permission has been blacklisted by | |
61 // Safe Browsing. The check is done asynchronously as no state can be stored in | |
62 // PermissionContextBase (since additional permission requests may be made). | |
63 // This class must be created and destroyed on the UI thread. | |
64 class PermissionsBlacklistingClient | |
65 : public safe_browsing::SafeBrowsingDatabaseManager::Client, | |
66 public base::RefCountedThreadSafe<PermissionsBlacklistingClient>, | |
67 public content::WebContentsObserver { | |
68 public: | |
69 static void CheckSafeBrowsingBlacklist( | |
70 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, | |
71 content::PermissionType permission_type, | |
72 const GURL& request_origin, | |
73 content::WebContents* web_contents, | |
74 int timeout, | |
75 base::Callback<void(bool)> callback) { | |
76 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
77 | |
78 new PermissionsBlacklistingClient(db_manager, permission_type, | |
79 request_origin, web_contents, timeout, | |
80 callback); | |
81 } | |
82 | |
83 private: | |
84 friend class base::RefCountedThreadSafe<PermissionsBlacklistingClient>; | |
85 | |
86 PermissionsBlacklistingClient( | |
87 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, | |
88 content::PermissionType permission_type, | |
89 const GURL& request_origin, | |
90 content::WebContents* web_contents, | |
91 int timeout, | |
92 base::Callback<void(bool)> callback) | |
93 : content::WebContentsObserver(web_contents), | |
94 db_manager_(db_manager), | |
95 permission_type_(permission_type), | |
96 callback_(callback), | |
97 timeout_(timeout), | |
98 is_active_(true) /* Web Contents is active upon construction */ { | |
raymes
2017/01/10 02:57:15
nit: don't use an inline comment here. I think it'
meredithl
2017/01/10 03:40:46
Done.
| |
99 // Balanced by a call to Release() in OnCheckApiBlacklistUrlResult(). | |
100 AddRef(); | |
101 content::BrowserThread::PostTask( | |
102 content::BrowserThread::IO, FROM_HERE, | |
103 base::Bind(&PermissionsBlacklistingClient::StartCheck, this, | |
104 request_origin)); | |
105 } | |
106 | |
107 ~PermissionsBlacklistingClient() override {} | |
108 | |
109 void StartCheck(const GURL& request_origin) { | |
110 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
111 | |
112 // Start the timer to interrupt into the client callback method with an | |
113 // empty response if Safe Browsing times out. | |
114 safe_browsing::ThreatMetadata empty_metadata; | |
115 timer_ = base::MakeUnique<base::OneShotTimer>(); | |
116 timer_->Start( | |
117 FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_), | |
118 base::Bind(&PermissionsBlacklistingClient::OnCheckApiBlacklistUrlResult, | |
119 this, request_origin, empty_metadata)); | |
120 db_manager_->CheckApiBlacklistUrl(request_origin, this); | |
121 } | |
122 | |
123 // SafeBrowsingDatabaseManager::Client implementation. | |
124 void OnCheckApiBlacklistUrlResult( | |
125 const GURL& url, | |
126 const safe_browsing::ThreatMetadata& metadata) override { | |
127 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
128 | |
129 if (timer_->IsRunning()) | |
130 timer_->Stop(); | |
131 else | |
132 db_manager_->CancelApiCheck(this); | |
133 timer_.reset(nullptr); | |
134 | |
135 // TODO(meredithl): Convert the strings returned from Safe Browsing to the | |
136 // ones used by PermissionUtil for comparison. | |
137 bool permission_blocked = | |
138 metadata.api_permissions.find(PermissionUtil::GetPermissionString( | |
139 permission_type_)) != metadata.api_permissions.end(); | |
140 | |
141 content::BrowserThread::PostTask( | |
142 content::BrowserThread::UI, FROM_HERE, | |
143 base::Bind( | |
144 &PermissionsBlacklistingClient::EvaluateBlacklistResultOnUiThread, | |
145 this, permission_blocked)); | |
146 } | |
147 | |
148 void EvaluateBlacklistResultOnUiThread(bool permission_blocked) { | |
149 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
150 | |
151 if (is_active_) | |
152 callback_.Run(permission_blocked); | |
153 Release(); | |
154 } | |
155 | |
156 // WebContentsObserver implementation. Sets the flag so that when the database | |
157 // manager returns with a result, it won't attempt to run the callback with a | |
158 // deleted WebContents. | |
159 void WebContentsDestroyed() override { | |
160 is_active_ = false; | |
161 Observe(nullptr); | |
162 } | |
163 | |
164 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager_; | |
165 content::PermissionType permission_type_; | |
166 | |
167 // PermissionContextBase callback to run on the UI thread. | |
168 base::Callback<void(bool)> callback_; | |
169 | |
170 // Timer to abort the Safe Browsing check if it takes too long. Created and | |
171 // used on the IO Thread. | |
172 std::unique_ptr<base::OneShotTimer> timer_; | |
173 int timeout_; | |
174 | |
175 // True if |callback_| should be invoked, if web_contents() is destroyed, this | |
176 // is set to false. | |
177 bool is_active_; | |
178 | |
179 DISALLOW_COPY_AND_ASSIGN(PermissionsBlacklistingClient); | |
180 }; | |
45 | 181 |
46 PermissionContextBase::PermissionContextBase( | 182 PermissionContextBase::PermissionContextBase( |
47 Profile* profile, | 183 Profile* profile, |
48 const content::PermissionType permission_type, | 184 const content::PermissionType permission_type, |
49 const ContentSettingsType content_settings_type) | 185 const ContentSettingsType content_settings_type) |
50 : profile_(profile), | 186 : profile_(profile), |
51 permission_type_(permission_type), | 187 permission_type_(permission_type), |
52 content_settings_type_(content_settings_type), | 188 content_settings_type_(content_settings_type), |
189 safe_browsing_timeout_(kCheckUrlTimeoutMs), | |
53 weak_factory_(this) { | 190 weak_factory_(this) { |
54 #if defined(OS_ANDROID) | 191 #if defined(OS_ANDROID) |
55 permission_queue_controller_.reset(new PermissionQueueController( | 192 permission_queue_controller_.reset(new PermissionQueueController( |
56 profile_, permission_type_, content_settings_type_)); | 193 profile_, permission_type_, content_settings_type_)); |
57 #endif | 194 #endif |
58 PermissionDecisionAutoBlocker::UpdateFromVariations(); | 195 PermissionDecisionAutoBlocker::UpdateFromVariations(); |
59 } | 196 } |
60 | 197 |
61 PermissionContextBase::~PermissionContextBase() { | 198 PermissionContextBase::~PermissionContextBase() { |
62 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 199 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 | 231 |
95 DVLOG(1) << "Attempt to use " << type_name | 232 DVLOG(1) << "Attempt to use " << type_name |
96 << " from an invalid URL: " << requesting_origin << "," | 233 << " from an invalid URL: " << requesting_origin << "," |
97 << embedding_origin << " (" << type_name | 234 << embedding_origin << " (" << type_name |
98 << " is not supported in popups)"; | 235 << " is not supported in popups)"; |
99 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 236 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
100 false /* persist */, CONTENT_SETTING_BLOCK); | 237 false /* persist */, CONTENT_SETTING_BLOCK); |
101 return; | 238 return; |
102 } | 239 } |
103 | 240 |
241 if (base::FeatureList::IsEnabled(features::kPermissionsBlacklist)) { | |
242 if (!db_manager_) { | |
243 safe_browsing::SafeBrowsingService* sb_service = | |
244 g_browser_process->safe_browsing_service(); | |
245 if (sb_service) | |
246 db_manager_ = sb_service->database_manager(); | |
247 } | |
248 | |
249 // The client contacts Safe Browsing, and runs the callback with the result. | |
250 PermissionsBlacklistingClient::CheckSafeBrowsingBlacklist( | |
251 db_manager_, permission_type_, requesting_origin, web_contents, | |
252 safe_browsing_timeout_, | |
253 base::Bind(&PermissionContextBase::ContinueRequestPermission, | |
254 weak_factory_.GetWeakPtr(), web_contents, id, | |
255 requesting_origin, embedding_origin, user_gesture, | |
256 callback)); | |
257 } else { | |
258 // TODO(meredithl): Add UMA metrics here. | |
259 ContinueRequestPermission(web_contents, id, requesting_origin, | |
260 embedding_origin, user_gesture, callback, | |
261 false /* permission blocked */); | |
262 } | |
263 } | |
264 | |
265 void PermissionContextBase::ContinueRequestPermission( | |
266 content::WebContents* web_contents, | |
267 const PermissionRequestID& id, | |
268 const GURL& requesting_origin, | |
269 const GURL& embedding_origin, | |
270 bool user_gesture, | |
271 const BrowserPermissionCallback& callback, | |
272 bool permission_blocked) { | |
273 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
274 if (permission_blocked) { | |
275 // TODO(meredithl): Add UMA metrics here. | |
276 web_contents->GetMainFrame()->AddMessageToConsole( | |
277 content::CONSOLE_MESSAGE_LEVEL_LOG, | |
278 base::StringPrintf( | |
279 "%s permission has been auto-blocked.", | |
280 PermissionUtil::GetPermissionString(permission_type_).c_str())); | |
281 // Permission has been blacklisted, block the request. | |
282 // TODO(meredithl): Consider setting the content setting and persisting | |
283 // the decision to block. | |
284 callback.Run(CONTENT_SETTING_BLOCK); | |
285 return; | |
286 } | |
287 // Site is not blacklisted by Safe Browsing for the requested permission. | |
104 ContentSetting content_setting = | 288 ContentSetting content_setting = |
105 GetPermissionStatus(requesting_origin, embedding_origin); | 289 GetPermissionStatus(requesting_origin, embedding_origin); |
106 if (content_setting == CONTENT_SETTING_ALLOW) { | 290 if (content_setting == CONTENT_SETTING_ALLOW) { |
107 HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage( | 291 HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage( |
108 requesting_origin, embedding_origin, content_settings_type_); | 292 requesting_origin, embedding_origin, content_settings_type_); |
109 } | 293 } |
294 | |
110 if (content_setting == CONTENT_SETTING_ALLOW || | 295 if (content_setting == CONTENT_SETTING_ALLOW || |
111 content_setting == CONTENT_SETTING_BLOCK) { | 296 content_setting == CONTENT_SETTING_BLOCK) { |
112 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 297 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
113 false /* persist */, content_setting); | 298 false /* persist */, content_setting); |
114 return; | 299 return; |
115 } | 300 } |
116 | 301 |
117 PermissionUmaUtil::PermissionRequested(permission_type_, requesting_origin, | 302 PermissionUmaUtil::PermissionRequested(permission_type_, requesting_origin, |
118 embedding_origin, profile_); | 303 embedding_origin, profile_); |
119 | 304 |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 DCHECK(content_setting == CONTENT_SETTING_ALLOW || | 501 DCHECK(content_setting == CONTENT_SETTING_ALLOW || |
317 content_setting == CONTENT_SETTING_BLOCK); | 502 content_setting == CONTENT_SETTING_BLOCK); |
318 DCHECK(!requesting_origin.SchemeIsFile()); | 503 DCHECK(!requesting_origin.SchemeIsFile()); |
319 DCHECK(!embedding_origin.SchemeIsFile()); | 504 DCHECK(!embedding_origin.SchemeIsFile()); |
320 | 505 |
321 HostContentSettingsMapFactory::GetForProfile(profile_) | 506 HostContentSettingsMapFactory::GetForProfile(profile_) |
322 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, | 507 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, |
323 content_settings_type_, std::string(), | 508 content_settings_type_, std::string(), |
324 content_setting); | 509 content_setting); |
325 } | 510 } |
511 | |
512 void PermissionContextBase::SetSafeBrowsingDatabaseManagerAndTimeoutForTest( | |
513 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, | |
514 int timeout) { | |
515 db_manager_ = db_manager; | |
516 safe_browsing_timeout_ = timeout; | |
517 } | |
OLD | NEW |