blacklist.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/blacklist.h" 6 7#include <algorithm> 8 9#include "base/bind.h" 10#include "base/lazy_instance.h" 11#include "base/memory/ref_counted.h" 12#include "base/prefs/pref_service.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/chrome_notification_types.h" 15#include "chrome/browser/extensions/extension_prefs.h" 16#include "chrome/browser/safe_browsing/database_manager.h" 17#include "chrome/browser/safe_browsing/safe_browsing_service.h" 18#include "chrome/browser/safe_browsing/safe_browsing_util.h" 19#include "chrome/common/pref_names.h" 20#include "content/public/browser/notification_details.h" 21#include "content/public/browser/notification_source.h" 22 23using content::BrowserThread; 24 25namespace extensions { 26 27namespace { 28 29// The safe browsing database manager to use. Make this a global/static variable 30// rather than a member of Blacklist because Blacklist accesses the real 31// database manager before it has a chance to get a fake one. 32class LazySafeBrowsingDatabaseManager { 33 public: 34 LazySafeBrowsingDatabaseManager() { 35#if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING) 36 if (g_browser_process && g_browser_process->safe_browsing_service()) { 37 instance_ = 38 g_browser_process->safe_browsing_service()->database_manager(); 39 } 40#endif 41 } 42 43 scoped_refptr<SafeBrowsingDatabaseManager> get() { 44 return instance_; 45 } 46 47 void set(scoped_refptr<SafeBrowsingDatabaseManager> instance) { 48 instance_ = instance; 49 } 50 51 private: 52 scoped_refptr<SafeBrowsingDatabaseManager> instance_; 53}; 54 55static base::LazyInstance<LazySafeBrowsingDatabaseManager> g_database_manager = 56 LAZY_INSTANCE_INITIALIZER; 57 58// Implementation of SafeBrowsingDatabaseManager::Client, the class which is 59// called back from safebrowsing queries. 60// 61// Constructed on any thread but lives on the IO from then on. 62class SafeBrowsingClientImpl 63 : public SafeBrowsingDatabaseManager::Client, 64 public base::RefCountedThreadSafe<SafeBrowsingClientImpl> { 65 public: 66 typedef base::Callback<void(const std::set<std::string>&)> OnResultCallback; 67 68 // Constructs a client to query the database manager for |extension_ids| and 69 // run |callback| with the IDs of those which have been blacklisted. 70 SafeBrowsingClientImpl( 71 const std::set<std::string>& extension_ids, 72 const OnResultCallback& callback) 73 : callback_message_loop_(base::MessageLoopProxy::current()), 74 callback_(callback) { 75 BrowserThread::PostTask( 76 BrowserThread::IO, 77 FROM_HERE, 78 base::Bind(&SafeBrowsingClientImpl::StartCheck, this, 79 g_database_manager.Get().get(), 80 extension_ids)); 81 } 82 83 private: 84 friend class base::RefCountedThreadSafe<SafeBrowsingClientImpl>; 85 virtual ~SafeBrowsingClientImpl() {} 86 87 // Pass |database_manager| as a parameter to avoid touching 88 // SafeBrowsingService on the IO thread. 89 void StartCheck(scoped_refptr<SafeBrowsingDatabaseManager> database_manager, 90 const std::set<std::string>& extension_ids) { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 92 if (database_manager->CheckExtensionIDs(extension_ids, this)) { 93 // Definitely not blacklisted. Callback immediately. 94 callback_message_loop_->PostTask( 95 FROM_HERE, 96 base::Bind(callback_, std::set<std::string>())); 97 return; 98 } 99 // Something might be blacklisted, response will come in 100 // OnCheckExtensionsResult. 101 AddRef(); // Balanced in OnCheckExtensionsResult 102 } 103 104 virtual void OnCheckExtensionsResult( 105 const std::set<std::string>& hits) OVERRIDE { 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 107 callback_message_loop_->PostTask(FROM_HERE, base::Bind(callback_, hits)); 108 Release(); // Balanced in StartCheck. 109 } 110 111 scoped_refptr<base::MessageLoopProxy> callback_message_loop_; 112 OnResultCallback callback_; 113 114 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingClientImpl); 115}; 116 117void IsNotEmpty(const Blacklist::IsBlacklistedCallback& callback, 118 const std::set<std::string>& set) { 119 callback.Run(!set.empty()); 120} 121 122} // namespace 123 124Blacklist::Observer::Observer(Blacklist* blacklist) : blacklist_(blacklist) { 125 blacklist_->AddObserver(this); 126} 127 128Blacklist::Observer::~Observer() { 129 blacklist_->RemoveObserver(this); 130} 131 132Blacklist::ScopedDatabaseManagerForTest::ScopedDatabaseManagerForTest( 133 scoped_refptr<SafeBrowsingDatabaseManager> database_manager) 134 : original_(GetDatabaseManager()) { 135 SetDatabaseManager(database_manager); 136} 137 138Blacklist::ScopedDatabaseManagerForTest::~ScopedDatabaseManagerForTest() { 139 SetDatabaseManager(original_); 140} 141 142Blacklist::Blacklist(ExtensionPrefs* prefs) : prefs_(prefs) { 143 scoped_refptr<SafeBrowsingDatabaseManager> database_manager = 144 g_database_manager.Get().get(); 145 if (database_manager.get()) { 146 registrar_.Add( 147 this, 148 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, 149 content::Source<SafeBrowsingDatabaseManager>(database_manager.get())); 150 } 151 152 // TODO(kalman): Delete anything from the pref blacklist that is in the 153 // safebrowsing blacklist (of course, only entries for which the extension 154 // hasn't been installed). 155 // 156 // Or maybe just wait until we're able to delete the pref blacklist 157 // altogether (when we're sure it's a strict subset of the safebrowsing one). 158} 159 160Blacklist::~Blacklist() { 161} 162 163void Blacklist::GetBlacklistedIDs(const std::set<std::string>& ids, 164 const GetBlacklistedIDsCallback& callback) { 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 166 167 if (ids.empty()) { 168 base::MessageLoopProxy::current()->PostTask( 169 FROM_HERE, 170 base::Bind(callback, std::set<std::string>())); 171 return; 172 } 173 174 // The blacklisted IDs are the union of those blacklisted in prefs and 175 // those blacklisted from safe browsing. 176 std::set<std::string> pref_blacklisted_ids; 177 for (std::set<std::string>::const_iterator it = ids.begin(); 178 it != ids.end(); ++it) { 179 if (prefs_->IsExtensionBlacklisted(*it)) 180 pref_blacklisted_ids.insert(*it); 181 } 182 183 if (!g_database_manager.Get().get().get()) { 184 base::MessageLoopProxy::current()->PostTask( 185 FROM_HERE, base::Bind(callback, pref_blacklisted_ids)); 186 return; 187 } 188 189 // Constructing the SafeBrowsingClientImpl begins the process of asking 190 // safebrowsing for the blacklisted extensions. 191 new SafeBrowsingClientImpl( 192 ids, 193 base::Bind(&Blacklist::OnSafeBrowsingResponse, AsWeakPtr(), 194 pref_blacklisted_ids, 195 callback)); 196} 197 198void Blacklist::IsBlacklisted(const std::string& extension_id, 199 const IsBlacklistedCallback& callback) { 200 std::set<std::string> check; 201 check.insert(extension_id); 202 GetBlacklistedIDs(check, base::Bind(&IsNotEmpty, callback)); 203} 204 205void Blacklist::SetFromUpdater(const std::vector<std::string>& ids, 206 const std::string& version) { 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 208 209 std::set<std::string> ids_as_set; 210 for (std::vector<std::string>::const_iterator it = ids.begin(); 211 it != ids.end(); ++it) { 212 if (Extension::IdIsValid(*it)) 213 ids_as_set.insert(*it); 214 else 215 LOG(WARNING) << "Got invalid extension ID \"" << *it << "\""; 216 } 217 218 std::set<std::string> from_prefs = prefs_->GetBlacklistedExtensions(); 219 220 std::set<std::string> no_longer_blacklisted; 221 std::set_difference(from_prefs.begin(), from_prefs.end(), 222 ids_as_set.begin(), ids_as_set.end(), 223 std::inserter(no_longer_blacklisted, 224 no_longer_blacklisted.begin())); 225 std::set<std::string> not_yet_blacklisted; 226 std::set_difference(ids_as_set.begin(), ids_as_set.end(), 227 from_prefs.begin(), from_prefs.end(), 228 std::inserter(not_yet_blacklisted, 229 not_yet_blacklisted.begin())); 230 231 for (std::set<std::string>::iterator it = no_longer_blacklisted.begin(); 232 it != no_longer_blacklisted.end(); ++it) { 233 prefs_->SetExtensionBlacklisted(*it, false); 234 } 235 for (std::set<std::string>::iterator it = not_yet_blacklisted.begin(); 236 it != not_yet_blacklisted.end(); ++it) { 237 prefs_->SetExtensionBlacklisted(*it, true); 238 } 239 240 prefs_->pref_service()->SetString(prefs::kExtensionBlacklistUpdateVersion, 241 version); 242 243 FOR_EACH_OBSERVER(Observer, observers_, OnBlacklistUpdated()); 244} 245 246void Blacklist::AddObserver(Observer* observer) { 247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 248 observers_.AddObserver(observer); 249} 250 251void Blacklist::RemoveObserver(Observer* observer) { 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 253 observers_.RemoveObserver(observer); 254} 255 256// static 257void Blacklist::SetDatabaseManager( 258 scoped_refptr<SafeBrowsingDatabaseManager> database_manager) { 259 g_database_manager.Get().set(database_manager); 260} 261 262// static 263scoped_refptr<SafeBrowsingDatabaseManager> Blacklist::GetDatabaseManager() { 264 return g_database_manager.Get().get(); 265} 266 267void Blacklist::OnSafeBrowsingResponse( 268 const std::set<std::string>& pref_blacklisted_ids, 269 const GetBlacklistedIDsCallback& callback, 270 const std::set<std::string>& safebrowsing_blacklisted_ids) { 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 272 273 std::set<std::string> blacklist = pref_blacklisted_ids; 274 blacklist.insert(safebrowsing_blacklisted_ids.begin(), 275 safebrowsing_blacklisted_ids.end()); 276 277 callback.Run(blacklist); 278} 279 280void Blacklist::Observe(int type, 281 const content::NotificationSource& source, 282 const content::NotificationDetails& details) { 283 DCHECK_EQ(chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, type); 284 FOR_EACH_OBSERVER(Observer, observers_, OnBlacklistUpdated()); 285} 286 287} // namespace extensions 288