2012-07-28 10:25:11 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2012-10-31 20:13:28 +04:00
|
|
|
this.EXPORTED_SYMBOLS = ["SafeBrowsing"];
|
2012-07-28 10:25:11 +04:00
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
const Cu = Components.utils;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
|
2015-09-17 10:59:26 +03:00
|
|
|
// Log only if browser.safebrowsing.debug is true
|
|
|
|
function log(...stuff) {
|
|
|
|
let logging = null;
|
|
|
|
try {
|
|
|
|
logging = Services.prefs.getBoolPref("browser.safebrowsing.debug");
|
|
|
|
} catch(e) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!logging) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var d = new Date();
|
|
|
|
let msg = "SafeBrowsing: " + d.toTimeString() + ": " + stuff.join(" ");
|
|
|
|
dump(msg + "\n");
|
|
|
|
}
|
|
|
|
|
2014-04-17 21:57:08 +04:00
|
|
|
// Skip all the ones containining "test", because we never need to ask for
|
|
|
|
// updates for them.
|
|
|
|
function getLists(prefName) {
|
2015-09-08 09:22:10 +03:00
|
|
|
log("getLists: " + prefName);
|
|
|
|
let pref = null;
|
|
|
|
try {
|
|
|
|
pref = Services.prefs.getCharPref(prefName);
|
|
|
|
} catch(e) {
|
|
|
|
return null;
|
|
|
|
}
|
2014-04-22 17:11:53 +04:00
|
|
|
// Splitting an empty string returns [''], we really want an empty array.
|
|
|
|
if (!pref) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
return pref.split(",")
|
2014-04-17 21:57:08 +04:00
|
|
|
.filter(function(value) { return value.indexOf("test-") == -1; })
|
|
|
|
.map(function(value) { return value.trim(); });
|
|
|
|
}
|
|
|
|
|
|
|
|
// These may be a comma-separated lists of tables.
|
2014-07-02 23:41:00 +04:00
|
|
|
const phishingLists = getLists("urlclassifier.phishTable");
|
|
|
|
const malwareLists = getLists("urlclassifier.malwareTable");
|
2014-04-17 21:57:08 +04:00
|
|
|
const downloadBlockLists = getLists("urlclassifier.downloadBlockTable");
|
|
|
|
const downloadAllowLists = getLists("urlclassifier.downloadAllowTable");
|
2014-07-02 23:41:00 +04:00
|
|
|
const trackingProtectionLists = getLists("urlclassifier.trackingTable");
|
2015-08-07 23:08:22 +03:00
|
|
|
const trackingProtectionWhitelists = getLists("urlclassifier.trackingWhitelistTable");
|
2012-07-28 10:25:11 +04:00
|
|
|
|
2012-10-31 20:13:28 +04:00
|
|
|
this.SafeBrowsing = {
|
2012-07-28 10:25:11 +04:00
|
|
|
|
2012-07-31 04:14:29 +04:00
|
|
|
init: function() {
|
2012-07-28 10:25:11 +04:00
|
|
|
if (this.initialized) {
|
|
|
|
log("Already initialized");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-07 12:50:19 +04:00
|
|
|
Services.prefs.addObserver("browser.safebrowsing", this.readPrefs.bind(this), false);
|
2014-07-11 05:13:35 +04:00
|
|
|
Services.prefs.addObserver("privacy.trackingprotection", this.readPrefs.bind(this), false);
|
2012-07-28 10:25:11 +04:00
|
|
|
this.readPrefs();
|
2015-09-08 09:22:10 +03:00
|
|
|
this.addMozEntries();
|
2012-07-28 10:25:11 +04:00
|
|
|
|
2015-09-08 09:22:10 +03:00
|
|
|
this.controlUpdateChecking();
|
|
|
|
this.initialized = true;
|
|
|
|
|
|
|
|
log("init() finished");
|
|
|
|
},
|
|
|
|
|
|
|
|
registerTableWithURLs: function(listname) {
|
2012-07-28 10:25:11 +04:00
|
|
|
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
|
2015-09-08 09:22:10 +03:00
|
|
|
getService(Ci.nsIUrlListManager);
|
|
|
|
|
|
|
|
let providerName = this.listToProvider[listname];
|
|
|
|
let provider = this.providers[providerName];
|
|
|
|
|
|
|
|
listManager.registerTable(listname, provider.updateURL, provider.gethashURL);
|
|
|
|
},
|
|
|
|
|
|
|
|
registerTables: function() {
|
2014-04-17 21:57:08 +04:00
|
|
|
for (let i = 0; i < phishingLists.length; ++i) {
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTableWithURLs(phishingLists[i]);
|
2014-04-17 21:57:08 +04:00
|
|
|
}
|
|
|
|
for (let i = 0; i < malwareLists.length; ++i) {
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTableWithURLs(malwareLists[i]);
|
2014-04-17 21:57:08 +04:00
|
|
|
}
|
|
|
|
for (let i = 0; i < downloadBlockLists.length; ++i) {
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTableWithURLs(downloadBlockLists[i]);
|
2014-04-17 21:57:08 +04:00
|
|
|
}
|
|
|
|
for (let i = 0; i < downloadAllowLists.length; ++i) {
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTableWithURLs(downloadAllowLists[i]);
|
2014-04-17 21:57:08 +04:00
|
|
|
}
|
2014-07-02 23:41:00 +04:00
|
|
|
for (let i = 0; i < trackingProtectionLists.length; ++i) {
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTableWithURLs(trackingProtectionLists[i]);
|
2014-07-02 23:41:00 +04:00
|
|
|
}
|
2015-08-07 23:08:22 +03:00
|
|
|
for (let i = 0; i < trackingProtectionWhitelists.length; ++i) {
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTableWithURLs(trackingProtectionWhitelists[i]);
|
2015-08-07 23:08:22 +03:00
|
|
|
}
|
2012-07-28 10:25:11 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
initialized: false,
|
|
|
|
phishingEnabled: false,
|
|
|
|
malwareEnabled: false,
|
|
|
|
|
|
|
|
updateURL: null,
|
|
|
|
gethashURL: null,
|
2012-08-02 02:52:47 +04:00
|
|
|
|
|
|
|
reportURL: null,
|
2012-07-28 10:25:11 +04:00
|
|
|
|
2015-06-16 22:28:42 +03:00
|
|
|
getReportURL: function(kind, URI) {
|
|
|
|
let pref;
|
|
|
|
switch (kind) {
|
|
|
|
case "Phish":
|
|
|
|
pref = "browser.safebrowsing.reportPhishURL";
|
|
|
|
break;
|
|
|
|
case "PhishMistake":
|
|
|
|
pref = "browser.safebrowsing.reportPhishMistakeURL";
|
|
|
|
break;
|
|
|
|
case "MalwareMistake":
|
|
|
|
pref = "browser.safebrowsing.reportMalwareMistakeURL";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
let err = "SafeBrowsing getReportURL() called with unknown kind: " + kind;
|
|
|
|
Components.utils.reportError(err);
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
let reportUrl = Services.urlFormatter.formatURLPref(pref);
|
|
|
|
|
|
|
|
let pageUri = URI.clone();
|
|
|
|
|
|
|
|
// Remove the query to avoid including potentially sensitive data
|
|
|
|
if (pageUri instanceof Ci.nsIURL)
|
|
|
|
pageUri.query = '';
|
2012-07-28 10:25:11 +04:00
|
|
|
|
2015-06-16 22:28:42 +03:00
|
|
|
reportUrl += encodeURIComponent(pageUri.asciiSpec);
|
|
|
|
|
|
|
|
return reportUrl;
|
2012-07-28 10:25:11 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
readPrefs: function() {
|
|
|
|
log("reading prefs");
|
|
|
|
|
2015-09-17 10:59:26 +03:00
|
|
|
this.debug = Services.prefs.getBoolPref("browser.safebrowsing.debug");
|
2012-07-28 10:25:11 +04:00
|
|
|
this.phishingEnabled = Services.prefs.getBoolPref("browser.safebrowsing.enabled");
|
2014-07-02 23:41:00 +04:00
|
|
|
this.malwareEnabled = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
|
2015-03-24 21:10:00 +03:00
|
|
|
this.trackingEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.enabled") || Services.prefs.getBoolPref("privacy.trackingprotection.pbmode.enabled");
|
2012-08-02 02:52:47 +04:00
|
|
|
this.updateProviderURLs();
|
2015-09-08 09:22:10 +03:00
|
|
|
this.registerTables();
|
2012-07-28 10:25:11 +04:00
|
|
|
|
|
|
|
// XXX The listManager backend gets confused if this is called before the
|
|
|
|
// lists are registered. So only call it here when a pref changes, and not
|
|
|
|
// when doing initialization. I expect to refactor this later, so pardon the hack.
|
2014-07-11 05:13:35 +04:00
|
|
|
if (this.initialized) {
|
2012-07-28 10:25:11 +04:00
|
|
|
this.controlUpdateChecking();
|
2014-07-11 05:13:35 +04:00
|
|
|
}
|
2012-07-28 10:25:11 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
|
2012-08-02 02:52:47 +04:00
|
|
|
updateProviderURLs: function() {
|
2013-01-10 11:38:50 +04:00
|
|
|
try {
|
|
|
|
var clientID = Services.prefs.getCharPref("browser.safebrowsing.id");
|
|
|
|
} catch(e) {
|
2015-09-08 09:22:10 +03:00
|
|
|
clientID = Services.appinfo.name;
|
2013-01-10 11:38:50 +04:00
|
|
|
}
|
2012-07-31 04:14:29 +04:00
|
|
|
|
2015-09-08 09:22:10 +03:00
|
|
|
log("initializing safe browsing URLs, client id", clientID);
|
2012-08-02 02:52:47 +04:00
|
|
|
|
2015-09-08 09:22:10 +03:00
|
|
|
// Get the different providers
|
|
|
|
let branch = Services.prefs.getBranch("browser.safebrowsing.provider.");
|
|
|
|
let children = branch.getChildList("", {});
|
|
|
|
this.providers = {};
|
|
|
|
this.listToProvider = {};
|
2012-08-02 02:52:47 +04:00
|
|
|
|
2015-09-08 09:22:10 +03:00
|
|
|
for (let child of children) {
|
|
|
|
log("Child: " + child);
|
|
|
|
let prefComponents = child.split(".");
|
|
|
|
let providerName = prefComponents[0];
|
|
|
|
this.providers[providerName] = {};
|
|
|
|
}
|
|
|
|
|
2015-09-17 10:59:26 +03:00
|
|
|
if (this.debug) {
|
2015-09-08 09:22:10 +03:00
|
|
|
let providerStr = "";
|
|
|
|
Object.keys(this.providers).forEach(function(provider) {
|
|
|
|
if (providerStr === "") {
|
|
|
|
providerStr = provider;
|
|
|
|
} else {
|
|
|
|
providerStr += ", " + provider;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
log("Providers: " + providerStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.keys(this.providers).forEach(function(provider) {
|
|
|
|
let updateURL = Services.urlFormatter.formatURLPref(
|
|
|
|
"browser.safebrowsing.provider." + provider + ".updateURL");
|
|
|
|
let gethashURL = Services.urlFormatter.formatURLPref(
|
|
|
|
"browser.safebrowsing.provider." + provider + ".gethashURL");
|
|
|
|
updateURL = updateURL.replace("SAFEBROWSING_ID", clientID);
|
|
|
|
gethashURL = gethashURL.replace("SAFEBROWSING_ID", clientID);
|
|
|
|
|
|
|
|
log("Provider: " + provider + " updateURL=" + updateURL);
|
|
|
|
log("Provider: " + provider + " gethashURL=" + gethashURL);
|
|
|
|
|
|
|
|
// Urls used to update DB
|
|
|
|
this.providers[provider].updateURL = updateURL;
|
|
|
|
this.providers[provider].gethashURL = gethashURL;
|
|
|
|
|
|
|
|
// Get lists this provider manages
|
|
|
|
let lists = getLists("browser.safebrowsing.provider." + provider + ".lists");
|
|
|
|
if (lists) {
|
|
|
|
lists.forEach(function(list) {
|
|
|
|
this.listToProvider[list] = provider;
|
|
|
|
}, this);
|
|
|
|
} else {
|
|
|
|
log("Update URL given but no lists managed for provider: " + provider);
|
|
|
|
}
|
|
|
|
}, this);
|
2012-07-28 10:25:11 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
controlUpdateChecking: function() {
|
2014-07-11 05:13:35 +04:00
|
|
|
log("phishingEnabled:", this.phishingEnabled, "malwareEnabled:",
|
|
|
|
this.malwareEnabled, "trackingEnabled:", this.trackingEnabled);
|
2012-07-28 10:25:11 +04:00
|
|
|
|
|
|
|
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
|
|
|
|
getService(Ci.nsIUrlListManager);
|
|
|
|
|
2014-04-17 21:57:08 +04:00
|
|
|
for (let i = 0; i < phishingLists.length; ++i) {
|
|
|
|
if (this.phishingEnabled) {
|
|
|
|
listManager.enableUpdate(phishingLists[i]);
|
|
|
|
} else {
|
|
|
|
listManager.disableUpdate(phishingLists[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (let i = 0; i < malwareLists.length; ++i) {
|
|
|
|
if (this.malwareEnabled) {
|
|
|
|
listManager.enableUpdate(malwareLists[i]);
|
|
|
|
} else {
|
|
|
|
listManager.disableUpdate(malwareLists[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (let i = 0; i < downloadBlockLists.length; ++i) {
|
|
|
|
if (this.malwareEnabled) {
|
|
|
|
listManager.enableUpdate(downloadBlockLists[i]);
|
|
|
|
} else {
|
|
|
|
listManager.disableUpdate(downloadBlockLists[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (let i = 0; i < downloadAllowLists.length; ++i) {
|
|
|
|
if (this.malwareEnabled) {
|
|
|
|
listManager.enableUpdate(downloadAllowLists[i]);
|
|
|
|
} else {
|
|
|
|
listManager.disableUpdate(downloadAllowLists[i]);
|
|
|
|
}
|
2013-11-01 01:15:14 +04:00
|
|
|
}
|
2014-07-02 23:41:00 +04:00
|
|
|
for (let i = 0; i < trackingProtectionLists.length; ++i) {
|
|
|
|
if (this.trackingEnabled) {
|
|
|
|
listManager.enableUpdate(trackingProtectionLists[i]);
|
2015-08-07 23:08:22 +03:00
|
|
|
listManager.enableUpdate(trackingProtectionWhitelists[i]);
|
2014-07-02 23:41:00 +04:00
|
|
|
} else {
|
|
|
|
listManager.disableUpdate(trackingProtectionLists[i]);
|
2015-08-07 23:08:22 +03:00
|
|
|
listManager.disableUpdate(trackingProtectionWhitelists[i]);
|
2014-07-02 23:41:00 +04:00
|
|
|
}
|
|
|
|
}
|
2014-07-11 05:13:35 +04:00
|
|
|
listManager.maybeToggleUpdateChecking();
|
2012-07-28 10:25:11 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
addMozEntries: function() {
|
|
|
|
// Add test entries to the DB.
|
2012-08-02 02:52:47 +04:00
|
|
|
// XXX bug 779008 - this could be done by DB itself?
|
2015-04-22 12:01:37 +03:00
|
|
|
const phishURL = "itisatrap.org/firefox/its-a-trap.html";
|
|
|
|
const malwareURL = "itisatrap.org/firefox/its-an-attack.html";
|
|
|
|
const unwantedURL = "itisatrap.org/firefox/unwanted.html";
|
2015-08-07 23:08:22 +03:00
|
|
|
const trackerURLs = [
|
2015-07-27 21:05:26 +03:00
|
|
|
"trackertest.org/",
|
|
|
|
"itisatracker.org/",
|
|
|
|
];
|
2015-08-07 23:08:22 +03:00
|
|
|
const whitelistURL = "itisatrap.org/?resource=itisatracker.org";
|
2012-07-28 10:25:11 +04:00
|
|
|
|
|
|
|
let update = "n:1000\ni:test-malware-simple\nad:1\n" +
|
|
|
|
"a:1:32:" + malwareURL.length + "\n" +
|
2015-08-07 23:08:22 +03:00
|
|
|
malwareURL + "\n";
|
2012-07-28 10:25:11 +04:00
|
|
|
update += "n:1000\ni:test-phish-simple\nad:1\n" +
|
|
|
|
"a:1:32:" + phishURL.length + "\n" +
|
2015-08-07 23:08:22 +03:00
|
|
|
phishURL + "\n";
|
2015-04-22 12:01:37 +03:00
|
|
|
update += "n:1000\ni:test-unwanted-simple\nad:1\n" +
|
|
|
|
"a:1:32:" + unwantedURL.length + "\n" +
|
2015-08-07 23:08:22 +03:00
|
|
|
unwantedURL + "\n";
|
|
|
|
update += "n:1000\ni:test-track-simple\n" +
|
|
|
|
"ad:" + trackerURLs.length + "\n";
|
2015-07-27 21:05:26 +03:00
|
|
|
trackerURLs.forEach((trackerURL, i) => {
|
2015-08-07 23:08:22 +03:00
|
|
|
update += "a:" + (i + 1) + ":32:" + trackerURL.length + "\n" +
|
|
|
|
trackerURL + "\n";
|
2015-07-27 21:05:26 +03:00
|
|
|
});
|
2015-08-07 23:08:22 +03:00
|
|
|
update += "n:1000\ni:test-trackwhite-simple\nad:1\n" +
|
|
|
|
"a:1:32:" + whitelistURL.length + "\n" +
|
|
|
|
whitelistURL;
|
2012-07-28 10:25:11 +04:00
|
|
|
log("addMozEntries:", update);
|
|
|
|
|
|
|
|
let db = Cc["@mozilla.org/url-classifier/dbservice;1"].
|
|
|
|
getService(Ci.nsIUrlClassifierDBService);
|
|
|
|
|
|
|
|
// nsIUrlClassifierUpdateObserver
|
|
|
|
let dummyListener = {
|
|
|
|
updateUrlRequested: function() { },
|
|
|
|
streamFinished: function() { },
|
|
|
|
updateError: function() { },
|
|
|
|
updateSuccess: function() { }
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
2015-08-07 23:08:22 +03:00
|
|
|
let tables = "test-malware-simple,test-phish-simple,test-unwanted-simple,test-track-simple,test-trackwhite-simple";
|
2015-07-27 21:05:26 +03:00
|
|
|
db.beginUpdate(dummyListener, tables, "");
|
2012-07-28 10:25:11 +04:00
|
|
|
db.beginStream("", "");
|
|
|
|
db.updateStream(update);
|
|
|
|
db.finishStream();
|
|
|
|
db.finishUpdate();
|
|
|
|
} catch(ex) {
|
|
|
|
// beginUpdate will throw harmlessly if there's an existing update in progress, ignore failures.
|
|
|
|
log("addMozEntries failed!", ex);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|