Chromium Code Reviews| 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 const int kCheckUrlTimeoutMs = 1000; | |
|
kcarattini
2016/12/20 19:57:10
I'm concerned that this is too short. How about we
meredithl
2016/12/29 06:23:35
Done.
| |
| 58 | |
| 59 // The client used when checking whether a permission has been blacklisted by | |
| 60 // Safe Browsing. The check is done asynchronously as no state can be stored in | |
| 61 // PermissionContextBase (since additional permission requests may be made). | |
| 62 // This class must be created and destroyed on the UI thread. | |
| 63 class PermissionsBlacklistingClient | |
|
raymes
2016/12/20 23:58:57
This is a fairly substantial class now. I think it
meredithl
2016/12/29 06:23:35
Yep, that's in the works, which I'll be detailing
| |
| 64 : public safe_browsing::SafeBrowsingDatabaseManager::Client, | |
| 65 public base::RefCountedThreadSafe<PermissionsBlacklistingClient>, | |
| 66 public content::WebContentsObserver { | |
| 67 public: | |
| 68 static void CheckSafeBrowsingBlacklist( | |
| 69 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, | |
| 70 content::PermissionType permission_type, | |
| 71 const GURL& request_origin, | |
| 72 content::WebContents* web_contents, | |
| 73 int timeout, | |
|
raymes
2016/12/20 23:58:57
Could we just make this a member variable of the c
meredithl
2016/12/29 06:23:35
Done.
raymes
2017/01/09 06:28:17
Can we remove this as an argument from this functi
meredithl
2017/01/10 02:24:57
It gets passed from here into the constructor to b
raymes
2017/01/10 02:57:15
Oh sorry, you're right, we need it here :)
meredithl
2017/01/10 03:40:46
Acknowledged.
| |
| 74 base::Callback<void(bool)> callback) { | |
| 75 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 76 | |
| 77 new PermissionsBlacklistingClient(db_manager, permission_type, | |
| 78 request_origin, web_contents, timeout, | |
| 79 callback); | |
| 80 } | |
| 81 | |
| 82 private: | |
| 83 friend class base::RefCountedThreadSafe<PermissionsBlacklistingClient>; | |
| 84 ~PermissionsBlacklistingClient() override {} | |
|
raymes
2016/12/20 23:58:57
nit: constructor before destructor usually
meredithl
2016/12/29 06:23:35
Done.
| |
| 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 // Balanced by a call to Release() in OnCheckApiBlacklistUrlResult(). | |
| 98 AddRef(); | |
| 99 content::BrowserThread::PostTask( | |
| 100 content::BrowserThread::IO, FROM_HERE, | |
| 101 base::Bind(&PermissionsBlacklistingClient::StartCheck, this, | |
| 102 request_origin, timeout)); | |
| 103 } | |
| 104 | |
| 105 void StartCheck(const GURL& request_origin, int timeout) { | |
|
raymes
2017/01/09 06:28:17
nit: Can we remove timeout here and just use timeo
meredithl
2017/01/10 02:24:57
Done.
| |
| 106 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 107 | |
| 108 // Start the timer to interrupt into the client callback method with an | |
| 109 // empty response if Safe Browsing times out. | |
| 110 safe_browsing::ThreatMetadata empty_metadata; | |
| 111 timer_ = base::MakeUnique<base::OneShotTimer>(); | |
| 112 timer_->Start( | |
| 113 FROM_HERE, base::TimeDelta::FromMilliseconds(timeout), | |
| 114 base::Bind(&PermissionsBlacklistingClient::OnCheckApiBlacklistUrlResult, | |
| 115 this, request_origin, empty_metadata)); | |
| 116 db_manager_->CheckApiBlacklistUrl(request_origin, this); | |
| 117 } | |
| 118 | |
| 119 // SafeBrowsingDatabaseManager::Client implementation. | |
| 120 // TODO(meredithl) : fix this for post task | |
|
raymes
2016/12/20 23:58:57
I'm not sure what this comment means?
meredithl
2016/12/29 06:23:35
Sorry. Was an old comment for me to look at, forgo
| |
| 121 void OnCheckApiBlacklistUrlResult( | |
| 122 const GURL& url, | |
| 123 const safe_browsing::ThreatMetadata& metadata) override { | |
| 124 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 125 | |
| 126 if (timer_->IsRunning()) | |
| 127 timer_->Stop(); | |
| 128 else | |
| 129 db_manager_->CancelApiCheck(this); | |
| 130 timer_.reset(nullptr); | |
| 131 | |
| 132 // TODO(meredithl) : Implement correct permission string check. | |
|
raymes
2016/12/20 23:58:57
Hmm I'm not sure what this one means either?
meredithl
2016/12/29 06:23:35
Safe Browsing stringify the PermissionType enum, w
| |
| 133 bool permission_blocked = | |
| 134 metadata.api_permissions.find(PermissionUtil::GetPermissionString( | |
| 135 permission_type_)) != metadata.api_permissions.end(); | |
| 136 | |
| 137 content::BrowserThread::PostTask( | |
| 138 content::BrowserThread::UI, FROM_HERE, | |
| 139 base::Bind( | |
| 140 &PermissionsBlacklistingClient::EvaluateBlacklistResultOnUiThread, | |
| 141 this, permission_blocked)); | |
| 142 } | |
| 143 | |
| 144 void EvaluateBlacklistResultOnUiThread(bool permission_blocked) { | |
| 145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 146 | |
| 147 if (is_active_) | |
|
raymes
2016/12/20 23:58:57
It doesn't look like is_active_ is initialized any
meredithl
2016/12/29 06:23:35
Done.
| |
| 148 callback_.Run(permission_blocked); | |
| 149 Release(); | |
| 150 } | |
| 151 | |
| 152 // WebContentsObserver implementation. Sets the flag so that when the database | |
| 153 // manager returns with a result, it won't attempt to run the callback with a | |
| 154 // deleted WebContents. | |
| 155 void WebContentsDestroyed() override { | |
| 156 is_active_ = false; | |
| 157 Observe(nullptr); | |
|
raymes
2016/12/20 23:58:57
Why is this needed? Is it just so we don't acciden
meredithl
2016/12/29 06:23:35
I believe so. Dominick suggested to put it in, and
| |
| 158 } | |
| 159 | |
| 160 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager_; | |
| 161 content::PermissionType permission_type_; | |
| 162 | |
| 163 // PermissionContextBase callback to run on the UI thread. | |
| 164 base::Callback<void(bool)> callback_; | |
| 165 | |
| 166 // Timer to abort the Safe Browsing check if it takes too long. Created and | |
| 167 // used on the IO Thread. | |
| 168 std::unique_ptr<base::OneShotTimer> timer_; | |
| 169 | |
| 170 // True if |callback_| should be invoked. For instance, if web_contents() is | |
|
raymes
2016/12/20 23:58:57
nit: Since the only reason why this would be false
meredithl
2016/12/29 06:23:35
Done.
| |
| 171 // destroyed, this is set to false. | |
| 172 bool is_active_; | |
| 173 | |
| 174 DISALLOW_COPY_AND_ASSIGN(PermissionsBlacklistingClient); | |
| 175 }; | |
| 45 | 176 |
| 46 PermissionContextBase::PermissionContextBase( | 177 PermissionContextBase::PermissionContextBase( |
| 47 Profile* profile, | 178 Profile* profile, |
| 48 const content::PermissionType permission_type, | 179 const content::PermissionType permission_type, |
| 49 const ContentSettingsType content_settings_type) | 180 const ContentSettingsType content_settings_type) |
| 50 : profile_(profile), | 181 : profile_(profile), |
| 51 permission_type_(permission_type), | 182 permission_type_(permission_type), |
| 52 content_settings_type_(content_settings_type), | 183 content_settings_type_(content_settings_type), |
| 184 safe_browsing_timeout_(kCheckUrlTimeoutMs), | |
| 53 weak_factory_(this) { | 185 weak_factory_(this) { |
| 54 #if defined(OS_ANDROID) | 186 #if defined(OS_ANDROID) |
| 55 permission_queue_controller_.reset(new PermissionQueueController( | 187 permission_queue_controller_.reset(new PermissionQueueController( |
| 56 profile_, permission_type_, content_settings_type_)); | 188 profile_, permission_type_, content_settings_type_)); |
| 57 #endif | 189 #endif |
| 58 PermissionDecisionAutoBlocker::UpdateFromVariations(); | 190 PermissionDecisionAutoBlocker::UpdateFromVariations(); |
| 59 } | 191 } |
| 60 | 192 |
| 61 PermissionContextBase::~PermissionContextBase() { | 193 PermissionContextBase::~PermissionContextBase() { |
| 62 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 | 226 |
| 95 DVLOG(1) << "Attempt to use " << type_name | 227 DVLOG(1) << "Attempt to use " << type_name |
| 96 << " from an invalid URL: " << requesting_origin << "," | 228 << " from an invalid URL: " << requesting_origin << "," |
| 97 << embedding_origin << " (" << type_name | 229 << embedding_origin << " (" << type_name |
| 98 << " is not supported in popups)"; | 230 << " is not supported in popups)"; |
| 99 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 231 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
| 100 false /* persist */, CONTENT_SETTING_BLOCK); | 232 false /* persist */, CONTENT_SETTING_BLOCK); |
| 101 return; | 233 return; |
| 102 } | 234 } |
| 103 | 235 |
| 236 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager = | |
| 237 db_manager_; | |
| 238 if (!db_manager) { | |
| 239 safe_browsing::SafeBrowsingService* sb_service = | |
| 240 g_browser_process->safe_browsing_service(); | |
| 241 if (sb_service) | |
| 242 db_manager = sb_service->database_manager(); | |
|
raymes
2016/12/20 23:58:57
Hmm, we never set the instance variable here. I th
meredithl
2016/12/29 06:23:35
Done.
| |
| 243 } | |
|
kcarattini
2016/12/20 19:57:10
Do you need these 8 lines here or can you move the
raymes
2016/12/20 23:58:57
Good thought.
meredithl
2016/12/29 06:23:35
Ooh yep. Good catch. Done.
| |
| 244 | |
| 245 if (base::FeatureList::IsEnabled(features::kPermissionsBlacklist) && | |
| 246 db_manager) { | |
| 247 // The client contacts Safe Browsing, and runs the callback with the result. | |
| 248 PermissionsBlacklistingClient::CheckSafeBrowsingBlacklist( | |
| 249 db_manager, permission_type_, requesting_origin, web_contents, | |
| 250 safe_browsing_timeout_, | |
| 251 base::Bind(&PermissionContextBase::ContinueRequestPermission, | |
| 252 weak_factory_.GetWeakPtr(), web_contents, id, | |
| 253 requesting_origin, embedding_origin, user_gesture, | |
| 254 callback)); | |
| 255 } else { | |
| 256 // TODO(meredithl) : add UMA metrics here. | |
|
raymes
2016/12/20 23:58:57
nit: here and elsewhere, no space before : in TODO
meredithl
2016/12/29 06:23:35
Done.
| |
| 257 ContinueRequestPermission(web_contents, id, requesting_origin, | |
| 258 embedding_origin, user_gesture, callback, | |
| 259 false /* permission blocked */); | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 void PermissionContextBase::ContinueRequestPermission( | |
| 264 content::WebContents* web_contents, | |
| 265 const PermissionRequestID& id, | |
| 266 const GURL& requesting_origin, | |
| 267 const GURL& embedding_origin, | |
| 268 bool user_gesture, | |
| 269 const BrowserPermissionCallback& callback, | |
| 270 bool permission_blocked) { | |
| 271 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 272 if (permission_blocked) { | |
| 273 // TODO(meredithl) : add UMA metrics here. | |
| 274 web_contents->GetMainFrame()->AddMessageToConsole( | |
| 275 content::CONSOLE_MESSAGE_LEVEL_LOG, | |
| 276 base::StringPrintf( | |
| 277 "%s permission has been auto-blocked.", | |
| 278 PermissionUtil::GetPermissionString(permission_type_).c_str())); | |
| 279 // Permission has been blacklisted, block the request. | |
| 280 // TODO(meredithl) : consider setting the content setting and persisting | |
| 281 // the decision to block. | |
| 282 callback.Run(CONTENT_SETTING_BLOCK); | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 // Site is not blacklisted by Safe Browsing for the requested permission. | |
| 104 ContentSetting content_setting = | 287 ContentSetting content_setting = |
| 105 GetPermissionStatus(requesting_origin, embedding_origin); | 288 GetPermissionStatus(requesting_origin, embedding_origin); |
| 106 if (content_setting == CONTENT_SETTING_ALLOW) { | 289 if (content_setting == CONTENT_SETTING_ALLOW) { |
| 107 HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage( | 290 HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage( |
| 108 requesting_origin, embedding_origin, content_settings_type_); | 291 requesting_origin, embedding_origin, content_settings_type_); |
| 109 } | 292 } |
| 293 | |
| 110 if (content_setting == CONTENT_SETTING_ALLOW || | 294 if (content_setting == CONTENT_SETTING_ALLOW || |
| 111 content_setting == CONTENT_SETTING_BLOCK) { | 295 content_setting == CONTENT_SETTING_BLOCK) { |
| 112 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 296 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
| 113 false /* persist */, content_setting); | 297 false /* persist */, content_setting); |
| 114 return; | 298 return; |
| 115 } | 299 } |
| 116 | 300 |
| 117 PermissionUmaUtil::PermissionRequested(permission_type_, requesting_origin, | 301 PermissionUmaUtil::PermissionRequested(permission_type_, requesting_origin, |
| 118 embedding_origin, profile_); | 302 embedding_origin, profile_); |
| 119 | 303 |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 316 DCHECK(content_setting == CONTENT_SETTING_ALLOW || | 500 DCHECK(content_setting == CONTENT_SETTING_ALLOW || |
| 317 content_setting == CONTENT_SETTING_BLOCK); | 501 content_setting == CONTENT_SETTING_BLOCK); |
| 318 DCHECK(!requesting_origin.SchemeIsFile()); | 502 DCHECK(!requesting_origin.SchemeIsFile()); |
| 319 DCHECK(!embedding_origin.SchemeIsFile()); | 503 DCHECK(!embedding_origin.SchemeIsFile()); |
| 320 | 504 |
| 321 HostContentSettingsMapFactory::GetForProfile(profile_) | 505 HostContentSettingsMapFactory::GetForProfile(profile_) |
| 322 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, | 506 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, |
| 323 content_settings_type_, std::string(), | 507 content_settings_type_, std::string(), |
| 324 content_setting); | 508 content_setting); |
| 325 } | 509 } |
| 510 | |
| 511 void PermissionContextBase::SetSafeBrowsingDatabaseManagerForTests( | |
| 512 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager) { | |
| 513 db_manager_ = db_manager; | |
| 514 } | |
| 515 | |
| 516 void PermissionContextBase::SetTimeoutForSafeBrowsingClient(int timeout) { | |
| 517 safe_browsing_timeout_ = timeout; | |
| 518 } | |
| OLD | NEW |