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) { |
| 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 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 DCHECK(content_setting == CONTENT_SETTING_ALLOW || | 503 DCHECK(content_setting == CONTENT_SETTING_ALLOW || |
319 content_setting == CONTENT_SETTING_BLOCK); | 504 content_setting == CONTENT_SETTING_BLOCK); |
320 DCHECK(!requesting_origin.SchemeIsFile()); | 505 DCHECK(!requesting_origin.SchemeIsFile()); |
321 DCHECK(!embedding_origin.SchemeIsFile()); | 506 DCHECK(!embedding_origin.SchemeIsFile()); |
322 | 507 |
323 HostContentSettingsMapFactory::GetForProfile(profile_) | 508 HostContentSettingsMapFactory::GetForProfile(profile_) |
324 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, | 509 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, |
325 content_settings_type_, std::string(), | 510 content_settings_type_, std::string(), |
326 content_setting); | 511 content_setting); |
327 } | 512 } |
| 513 |
| 514 void PermissionContextBase::SetSafeBrowsingDatabaseManagerAndTimeoutForTest( |
| 515 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, |
| 516 int timeout) { |
| 517 db_manager_ = db_manager; |
| 518 safe_browsing_timeout_ = timeout; |
| 519 } |
OLD | NEW |