106
106
// Read state: should we be checking remote preferences?
107
107
this.checkRemote_ = this.prefs_.getPref(kPhishWardenRemoteLookups, null);
109
// true if we should use whitelists to suppress remote lookups
110
this.checkWhitelists_ = false;
109
112
// Get notifications when the remote check preference changes
110
113
var checkRemotePrefObserver = BindToObject(this.onCheckRemotePrefChanged,
118
121
var phishWardenPrefObserver =
119
122
BindToObject(this.onPhishWardenEnabledPrefChanged, this);
120
123
this.prefs_.addObserver(kPhishWardenEnabledPref, phishWardenPrefObserver);
125
// Get notifications when the data provider pref changes
126
var dataProviderPrefObserver =
127
BindToObject(this.onDataProviderPrefChanged, this);
128
this.prefs_.addObserver(kDataProviderIdPref, dataProviderPrefObserver);
122
130
// hook up our browser listener
123
131
this.progressListener_ = progressListener;
126
134
// ms to wait after a request has started before firing JS callback
127
135
this.progressListener_.delay = 1500;
137
// object to keep track of request errors if we're in remote check mode
138
this.requestBackoff_ = new RequestBackoff(3 /* num errors */,
139
10*60*1000 /* error time, 10min */,
140
10*60*1000 /* backoff interval, 10min */,
141
6*60*60*1000 /* max backoff, 6hr */);
129
143
G_Debug(this, "phishWarden initialized");
182
196
// We update and save to disk all tables if we don't have remote checking
184
if (phishWardenEnabled === true && this.checkRemote_ === false) {
198
if (phishWardenEnabled === true) {
199
// If anti-phishing is enabled, we always download the local files to
200
// use in case remote lookups fail.
185
201
this.enableBlacklistTableUpdates();
186
202
this.enableWhitelistTableUpdates();
204
if (this.checkRemote_ === true) {
205
// Remote lookup mode
206
// We check to see if the local list update host is the same as the
207
// remote lookup host. If they are the same, then we don't bother
208
// to do a remote url check if the url is in the whitelist.
209
var ioService = Cc["@mozilla.org/network/io-service;1"]
210
.getService(Ci.nsIIOService);
214
var url = ioService.newURI(gDataProvider.getUpdateURL(),
216
updateHost = url.asciiHost;
219
var url = ioService.newURI(gDataProvider.getLookupURL(),
221
lookupHost = url.asciiHost;
224
if (updateHost && lookupHost && updateHost == lookupHost) {
225
// The data provider for local lists and remote lookups is the
226
// same, enable whitelist lookup suppression.
227
this.checkWhitelists_ = true;
229
// hosts don't match, don't use whitelist suppression
230
this.checkWhitelists_ = false;
234
// Anti-phishing is off, disable table updates
188
235
this.disableBlacklistTableUpdates();
189
236
this.disableWhitelistTableUpdates();
240
288
this.phishWardenEnabled_ =
241
289
this.prefs_.getBoolPrefOrDefault(prefName, this.phishWardenEnabled_);
290
this.requestBackoff_.reset();
242
291
this.maybeToggleUpdateChecking();
243
292
this.progressListener_.enabled = this.phishWardenEnabled_;
296
* Event fired when the user changes data providers.
298
PROT_PhishingWarden.prototype.onDataProviderPrefChanged = function(prefName) {
299
// We want to reset request backoff state since it's a different provider.
300
this.requestBackoff_.reset();
302
// If we have a new data provider and we're doing remote lookups, then
303
// we may want to use whitelist lookup suppression or change which
304
// tables are being downloaded.
305
if (this.checkRemote_) {
306
this.maybeToggleUpdateChecking();
247
311
* A request for a Document has been initiated somewhere. Check it!
253
317
G_Debug(this, "checkRemote: " +
254
318
(this.checkRemote_ ? "yes" : "no"));
256
// This logic is a bit involved. In some instances of SafeBrowsing
257
// (the stand-alone extension, for example), the user might yet have
258
// opted into or out of advanced protection mode. In this case we
259
// would like to show them a modal dialog requiring them
260
// to. However, there are links from that dialog to the test page,
261
// and the warden starts out as disabled. So we want to show the
262
// warning on the test page so long as the extension hasn't been
263
// explicitly disabled.
265
// If we're on the test page and we're not explicitly disabled
320
// If we're on a test page, trigger the warning.
266
321
// XXX Do we still need a test url or should each provider just put
267
322
// it in their local list?
268
// Either send a request off or check locally
269
if (this.checkRemote_) {
270
// First check to see if it's a blacklist url.
271
if (this.isBlacklistTestURL(url)) {
272
this.houstonWeHaveAProblem_(request);
323
if (this.isBlacklistTestURL(url)) {
324
this.houstonWeHaveAProblem_(request);
328
// Make a remote lookup check if the pref is selected and if we haven't
329
// triggered server backoff. Otherwise, make a local check.
330
if (this.checkRemote_ && this.requestBackoff_.canMakeRequest()) {
331
// If we can use whitelists to suppress remote lookups, do so.
332
if (this.checkWhitelists_) {
333
var maybeRemoteCheck = BindToObject(this.maybeMakeRemoteCheck_,
337
this.isWhiteURL(url, maybeRemoteCheck);
274
// TODO: Use local whitelists to suppress remote BL lookups.
339
// Do a remote lookup (don't check whitelists)
275
340
this.fetcher_.get(url,
276
341
BindToObject(this.onTRFetchComplete,
286
this.checkUrl_(url, evilCallback);
352
this.isEvilURL(url, evilCallback);
357
* Callback from whitelist check when remote lookups is on.
358
* @param url String url to lookup
359
* @param request nsIRequest object
360
* @param status int enum from callback (PROT_ListWarden.IN_BLACKLIST,
361
* PROT_ListWarden.IN_WHITELIST, PROT_ListWarden.NOT_FOUND)
363
PROT_PhishingWarden.prototype.maybeMakeRemoteCheck_ = function(url, request, status) {
364
if (PROT_ListWarden.IN_WHITELIST == status)
367
G_Debug(this, "Local whitelist lookup failed");
368
this.fetcher_.get(url,
369
BindToObject(this.onTRFetchComplete,
291
376
* Invoked with the result of a lookupserver request.
378
* @param url String the URL we looked up
293
379
* @param request The nsIRequest in which we're interested
295
380
* @param trValues Object holding name/value pairs parsed from the
296
381
* lookupserver's response
382
* @param status Number HTTP status code or NS_ERROR_NOT_AVAILABLE if there's
298
PROT_PhishingWarden.prototype.onTRFetchComplete = function(request,
300
var callback = BindToObject(this.houstonWeHaveAProblem_, this, request);
301
this.checkRemoteData(callback, trValues);
385
PROT_PhishingWarden.prototype.onTRFetchComplete = function(url,
389
// Did the remote http request succeed? If not, we fall back on
391
if (status == Components.results.NS_ERROR_NOT_AVAILABLE ||
392
this.requestBackoff_.isErrorStatus_(status)) {
393
this.requestBackoff_.noteServerResponse(status);
395
G_Debug(this, "remote check failed, using local lists instead");
396
var evilCallback = BindToObject(this.localListMatch_,
400
this.isEvilURL(url, evilCallback);
402
var callback = BindToObject(this.houstonWeHaveAProblem_, this, request);
403
this.checkRemoteData(callback, trValues);
434
* Check to see if the url is in the blacklist.
437
* @param callback Function
439
PROT_PhishingWarden.prototype.checkUrl_ = function(url, callback) {
440
// First check to see if it's a blacklist url.
441
if (this.isBlacklistTestURL(url)) {
445
this.isEvilURL_(url, callback);
449
537
* Callback for found local blacklist match. First we report that we have
450
538
* a blacklist hit, then we bring up the warning dialog.
539
* @param status Number enum from callback (PROT_ListWarden.IN_BLACKLIST,
540
* PROT_ListWarden.IN_WHITELIST, PROT_ListWarden.NOT_FOUND)
452
PROT_PhishingWarden.prototype.localListMatch_ = function(url, request) {
542
PROT_PhishingWarden.prototype.localListMatch_ = function(url, request, status) {
543
if (PROT_ListWarden.IN_BLACKLIST != status)
453
546
// Maybe send a report
454
547
(new PROT_Reporter).report("phishblhit", url);
455
548
this.houstonWeHaveAProblem_(request);
479
572
G_Debug(this, "Remote blacklist miss");
577
// Some unittests (e.g., paste into JS shell)
578
var warden = safebrowsing.phishWarden;
579
function expectLocalCheck() {
580
warden.isEvilURL = function() {
581
dump("checkurl: ok\n");
583
warden.checkRemoteData = function() {
584
throw "unexpected remote check";
587
function expectRemoteCheck() {
588
warden.isEvilURL = function() {
589
throw "unexpected local check";
591
warden.checkRemoteData = function() {
592
dump("checkremote: ok\n");
596
warden.requestBackoff_.reset();
600
warden.onTRFetchComplete(null, null, null, 200);
602
// HTTP 5xx should fallback on local check
604
warden.onTRFetchComplete(null, null, null, 500);
605
warden.onTRFetchComplete(null, null, null, 502);
607
// Only two errors have occurred, so we continue to try remote lookups.
608
if (!warden.requestBackoff_.canMakeRequest()) throw "expected ok";
610
// NS_ERROR_NOT_AVAILABLE also triggers a local check, but it doesn't
611
// count as a remote lookup error. We don't know /why/ it failed (e.g.,
612
// user may just be in offline mode).
613
warden.onTRFetchComplete(null, null, null,
614
Components.results.NS_ERROR_NOT_AVAILABLE);
615
if (!warden.requestBackoff_.canMakeRequest()) throw "expected ok";
617
// HTTP 302, 303, 307 should also trigger an error. This is our
618
// third error so we should now be in backoff mode.
620
warden.onTRFetchComplete(null, null, null, 303);
622
if (warden.requestBackoff_.canMakeRequest()) throw "expected failed";