Index: chrome/browser/permissions/permission_context_base.cc |
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc |
index 5c99fbd3668796176b5a1b073fa2f16d013f9c3b..c056812497d3a652ce17b5559958bdfa1429912c 100644 |
--- a/chrome/browser/permissions/permission_context_base.cc |
+++ b/chrome/browser/permissions/permission_context_base.cc |
@@ -5,13 +5,19 @@ |
#include "chrome/browser/permissions/permission_context_base.h" |
#include <stddef.h> |
+ |
+#include <set> |
+#include <string> |
#include <utility> |
#include "base/callback.h" |
#include "base/logging.h" |
#include "base/memory/ptr_util.h" |
+#include "base/memory/weak_ptr.h" |
#include "base/strings/stringprintf.h" |
+#include "base/timer/timer.h" |
#include "build/build_config.h" |
+#include "chrome/browser/browser_process.h" |
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
#include "chrome/browser/permissions/permission_decision_auto_blocker.h" |
#include "chrome/browser/permissions/permission_request.h" |
@@ -21,14 +27,18 @@ |
#include "chrome/browser/permissions/permission_uma_util.h" |
#include "chrome/browser/permissions/permission_util.h" |
#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/safe_browsing/safe_browsing_service.h" |
+#include "chrome/common/chrome_features.h" |
#include "chrome/common/pref_names.h" |
#include "components/content_settings/core/browser/host_content_settings_map.h" |
#include "components/content_settings/core/browser/website_settings_registry.h" |
#include "components/prefs/pref_service.h" |
+#include "components/safe_browsing_db/database_manager.h" |
#include "components/variations/variations_associated_data.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/web_contents.h" |
+#include "content/public/browser/web_contents_observer.h" |
#include "content/public/common/origin_util.h" |
#include "url/gurl.h" |
@@ -42,6 +52,94 @@ const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = |
// static |
const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = |
"blocked"; |
+// Maximum time in milliseconds to wait for safe browsing service to check a |
+// url for blacklisting. After this amount of time, the check will be aborted |
+// and the url will be treated as not blacklisted. |
+const int kCheckUrlTimeoutMs = 1000; |
+ |
+// The client used when checking whether a permission has been blacklisted by |
+// Safe Browsing. The check is done asynchronously as no state can be stored in |
+// PermissionContextBase while it is in flight (since additional permission |
+// requests may be made). Hence, the client is heap allocated and is responsible |
+// for deleting itself when it is finished. Associated with a particular |
+// WebContents, so it can still delete itself when the WebContents is destroyed. |
+// A weak pointer factory is used to generate 'this' pointers for callbacks. |
+class PermissionsBlacklistSBClientImpl |
+ : public safe_browsing::SafeBrowsingDatabaseManager::Client, |
+ public content::WebContentsObserver { |
+ public: |
+ static void CheckSafeBrowsingBlacklist( |
+ content::PermissionType permission_type, |
+ const GURL& request_origin, |
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, |
+ content::WebContents* web_contents, |
+ base::Callback<void(bool)> callback) { |
+ new PermissionsBlacklistSBClientImpl(permission_type, request_origin, |
+ db_manager, web_contents, callback); |
+ } |
+ |
+ private: |
+ PermissionsBlacklistSBClientImpl( |
+ content::PermissionType permission_type, |
+ const GURL& request_origin, |
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, |
+ content::WebContents* web_contents, |
+ base::Callback<void(bool)> callback) |
+ : content::WebContentsObserver(web_contents), |
+ permission_type_(permission_type), |
+ callback_(callback), |
+ weak_ptr_factory_(this) { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&PermissionsBlacklistSBClientImpl::StartCheck, |
+ weak_ptr_factory_.GetWeakPtr(), db_manager, request_origin)); |
+ } |
+ |
+ ~PermissionsBlacklistSBClientImpl() override {} |
+ |
+ void StartCheck( |
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, |
+ const GURL& request_origin) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ // Start the timer to interrupt into the client callback method with an |
+ // empty response if Safe Browsing times out. |
+ safe_browsing::ThreatMetadata empty_metadata; |
+ timer_.Start( |
+ FROM_HERE, base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), |
+ base::Bind( |
+ &PermissionsBlacklistSBClientImpl::OnCheckApiBlacklistUrlResult, |
+ weak_ptr_factory_.GetWeakPtr(), request_origin, empty_metadata)); |
+ db_manager->CheckApiBlacklistUrl(request_origin, this); |
+ } |
+ |
+ // SafeBrowsingDatabaseManager::Client implementation. |
+ void OnCheckApiBlacklistUrlResult( |
+ const GURL& url, |
+ const safe_browsing::ThreatMetadata& metadata) override { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ weak_ptr_factory_.InvalidateWeakPtrs(); |
+ bool permission_blocked = |
+ metadata.api_permissions.find(PermissionUtil::GetPermissionString( |
+ permission_type_)) != metadata.api_permissions.end(); |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(callback_, permission_blocked)); |
+ // The result has been received, so the object can now delete itself. |
+ delete this; |
+ } |
+ |
+ // WebContentsObserver implementation. WebContents should outlive the |
+ // permission request, however if it doesn't, this will ensure the object |
+ // is still freed properly. |
+ void WebContentsDestroyed() override { delete this; } |
+ |
+ content::PermissionType permission_type_; |
+ base::Callback<void(bool)> callback_; |
+ // Timer to abort the Safe Browsing check if it takes too long. |
+ base::OneShotTimer timer_; |
+ // Note: Factory remains last member so it is destroyed and any weak |
+ // pointers invalidated before other members are destroyed. |
+ base::WeakPtrFactory<PermissionsBlacklistSBClientImpl> weak_ptr_factory_; |
dominickn
2016/12/15 03:52:45
Nit: DISALLOW_COPY_AND_ASSIGN here.
meredithl
2016/12/15 04:15:34
Done.
|
+}; |
PermissionContextBase::PermissionContextBase( |
Profile* profile, |
@@ -101,12 +199,57 @@ void PermissionContextBase::RequestPermission( |
return; |
} |
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager = |
+ GetSafeBrowsingDatabaseManager(); |
+ if (base::FeatureList::IsEnabled(features::kPermissionsBlacklist) && |
+ database_manager) { |
+ // The client will contact Safe Browsing, and invoke the callback with the |
+ // result. This object will be freed once Safe Browsing has returned the |
+ // results or timed out. |
+ PermissionsBlacklistSBClientImpl::CheckSafeBrowsingBlacklist( |
+ permission_type_, requesting_origin, database_manager, web_contents, |
+ base::Bind(&PermissionContextBase::CheckPermissionsBlacklistResult, |
+ base::Unretained(this), web_contents, id, requesting_origin, |
+ embedding_origin, user_gesture, callback)); |
+ } else { |
+ // TODO(meredithl) : add UMA metrics here. |
+ CheckPermissionsBlacklistResult(web_contents, id, requesting_origin, |
+ embedding_origin, user_gesture, callback, |
+ false); |
+ } |
+} |
+ |
+void PermissionContextBase::CheckPermissionsBlacklistResult( |
+ content::WebContents* web_contents, |
+ const PermissionRequestID& id, |
+ const GURL& requesting_origin, |
+ const GURL& embedding_origin, |
+ bool user_gesture, |
+ const BrowserPermissionCallback& callback, |
+ bool permission_blocked) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ if (permission_blocked) { |
+ // TODO(meredithl) : add UMA metrics here. |
+ web_contents->GetMainFrame()->AddMessageToConsole( |
+ content::CONSOLE_MESSAGE_LEVEL_LOG, |
+ base::StringPrintf( |
+ "%s permission has been auto-blocked.", |
+ PermissionUtil::GetPermissionString(permission_type_).c_str())); |
+ // Permission has been blacklisted, block the request. |
+ // TODO(meredithl) : consider setting the content setting and persisting |
+ // the decision to block. |
+ callback.Run(CONTENT_SETTING_BLOCK); |
+ return; |
+ } |
+ |
+ // Site is not blacklisted by Safe Browsing for the requested permission. |
ContentSetting content_setting = |
GetPermissionStatus(requesting_origin, embedding_origin); |
if (content_setting == CONTENT_SETTING_ALLOW) { |
HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage( |
requesting_origin, embedding_origin, content_settings_type_); |
} |
+ |
if (content_setting == CONTENT_SETTING_ALLOW || |
content_setting == CONTENT_SETTING_BLOCK) { |
NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
@@ -124,7 +267,6 @@ void PermissionContextBase::RequestPermission( |
ContentSetting PermissionContextBase::GetPermissionStatus( |
const GURL& requesting_origin, |
const GURL& embedding_origin) const { |
- |
// If the permission has been disabled through Finch, block all requests. |
if (IsPermissionKillSwitchOn()) |
return CONTENT_SETTING_BLOCK; |
@@ -139,9 +281,8 @@ ContentSetting PermissionContextBase::GetPermissionStatus( |
content_settings_type_, std::string()); |
} |
-void PermissionContextBase::ResetPermission( |
- const GURL& requesting_origin, |
- const GURL& embedding_origin) { |
+void PermissionContextBase::ResetPermission(const GURL& requesting_origin, |
+ const GURL& embedding_origin) { |
HostContentSettingsMapFactory::GetForProfile(profile_) |
->SetContentSettingDefaultScope(requesting_origin, embedding_origin, |
content_settings_type_, std::string(), |
@@ -181,7 +322,8 @@ void PermissionContextBase::DecidePermission( |
if (PermissionRequestManager::IsEnabled()) { |
PermissionRequestManager* permission_request_manager = |
PermissionRequestManager::FromWebContents(web_contents); |
- // TODO(felt): sometimes |permission_request_manager| is null. This check is |
+ // TODO(felt): sometimes |permission_request_manager| is null. This check |
+ // is |
dominickn
2016/12/15 03:52:45
Nit: fix formatting here.
meredithl
2016/12/15 04:15:34
Done.
|
// meant to prevent crashes. See crbug.com/457091. |
if (!permission_request_manager) |
return; |
@@ -318,3 +460,10 @@ bool PermissionContextBase::IsPermissionKillSwitchOn() const { |
return param == kPermissionsKillSwitchBlockedValue; |
} |
+ |
+scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> |
+PermissionContextBase::GetSafeBrowsingDatabaseManager() { |
+ safe_browsing::SafeBrowsingService* sb_service = |
+ g_browser_process->safe_browsing_service(); |
+ return sb_service ? sb_service->database_manager() : nullptr; |
+} |