blob: 9e1ef1b02b584a6ce3147e37fef8ee3b77199fa2 [file] [log] [blame]
[email protected]fdd679b2012-11-15 20:49:391// 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
[email protected]695b5712012-12-06 23:55:287#include <algorithm>
8
9#include "base/bind.h"
[email protected]3e72ed752013-02-02 00:47:4710#include "base/lazy_instance.h"
11#include "base/memory/ref_counted.h"
[email protected]3853a4c2013-02-11 17:15:5712#include "base/prefs/pref_service.h"
[email protected]3e72ed752013-02-02 00:47:4713#include "chrome/browser/browser_process.h"
[email protected]fdd679b2012-11-15 20:49:3914#include "chrome/browser/extensions/extension_prefs.h"
[email protected]3e72ed752013-02-02 00:47:4715#include "chrome/browser/safe_browsing/database_manager.h"
16#include "chrome/browser/safe_browsing/safe_browsing_service.h"
17#include "chrome/browser/safe_browsing/safe_browsing_util.h"
18#include "chrome/common/chrome_notification_types.h"
[email protected]fdd679b2012-11-15 20:49:3919#include "chrome/common/pref_names.h"
[email protected]3e72ed752013-02-02 00:47:4720#include "content/public/browser/notification_details.h"
21#include "content/public/browser/notification_source.h"
22
23using content::BrowserThread;
[email protected]fdd679b2012-11-15 20:49:3924
25namespace extensions {
26
[email protected]3e72ed752013-02-02 00:47:4727namespace {
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() {
[email protected]04f7d8292013-02-18 09:31:1035#if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING)
[email protected]3e72ed752013-02-02 00:47:4736 if (g_browser_process && g_browser_process->safe_browsing_service()) {
37 instance_ =
38 g_browser_process->safe_browsing_service()->database_manager();
39 }
[email protected]04f7d8292013-02-18 09:31:1040#endif
[email protected]3e72ed752013-02-02 00:47:4741 }
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
[email protected]49aeab62013-02-07 02:53:11104 virtual void OnCheckExtensionsResult(
105 const std::set<std::string>& hits) OVERRIDE {
[email protected]3e72ed752013-02-02 00:47:47106 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
[email protected]bc151cf92013-02-12 04:57:26117void IsNotEmpty(const Blacklist::IsBlacklistedCallback& callback,
118 const std::set<std::string>& set) {
119 callback.Run(!set.empty());
120}
121
[email protected]3e72ed752013-02-02 00:47:47122} // namespace
123
[email protected]fdd679b2012-11-15 20:49:39124Blacklist::Observer::Observer(Blacklist* blacklist) : blacklist_(blacklist) {
125 blacklist_->AddObserver(this);
126}
127
128Blacklist::Observer::~Observer() {
129 blacklist_->RemoveObserver(this);
130}
131
[email protected]3e72ed752013-02-02 00:47:47132Blacklist::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
[email protected]fdd679b2012-11-15 20:49:39142Blacklist::Blacklist(ExtensionPrefs* prefs) : prefs_(prefs) {
[email protected]3e72ed752013-02-02 00:47:47143 scoped_refptr<SafeBrowsingDatabaseManager> database_manager =
144 g_database_manager.Get().get();
[email protected]dc24976f2013-06-02 21:15:09145 if (database_manager.get()) {
146 registrar_.Add(
147 this,
148 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
149 content::Source<SafeBrowsingDatabaseManager>(database_manager.get()));
[email protected]3e72ed752013-02-02 00:47:47150 }
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).
[email protected]fdd679b2012-11-15 20:49:39158}
159
160Blacklist::~Blacklist() {
161}
162
[email protected]695b5712012-12-06 23:55:28163void Blacklist::GetBlacklistedIDs(const std::set<std::string>& ids,
164 const GetBlacklistedIDsCallback& callback) {
[email protected]3e72ed752013-02-02 00:47:47165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166
[email protected]bc151cf92013-02-12 04:57:26167 if (ids.empty()) {
168 base::MessageLoopProxy::current()->PostTask(
169 FROM_HERE,
170 base::Bind(callback, std::set<std::string>()));
171 return;
172 }
173
[email protected]3e72ed752013-02-02 00:47:47174 // 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;
[email protected]695b5712012-12-06 23:55:28177 for (std::set<std::string>::const_iterator it = ids.begin();
178 it != ids.end(); ++it) {
179 if (prefs_->IsExtensionBlacklisted(*it))
[email protected]3e72ed752013-02-02 00:47:47180 pref_blacklisted_ids.insert(*it);
[email protected]695b5712012-12-06 23:55:28181 }
[email protected]3e72ed752013-02-02 00:47:47182
[email protected]cadac622013-06-11 16:46:36183 if (!g_database_manager.Get().get().get()) {
[email protected]3e72ed752013-02-02 00:47:47184 base::MessageLoopProxy::current()->PostTask(
[email protected]cadac622013-06-11 16:46:36185 FROM_HERE, base::Bind(callback, pref_blacklisted_ids));
[email protected]3e72ed752013-02-02 00:47:47186 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));
[email protected]fdd679b2012-11-15 20:49:39196}
197
[email protected]bc151cf92013-02-12 04:57:26198void 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
[email protected]fdd679b2012-11-15 20:49:39205void Blacklist::SetFromUpdater(const std::vector<std::string>& ids,
206 const std::string& version) {
[email protected]3e72ed752013-02-02 00:47:47207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208
[email protected]fdd679b2012-11-15 20:49:39209 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
[email protected]695b5712012-12-06 23:55:28218 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
[email protected]fdd679b2012-11-15 20:49:39240 prefs_->pref_service()->SetString(prefs::kExtensionBlacklistUpdateVersion,
241 version);
242
243 FOR_EACH_OBSERVER(Observer, observers_, OnBlacklistUpdated());
244}
245
246void Blacklist::AddObserver(Observer* observer) {
[email protected]3e72ed752013-02-02 00:47:47247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]fdd679b2012-11-15 20:49:39248 observers_.AddObserver(observer);
249}
250
251void Blacklist::RemoveObserver(Observer* observer) {
[email protected]3e72ed752013-02-02 00:47:47252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]fdd679b2012-11-15 20:49:39253 observers_.RemoveObserver(observer);
254}
255
[email protected]3e72ed752013-02-02 00:47:47256// 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
[email protected]fdd679b2012-11-15 20:49:39287} // namespace extensions