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 |