| 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 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
| 17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 18 #include "chrome/browser/browser_process.h" | 18 #include "chrome/browser/browser_process.h" |
| 19 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 19 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 20 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" | 20 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" |
| 21 #include "chrome/browser/permissions/permission_request.h" | 21 #include "chrome/browser/permissions/permission_request.h" |
| 22 #include "chrome/browser/permissions/permission_request_id.h" | 22 #include "chrome/browser/permissions/permission_request_id.h" |
| 23 #include "chrome/browser/permissions/permission_request_impl.h" | 23 #include "chrome/browser/permissions/permission_request_impl.h" |
| 24 #include "chrome/browser/permissions/permission_request_manager.h" | 24 #include "chrome/browser/permissions/permission_request_manager.h" |
| 25 #include "chrome/browser/permissions/permission_uma_util.h" | 25 #include "chrome/browser/permissions/permission_uma_util.h" |
| 26 #include "chrome/browser/permissions/permission_util.h" | |
| 27 #include "chrome/browser/profiles/profile.h" | 26 #include "chrome/browser/profiles/profile.h" |
| 28 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 27 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| 29 #include "chrome/common/chrome_features.h" | 28 #include "chrome/common/chrome_features.h" |
| 30 #include "chrome/common/pref_names.h" | 29 #include "chrome/common/pref_names.h" |
| 31 #include "components/content_settings/core/browser/host_content_settings_map.h" | 30 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 32 #include "components/prefs/pref_service.h" | 31 #include "components/prefs/pref_service.h" |
| 33 #include "components/safe_browsing_db/database_manager.h" | 32 #include "components/safe_browsing_db/database_manager.h" |
| 34 #include "components/variations/variations_associated_data.h" | 33 #include "components/variations/variations_associated_data.h" |
| 35 #include "content/public/browser/browser_thread.h" | 34 #include "content/public/browser/browser_thread.h" |
| 36 #include "content/public/browser/render_frame_host.h" | 35 #include "content/public/browser/render_frame_host.h" |
| 37 #include "content/public/browser/web_contents.h" | 36 #include "content/public/browser/web_contents.h" |
| 38 #include "content/public/common/origin_util.h" | 37 #include "content/public/common/origin_util.h" |
| 39 #include "url/gurl.h" | 38 #include "url/gurl.h" |
| 40 | 39 |
| 41 #if defined(OS_ANDROID) | 40 #if defined(OS_ANDROID) |
| 42 #include "chrome/browser/permissions/permission_queue_controller.h" | 41 #include "chrome/browser/permissions/permission_queue_controller.h" |
| 43 #endif | 42 #endif |
| 44 | 43 |
| 45 // static | 44 // static |
| 46 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = | 45 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = |
| 47 "PermissionsKillSwitch"; | 46 "PermissionsKillSwitch"; |
| 48 // static | 47 // static |
| 49 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = | 48 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = |
| 50 "blocked"; | 49 "blocked"; |
| 51 | 50 |
| 52 PermissionResult::PermissionResult(ContentSetting cs, | |
| 53 PermissionStatusSource pss) | |
| 54 : content_setting(cs), source(pss) {} | |
| 55 | |
| 56 PermissionResult::~PermissionResult() {} | |
| 57 | |
| 58 PermissionContextBase::PermissionContextBase( | 51 PermissionContextBase::PermissionContextBase( |
| 59 Profile* profile, | 52 Profile* profile, |
| 60 const ContentSettingsType content_settings_type) | 53 const ContentSettingsType content_settings_type) |
| 61 : profile_(profile), | 54 : profile_(profile), |
| 62 content_settings_type_(content_settings_type), | 55 content_settings_type_(content_settings_type), |
| 63 weak_factory_(this) { | 56 weak_factory_(this) { |
| 64 #if defined(OS_ANDROID) | 57 #if defined(OS_ANDROID) |
| 65 permission_queue_controller_.reset( | 58 permission_queue_controller_.reset( |
| 66 new PermissionQueueController(profile_, content_settings_type_)); | 59 new PermissionQueueController(profile_, content_settings_type_)); |
| 67 #endif | 60 #endif |
| 68 PermissionDecisionAutoBlocker::UpdateFromVariations(); | 61 PermissionDecisionAutoBlocker::UpdateFromVariations(); |
| 69 } | 62 } |
| 70 | 63 |
| 71 PermissionContextBase::~PermissionContextBase() { | 64 PermissionContextBase::~PermissionContextBase() { |
| 72 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 65 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 73 } | 66 } |
| 74 | 67 |
| 75 void PermissionContextBase::RequestPermission( | 68 void PermissionContextBase::RequestPermission( |
| 76 content::WebContents* web_contents, | 69 content::WebContents* web_contents, |
| 77 const PermissionRequestID& id, | 70 const PermissionRequestID& id, |
| 78 const GURL& requesting_frame, | 71 const GURL& requesting_frame, |
| 79 bool user_gesture, | 72 bool user_gesture, |
| 80 const BrowserPermissionCallback& callback) { | 73 const BrowserPermissionCallback& callback) { |
| 81 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 74 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 82 | 75 |
| 83 // First check if this permission has been disabled. | |
| 84 if (IsPermissionKillSwitchOn()) { | |
| 85 // Log to the developer console. | |
| 86 web_contents->GetMainFrame()->AddMessageToConsole( | |
| 87 content::CONSOLE_MESSAGE_LEVEL_INFO, | |
| 88 base::StringPrintf( | |
| 89 "%s permission has been blocked.", | |
| 90 PermissionUtil::GetPermissionString(content_settings_type_) | |
| 91 .c_str())); | |
| 92 // The kill switch is enabled for this permission; Block all requests. | |
| 93 callback.Run(CONTENT_SETTING_BLOCK); | |
| 94 return; | |
| 95 } | |
| 96 | |
| 97 GURL requesting_origin = requesting_frame.GetOrigin(); | 76 GURL requesting_origin = requesting_frame.GetOrigin(); |
| 98 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); | 77 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); |
| 99 | 78 |
| 100 if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) { | 79 if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) { |
| 101 std::string type_name = | 80 std::string type_name = |
| 102 PermissionUtil::GetPermissionString(content_settings_type_); | 81 PermissionUtil::GetPermissionString(content_settings_type_); |
| 103 | 82 |
| 104 DVLOG(1) << "Attempt to use " << type_name | 83 DVLOG(1) << "Attempt to use " << type_name |
| 105 << " from an invalid URL: " << requesting_origin << "," | 84 << " from an invalid URL: " << requesting_origin << "," |
| 106 << embedding_origin << " (" << type_name | 85 << embedding_origin << " (" << type_name |
| 107 << " is not supported in popups)"; | 86 << " is not supported in popups)"; |
| 108 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 87 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
| 109 false /* persist */, CONTENT_SETTING_BLOCK); | 88 false /* persist */, CONTENT_SETTING_BLOCK); |
| 110 return; | 89 return; |
| 111 } | 90 } |
| 112 | 91 |
| 113 // Synchronously check the content setting to see if the user has already made | 92 // Synchronously check the content setting to see if the user has already made |
| 114 // a decision, or if the origin is under embargo. If so, respect that | 93 // a decision, or if the origin is under embargo. If so, respect that |
| 115 // decision. | 94 // decision. |
| 116 PermissionResult result = | 95 PermissionResult result = |
| 117 GetPermissionStatus(requesting_origin, embedding_origin); | 96 GetPermissionStatus(requesting_origin, embedding_origin); |
| 118 | 97 |
| 119 if (result.content_setting == CONTENT_SETTING_ALLOW || | 98 if (result.content_setting == CONTENT_SETTING_ALLOW || |
| 120 result.content_setting == CONTENT_SETTING_BLOCK) { | 99 result.content_setting == CONTENT_SETTING_BLOCK) { |
| 100 if (result.source == PermissionStatusSource::KILL_SWITCH) { |
| 101 // Block the request and log to the developer console. |
| 102 web_contents->GetMainFrame()->AddMessageToConsole( |
| 103 content::CONSOLE_MESSAGE_LEVEL_INFO, |
| 104 base::StringPrintf( |
| 105 "%s permission has been blocked.", |
| 106 PermissionUtil::GetPermissionString(content_settings_type_) |
| 107 .c_str())); |
| 108 callback.Run(CONTENT_SETTING_BLOCK); |
| 109 return; |
| 110 } |
| 111 |
| 112 // If we are under embargo, record the embargo reason for which we have |
| 113 // suppressed the prompt. |
| 114 PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(result.source); |
| 121 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 115 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
| 122 false /* persist */, result.content_setting); | 116 false /* persist */, result.content_setting); |
| 123 return; | 117 return; |
| 124 } | 118 } |
| 125 | 119 |
| 126 // Asynchronously check whether the origin should be blocked from making this | 120 // Asynchronously check whether the origin should be blocked from making this |
| 127 // permission request. It may be on the Safe Browsing API blacklist, or it may | 121 // permission request, e.g. it may be on the Safe Browsing API blacklist. |
| 128 // have been dismissed too many times in a row. If the origin is allowed to | |
| 129 // request, that request will be made to ContinueRequestPermission(). | |
| 130 PermissionDecisionAutoBlocker::GetForProfile(profile_)->UpdateEmbargoedStatus( | 122 PermissionDecisionAutoBlocker::GetForProfile(profile_)->UpdateEmbargoedStatus( |
| 131 content_settings_type_, requesting_origin, web_contents, | 123 content_settings_type_, requesting_origin, web_contents, |
| 132 base::Bind(&PermissionContextBase::ContinueRequestPermission, | 124 base::Bind(&PermissionContextBase::ContinueRequestPermission, |
| 133 weak_factory_.GetWeakPtr(), web_contents, id, | 125 weak_factory_.GetWeakPtr(), web_contents, id, |
| 134 requesting_origin, embedding_origin, user_gesture, callback)); | 126 requesting_origin, embedding_origin, user_gesture, callback)); |
| 135 } | 127 } |
| 136 | 128 |
| 137 void PermissionContextBase::ContinueRequestPermission( | 129 void PermissionContextBase::ContinueRequestPermission( |
| 138 content::WebContents* web_contents, | 130 content::WebContents* web_contents, |
| 139 const PermissionRequestID& id, | 131 const PermissionRequestID& id, |
| 140 const GURL& requesting_origin, | 132 const GURL& requesting_origin, |
| 141 const GURL& embedding_origin, | 133 const GURL& embedding_origin, |
| 142 bool user_gesture, | 134 bool user_gesture, |
| 143 const BrowserPermissionCallback& callback, | 135 const BrowserPermissionCallback& callback, |
| 144 bool permission_blocked) { | 136 bool permission_blocked) { |
| 145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 137 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 146 if (permission_blocked) { | 138 if (permission_blocked) { |
| 147 web_contents->GetMainFrame()->AddMessageToConsole( | 139 web_contents->GetMainFrame()->AddMessageToConsole( |
| 148 content::CONSOLE_MESSAGE_LEVEL_INFO, | 140 content::CONSOLE_MESSAGE_LEVEL_INFO, |
| 149 base::StringPrintf( | 141 base::StringPrintf( |
| 150 "%s permission has been auto-blocked.", | 142 "%s permission has been auto-blocked.", |
| 151 PermissionUtil::GetPermissionString(content_settings_type_) | 143 PermissionUtil::GetPermissionString(content_settings_type_) |
| 152 .c_str())); | 144 .c_str())); |
| 153 // Permission has been automatically blocked. | 145 // Permission has been automatically blocked. Record that the prompt was |
| 154 PermissionUmaUtil::RecordPermissionEmbargoStatus( | 146 // suppressed and that we hit the blacklist. |
| 147 PermissionUmaUtil::RecordEmbargoPromptSuppression( |
| 148 PermissionEmbargoStatus::PERMISSIONS_BLACKLISTING); |
| 149 PermissionUmaUtil::RecordEmbargoStatus( |
| 155 PermissionEmbargoStatus::PERMISSIONS_BLACKLISTING); | 150 PermissionEmbargoStatus::PERMISSIONS_BLACKLISTING); |
| 156 callback.Run(CONTENT_SETTING_BLOCK); | 151 callback.Run(CONTENT_SETTING_BLOCK); |
| 157 return; | 152 return; |
| 158 } | 153 } |
| 159 | 154 |
| 155 // We are going to show a prompt now. |
| 160 PermissionUmaUtil::PermissionRequested( | 156 PermissionUmaUtil::PermissionRequested( |
| 161 content_settings_type_, requesting_origin, embedding_origin, profile_); | 157 content_settings_type_, requesting_origin, embedding_origin, profile_); |
| 158 PermissionUmaUtil::RecordEmbargoPromptSuppression( |
| 159 PermissionEmbargoStatus::NOT_EMBARGOED); |
| 162 | 160 |
| 163 DecidePermission(web_contents, id, requesting_origin, embedding_origin, | 161 DecidePermission(web_contents, id, requesting_origin, embedding_origin, |
| 164 user_gesture, callback); | 162 user_gesture, callback); |
| 165 } | 163 } |
| 166 | 164 |
| 167 PermissionResult PermissionContextBase::GetPermissionStatus( | 165 PermissionResult PermissionContextBase::GetPermissionStatus( |
| 168 const GURL& requesting_origin, | 166 const GURL& requesting_origin, |
| 169 const GURL& embedding_origin) const { | 167 const GURL& embedding_origin) const { |
| 170 // TODO(raymes): Ensure we return appropriate decision reasons in the | |
| 171 // PermissionResult. We should add these as each is needed. | |
| 172 | |
| 173 // If the permission has been disabled through Finch, block all requests. | 168 // If the permission has been disabled through Finch, block all requests. |
| 174 if (IsPermissionKillSwitchOn()) { | 169 if (IsPermissionKillSwitchOn()) { |
| 175 return PermissionResult(CONTENT_SETTING_BLOCK, | 170 return PermissionResult(CONTENT_SETTING_BLOCK, |
| 176 PermissionStatusSource::UNSPECIFIED); | 171 PermissionStatusSource::KILL_SWITCH); |
| 177 } | 172 } |
| 178 | 173 |
| 179 if (IsRestrictedToSecureOrigins() && | 174 if (IsRestrictedToSecureOrigins() && |
| 180 !content::IsOriginSecure(requesting_origin)) { | 175 !content::IsOriginSecure(requesting_origin)) { |
| 181 return PermissionResult(CONTENT_SETTING_BLOCK, | 176 return PermissionResult(CONTENT_SETTING_BLOCK, |
| 182 PermissionStatusSource::UNSPECIFIED); | 177 PermissionStatusSource::UNSPECIFIED); |
| 183 } | 178 } |
| 184 | 179 |
| 185 ContentSetting content_setting = | 180 ContentSetting content_setting = |
| 186 GetPermissionStatusInternal(requesting_origin, embedding_origin); | 181 GetPermissionStatusInternal(requesting_origin, embedding_origin); |
| 187 if (content_setting == CONTENT_SETTING_ASK && | 182 if (content_setting == CONTENT_SETTING_ASK) { |
| 188 PermissionDecisionAutoBlocker::GetForProfile(profile_)->IsUnderEmbargo( | 183 PermissionResult result = |
| 189 content_settings_type_, requesting_origin)) { | 184 PermissionDecisionAutoBlocker::GetForProfile(profile_) |
| 190 return PermissionResult(CONTENT_SETTING_BLOCK, | 185 ->GetEmbargoResult(content_settings_type_, requesting_origin); |
| 191 PermissionStatusSource::UNSPECIFIED); | 186 DCHECK(result.content_setting == CONTENT_SETTING_ASK || |
| 187 result.content_setting == CONTENT_SETTING_BLOCK); |
| 188 return result; |
| 192 } | 189 } |
| 193 | 190 |
| 194 return PermissionResult(content_setting, PermissionStatusSource::UNSPECIFIED); | 191 return PermissionResult(content_setting, PermissionStatusSource::UNSPECIFIED); |
| 195 } | 192 } |
| 196 | 193 |
| 197 void PermissionContextBase::ResetPermission( | 194 void PermissionContextBase::ResetPermission(const GURL& requesting_origin, |
| 198 const GURL& requesting_origin, | 195 const GURL& embedding_origin) { |
| 199 const GURL& embedding_origin) { | |
| 200 HostContentSettingsMapFactory::GetForProfile(profile_) | 196 HostContentSettingsMapFactory::GetForProfile(profile_) |
| 201 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, | 197 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, |
| 202 content_settings_storage_type(), | 198 content_settings_storage_type(), |
| 203 std::string(), CONTENT_SETTING_DEFAULT); | 199 std::string(), CONTENT_SETTING_DEFAULT); |
| 204 } | 200 } |
| 205 | 201 |
| 206 void PermissionContextBase::CancelPermissionRequest( | 202 void PermissionContextBase::CancelPermissionRequest( |
| 207 content::WebContents* web_contents, | 203 content::WebContents* web_contents, |
| 208 const PermissionRequestID& id) { | 204 const PermissionRequestID& id) { |
| 209 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 205 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 } else { | 313 } else { |
| 318 PermissionUmaUtil::PermissionDismissed( | 314 PermissionUmaUtil::PermissionDismissed( |
| 319 content_settings_type_, gesture_type, requesting_origin, profile_); | 315 content_settings_type_, gesture_type, requesting_origin, profile_); |
| 320 | 316 |
| 321 if (PermissionDecisionAutoBlocker::GetForProfile(profile_) | 317 if (PermissionDecisionAutoBlocker::GetForProfile(profile_) |
| 322 ->RecordDismissAndEmbargo(requesting_origin, | 318 ->RecordDismissAndEmbargo(requesting_origin, |
| 323 content_settings_type_)) { | 319 content_settings_type_)) { |
| 324 embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS; | 320 embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS; |
| 325 } | 321 } |
| 326 } | 322 } |
| 327 PermissionUmaUtil::RecordPermissionEmbargoStatus(embargo_status); | 323 PermissionUmaUtil::RecordEmbargoStatus(embargo_status); |
| 328 } | 324 } |
| 329 | 325 |
| 330 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, | 326 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, |
| 331 persist, content_setting); | 327 persist, content_setting); |
| 332 } | 328 } |
| 333 | 329 |
| 334 #if defined(OS_ANDROID) | 330 #if defined(OS_ANDROID) |
| 335 PermissionQueueController* PermissionContextBase::GetQueueController() { | 331 PermissionQueueController* PermissionContextBase::GetQueueController() { |
| 336 return permission_queue_controller_.get(); | 332 return permission_queue_controller_.get(); |
| 337 } | 333 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 content_settings_storage_type(), | 379 content_settings_storage_type(), |
| 384 std::string(), content_setting); | 380 std::string(), content_setting); |
| 385 } | 381 } |
| 386 | 382 |
| 387 ContentSettingsType PermissionContextBase::content_settings_storage_type() | 383 ContentSettingsType PermissionContextBase::content_settings_storage_type() |
| 388 const { | 384 const { |
| 389 if (content_settings_type_ == CONTENT_SETTINGS_TYPE_PUSH_MESSAGING) | 385 if (content_settings_type_ == CONTENT_SETTINGS_TYPE_PUSH_MESSAGING) |
| 390 return CONTENT_SETTINGS_TYPE_NOTIFICATIONS; | 386 return CONTENT_SETTINGS_TYPE_NOTIFICATIONS; |
| 391 return content_settings_type_; | 387 return content_settings_type_; |
| 392 } | 388 } |
| OLD | NEW |