mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 783047 - Remove MAC support from SafeBrowsing code. r=mmc,dcamp
This commit is contained in:
parent
3e6531d3e8
commit
87ba1b8817
@ -143,13 +143,13 @@
|
||||
#define NS_URLCLASSIFIERPREFIXSET_CID \
|
||||
{ 0x3d8579f0, 0x75fa, 0x4e00, { 0xba, 0x41, 0x38, 0x66, 0x1d, 0x5b, 0x5d, 0x17} }
|
||||
|
||||
// {5eb7c3c1-ec1f-4007-87cc-eefb37d68ce6}
|
||||
// {8a389f21-f821-4e29-9c6b-3de6f33cd7cf}
|
||||
#define NS_URLCLASSIFIERDBSERVICE_CID \
|
||||
{ 0x5eb7c3c1, 0xec1f, 0x4007, { 0x87, 0xcc, 0xee, 0xfb, 0x37, 0xd6, 0x8c, 0xe6} }
|
||||
{ 0x8a389f21, 0xf821, 0x4e29, { 0x9c, 0x6b, 0x3d, 0xe6, 0xf3, 0x3c, 0xd7, 0xcf} }
|
||||
|
||||
// {c2be6dc0-ef1e-4abd-86a2-4f864ddc57f6}
|
||||
// {79e6b710-ce68-4639-ac6b-7d293af424a1}
|
||||
#define NS_URLCLASSIFIERSTREAMUPDATER_CID \
|
||||
{ 0xc2be6dc0, 0xef1e, 0x4abd, { 0x86, 0xa2, 0x4f, 0x86, 0x4d, 0xdc, 0x57, 0xf6} }
|
||||
{ 0x79e6b710, 0xce68, 0x4639, { 0xac, 0x6b, 0x7d, 0x29, 0x3a, 0xf4, 0x24, 0xa1} }
|
||||
|
||||
// {b7b2ccec-7912-4ea6-a548-b038447004bd}
|
||||
#define NS_URLCLASSIFIERUTILS_CID \
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "ProtocolParser.h"
|
||||
#include "LookupCache.h"
|
||||
#include "nsIKeyModule.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "prlog.h"
|
||||
#include "prnetdb.h"
|
||||
@ -70,7 +69,6 @@ ProtocolParser::ProtocolParser()
|
||||
, mUpdateStatus(NS_OK)
|
||||
, mUpdateWait(0)
|
||||
, mResetRequested(false)
|
||||
, mRekeyRequested(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -86,81 +84,6 @@ ProtocolParser::Init(nsICryptoHash* aHasher)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize HMAC for the stream.
|
||||
*
|
||||
* If serverMAC is empty, the update stream will need to provide a
|
||||
* server MAC.
|
||||
*/
|
||||
nsresult
|
||||
ProtocolParser::InitHMAC(const nsACString& aClientKey,
|
||||
const nsACString& aServerMAC)
|
||||
{
|
||||
mServerMAC = aServerMAC;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIKeyObjectFactory> keyObjectFactory(
|
||||
do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to get nsIKeyObjectFactory service");
|
||||
mUpdateStatus = rv;
|
||||
return mUpdateStatus;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIKeyObject> keyObject;
|
||||
rv = keyObjectFactory->KeyFromString(nsIKeyObject::HMAC, aClientKey,
|
||||
getter_AddRefs(keyObject));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to create key object, maybe not FIPS compliant?");
|
||||
mUpdateStatus = rv;
|
||||
return mUpdateStatus;
|
||||
}
|
||||
|
||||
mHMAC = do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to create nsICryptoHMAC instance");
|
||||
mUpdateStatus = rv;
|
||||
return mUpdateStatus;
|
||||
}
|
||||
|
||||
rv = mHMAC->Init(nsICryptoHMAC::SHA1, keyObject);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to initialize nsICryptoHMAC instance");
|
||||
mUpdateStatus = rv;
|
||||
return mUpdateStatus;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ProtocolParser::FinishHMAC()
|
||||
{
|
||||
if (NS_FAILED(mUpdateStatus)) {
|
||||
return mUpdateStatus;
|
||||
}
|
||||
|
||||
if (mRekeyRequested) {
|
||||
mUpdateStatus = NS_ERROR_FAILURE;
|
||||
return mUpdateStatus;
|
||||
}
|
||||
|
||||
if (!mHMAC) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString clientMAC;
|
||||
mHMAC->Finish(true, clientMAC);
|
||||
|
||||
if (clientMAC != mServerMAC) {
|
||||
NS_WARNING("Invalid update MAC!");
|
||||
LOG(("Invalid update MAC: expected %s, got %s",
|
||||
clientMAC.get(), mServerMAC.get()));
|
||||
mUpdateStatus = NS_ERROR_FAILURE;
|
||||
}
|
||||
return mUpdateStatus;
|
||||
}
|
||||
|
||||
void
|
||||
ProtocolParser::SetCurrentTable(const nsACString& aTable)
|
||||
{
|
||||
@ -174,17 +97,6 @@ ProtocolParser::AppendStream(const nsACString& aData)
|
||||
return mUpdateStatus;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Digest the data if we have a server MAC.
|
||||
if (mHMAC && !mServerMAC.IsEmpty()) {
|
||||
rv = mHMAC->Update(reinterpret_cast<const uint8_t*>(aData.BeginReading()),
|
||||
aData.Length());
|
||||
if (NS_FAILED(rv)) {
|
||||
mUpdateStatus = rv;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mPending.Append(aData);
|
||||
|
||||
bool done = false;
|
||||
@ -215,13 +127,7 @@ ProtocolParser::ProcessControl(bool* aDone)
|
||||
while (NextLine(line)) {
|
||||
//LOG(("Processing %s\n", line.get()));
|
||||
|
||||
if (line.EqualsLiteral("e:pleaserekey")) {
|
||||
mRekeyRequested = true;
|
||||
return NS_OK;
|
||||
} else if (mHMAC && mServerMAC.IsEmpty()) {
|
||||
rv = ProcessMAC(line);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("i:"))) {
|
||||
if (StringBeginsWith(line, NS_LITERAL_CSTRING("i:"))) {
|
||||
// Set the table name from the table header line.
|
||||
SetCurrentTable(Substring(line, 2));
|
||||
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("n:"))) {
|
||||
@ -251,28 +157,6 @@ ProtocolParser::ProcessControl(bool* aDone)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
ProtocolParser::ProcessMAC(const nsCString& aLine)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("line: %s", aLine.get()));
|
||||
|
||||
if (StringBeginsWith(aLine, NS_LITERAL_CSTRING("m:"))) {
|
||||
mServerMAC = Substring(aLine, 2);
|
||||
nsUrlClassifierUtils::UnUrlsafeBase64(mServerMAC);
|
||||
|
||||
// The remainder of the pending update wasn't digested, digest it now.
|
||||
rv = mHMAC->Update(reinterpret_cast<const uint8_t*>(mPending.BeginReading()),
|
||||
mPending.Length());
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG(("No MAC specified!"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ProtocolParser::ProcessExpirations(const nsCString& aLine)
|
||||
{
|
||||
@ -364,29 +248,11 @@ nsresult
|
||||
ProtocolParser::ProcessForward(const nsCString& aLine)
|
||||
{
|
||||
const nsCSubstring &forward = Substring(aLine, 2);
|
||||
if (mHMAC) {
|
||||
// We're expecting MACs alongside any url forwards.
|
||||
nsCSubstring::const_iterator begin, end, sepBegin, sepEnd;
|
||||
forward.BeginReading(begin);
|
||||
sepBegin = begin;
|
||||
|
||||
forward.EndReading(end);
|
||||
sepEnd = end;
|
||||
|
||||
if (!RFindInReadable(NS_LITERAL_CSTRING(","), sepBegin, sepEnd)) {
|
||||
NS_WARNING("No MAC specified for a redirect in a request that expects a MAC");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCString serverMAC(Substring(sepEnd, end));
|
||||
nsUrlClassifierUtils::UnUrlsafeBase64(serverMAC);
|
||||
return AddForward(Substring(begin, sepBegin), serverMAC);
|
||||
}
|
||||
return AddForward(forward, mServerMAC);
|
||||
return AddForward(forward);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ProtocolParser::AddForward(const nsACString& aUrl, const nsACString& aMac)
|
||||
ProtocolParser::AddForward(const nsACString& aUrl)
|
||||
{
|
||||
if (!mTableUpdate) {
|
||||
NS_WARNING("Forward without a table name.");
|
||||
@ -396,7 +262,6 @@ ProtocolParser::AddForward(const nsACString& aUrl, const nsACString& aMac)
|
||||
ForwardedUpdate *forward = mForwards.AppendElement();
|
||||
forward->table = mTableUpdate->TableName();
|
||||
forward->url.Assign(aUrl);
|
||||
forward->mac.Assign(aMac);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ public:
|
||||
struct ForwardedUpdate {
|
||||
nsCString table;
|
||||
nsCString url;
|
||||
nsCString mac;
|
||||
};
|
||||
|
||||
ProtocolParser();
|
||||
@ -30,10 +29,6 @@ public:
|
||||
|
||||
nsresult Init(nsICryptoHash* aHasher);
|
||||
|
||||
nsresult InitHMAC(const nsACString& aClientKey,
|
||||
const nsACString& aServerMAC);
|
||||
nsresult FinishHMAC();
|
||||
|
||||
void SetCurrentTable(const nsACString& aTable);
|
||||
|
||||
nsresult Begin();
|
||||
@ -49,15 +44,13 @@ public:
|
||||
const nsTArray<ForwardedUpdate> &Forwards() const { return mForwards; }
|
||||
int32_t UpdateWait() { return mUpdateWait; }
|
||||
bool ResetRequested() { return mResetRequested; }
|
||||
bool RekeyRequested() { return mRekeyRequested; }
|
||||
|
||||
private:
|
||||
nsresult ProcessControl(bool* aDone);
|
||||
nsresult ProcessMAC(const nsCString& aLine);
|
||||
nsresult ProcessExpirations(const nsCString& aLine);
|
||||
nsresult ProcessChunkControl(const nsCString& aLine);
|
||||
nsresult ProcessForward(const nsCString& aLine);
|
||||
nsresult AddForward(const nsACString& aUrl, const nsACString& aMac);
|
||||
nsresult AddForward(const nsACString& aUrl);
|
||||
nsresult ProcessChunk(bool* done);
|
||||
// Remove this, it's only used for testing
|
||||
nsresult ProcessPlaintextChunk(const nsACString& aChunk);
|
||||
@ -110,12 +103,8 @@ private:
|
||||
nsresult mUpdateStatus;
|
||||
nsCString mPending;
|
||||
|
||||
nsCOMPtr<nsICryptoHMAC> mHMAC;
|
||||
nsCString mServerMAC;
|
||||
|
||||
uint32_t mUpdateWait;
|
||||
bool mResetRequested;
|
||||
bool mRekeyRequested;
|
||||
|
||||
nsTArray<ForwardedUpdate> mForwards;
|
||||
// Keep track of updates to apply before passing them to the DBServiceWorkers.
|
||||
|
@ -59,7 +59,6 @@ this.SafeBrowsing = {
|
||||
malwareEnabled: false,
|
||||
|
||||
updateURL: null,
|
||||
keyURL: null,
|
||||
gethashURL: null,
|
||||
|
||||
reportURL: null,
|
||||
@ -111,21 +110,15 @@ this.SafeBrowsing = {
|
||||
|
||||
// Urls used to update DB
|
||||
this.updateURL = Services.urlFormatter.formatURLPref(basePref + "updateURL");
|
||||
this.keyURL = Services.urlFormatter.formatURLPref(basePref + "keyURL");
|
||||
this.gethashURL = Services.urlFormatter.formatURLPref(basePref + "gethashURL");
|
||||
|
||||
this.updateURL = this.updateURL.replace("SAFEBROWSING_ID", clientID);
|
||||
this.keyURL = this.keyURL.replace("SAFEBROWSING_ID", clientID);
|
||||
this.gethashURL = this.gethashURL.replace("SAFEBROWSING_ID", clientID);
|
||||
|
||||
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
|
||||
getService(Ci.nsIUrlListManager);
|
||||
|
||||
listManager.setUpdateUrl(this.updateURL);
|
||||
// XXX Bug 779317 - setKeyUrl has the side effect of fetching a key from the server.
|
||||
// This shouldn't happen if anti-phishing/anti-malware is disabled.
|
||||
if (this.phishingEnabled || this.malwareEnabled)
|
||||
listManager.setKeyUrl(this.keyURL);
|
||||
listManager.setGethashUrl(this.gethashURL);
|
||||
},
|
||||
|
||||
|
@ -47,16 +47,6 @@ function PROT_ListManager() {
|
||||
BindToObject(this.shutdown_, this),
|
||||
true /*only once*/);
|
||||
|
||||
// Lazily create the key manager (to avoid fetching keys when they
|
||||
// aren't needed).
|
||||
this.keyManager_ = null;
|
||||
|
||||
this.rekeyObserver_ = new G_ObserverServiceObserver(
|
||||
'url-classifier-rekey-requested',
|
||||
BindToObject(this.rekey_, this),
|
||||
false);
|
||||
this.updateWaitingForKey_ = false;
|
||||
|
||||
this.cookieObserver_ = new G_ObserverServiceObserver(
|
||||
'cookie-changed',
|
||||
BindToObject(this.cookieChanged_, this),
|
||||
@ -85,10 +75,6 @@ function PROT_ListManager() {
|
||||
* Delete all of our data tables which seem to leak otherwise.
|
||||
*/
|
||||
PROT_ListManager.prototype.shutdown_ = function() {
|
||||
if (this.keyManager_) {
|
||||
this.keyManager_.shutdown();
|
||||
}
|
||||
|
||||
for (var name in this.tablesData) {
|
||||
delete this.tablesData[name];
|
||||
}
|
||||
@ -127,23 +113,6 @@ PROT_ListManager.prototype.setGethashUrl = function(url) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the crypto key url.
|
||||
* @param url String
|
||||
*/
|
||||
PROT_ListManager.prototype.setKeyUrl = function(url) {
|
||||
G_Debug(this, "Set key url: " + url);
|
||||
if (!this.keyManager_) {
|
||||
this.keyManager_ = new PROT_UrlCryptoKeyManager();
|
||||
this.keyManager_.onNewKey(BindToObject(this.newKey_, this));
|
||||
|
||||
this.hashCompleter_.setKeys(this.keyManager_.getClientKey(),
|
||||
this.keyManager_.getWrappedKey());
|
||||
}
|
||||
|
||||
this.keyManager_.setKeyUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new table table
|
||||
* @param tableName - the name of the table
|
||||
@ -362,27 +331,6 @@ PROT_ListManager.prototype.checkForUpdates = function() {
|
||||
* tablename;<chunk ranges>\n
|
||||
*/
|
||||
PROT_ListManager.prototype.makeUpdateRequest_ = function(tableData) {
|
||||
if (!this.keyManager_)
|
||||
return;
|
||||
|
||||
if (!this.keyManager_.hasKey()) {
|
||||
// We don't have a client key yet. Schedule a rekey, and rerequest
|
||||
// when we have one.
|
||||
|
||||
// If there's already an update waiting for a new key, don't bother.
|
||||
if (this.updateWaitingForKey_)
|
||||
return;
|
||||
|
||||
// If maybeReKey() returns false we have asked for too many keys,
|
||||
// and won't be getting a new one. Since we don't want to do
|
||||
// updates without a client key, we'll skip this update if maybeReKey()
|
||||
// fails.
|
||||
if (this.keyManager_.maybeReKey())
|
||||
this.updateWaitingForKey_ = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var tableList;
|
||||
var tableNames = {};
|
||||
for (var tableName in this.tablesData) {
|
||||
@ -403,7 +351,7 @@ PROT_ListManager.prototype.makeUpdateRequest_ = function(tableData) {
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var fields = lines[i].split(";");
|
||||
if (tableNames[fields[0]]) {
|
||||
request += lines[i] + ":mac\n";
|
||||
request += lines[i] + "\n";
|
||||
delete tableNames[fields[0]];
|
||||
}
|
||||
}
|
||||
@ -411,15 +359,14 @@ PROT_ListManager.prototype.makeUpdateRequest_ = function(tableData) {
|
||||
// For each requested table that didn't have chunk data in the database,
|
||||
// request it fresh
|
||||
for (var tableName in tableNames) {
|
||||
request += tableName + ";mac\n";
|
||||
request += tableName + "\n";
|
||||
}
|
||||
|
||||
G_Debug(this, 'checkForUpdates: scheduling request..');
|
||||
var streamer = Cc["@mozilla.org/url-classifier/streamupdater;1"]
|
||||
.getService(Ci.nsIUrlClassifierStreamUpdater);
|
||||
try {
|
||||
streamer.updateUrl = this.updateserverURL_ +
|
||||
"&wrkey=" + this.keyManager_.getWrappedKey();
|
||||
streamer.updateUrl = this.updateserverURL_;
|
||||
} catch (e) {
|
||||
G_Debug(this, 'invalid url');
|
||||
return;
|
||||
@ -429,7 +376,6 @@ PROT_ListManager.prototype.makeUpdateRequest_ = function(tableData) {
|
||||
|
||||
if (!streamer.downloadUpdates(tableList,
|
||||
request,
|
||||
this.keyManager_.getClientKey(),
|
||||
BindToObject(this.updateSuccess_, this),
|
||||
BindToObject(this.updateError_, this),
|
||||
BindToObject(this.downloadError_, this))) {
|
||||
@ -488,43 +434,13 @@ PROT_ListManager.prototype.downloadError_ = function(status) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when either the update process or a gethash request signals
|
||||
* that the server requested a rekey.
|
||||
*/
|
||||
PROT_ListManager.prototype.rekey_ = function() {
|
||||
G_Debug(this, "rekey requested");
|
||||
|
||||
// The current key is no good anymore.
|
||||
this.keyManager_.dropKey();
|
||||
this.keyManager_.maybeReKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when cookies are cleared - clears the current MAC keys.
|
||||
* Called when cookies are cleared
|
||||
*/
|
||||
PROT_ListManager.prototype.cookieChanged_ = function(subject, topic, data) {
|
||||
if (data != "cleared")
|
||||
return;
|
||||
|
||||
G_Debug(this, "cookies cleared");
|
||||
this.keyManager_.dropKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we've received a new key from the server.
|
||||
*/
|
||||
PROT_ListManager.prototype.newKey_ = function() {
|
||||
G_Debug(this, "got a new MAC key");
|
||||
|
||||
this.hashCompleter_.setKeys(this.keyManager_.getClientKey(),
|
||||
this.keyManager_.getWrappedKey());
|
||||
|
||||
if (this.keyManager_.hasKey()) {
|
||||
if (this.updateWaitingForKey_) {
|
||||
this.updateWaitingForKey_ = false;
|
||||
this.checkForUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROT_ListManager.prototype.QueryInterface = function(iid) {
|
||||
|
@ -1,386 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
|
||||
// This file implements the tricky business of managing the keys for our
|
||||
// URL encryption. The protocol is:
|
||||
//
|
||||
// - Server generates secret key K_S
|
||||
// - Client starts up and requests a new key K_C from the server via HTTPS
|
||||
// - Server generates K_C and WrappedKey, which is K_C encrypted with K_S
|
||||
// - Server resonse with K_C and WrappedKey
|
||||
// - When client wants to encrypt a URL, it encrypts it with K_C and sends
|
||||
// the encrypted URL along with WrappedKey
|
||||
// - Server decrypts WrappedKey with K_S to get K_C, and the URL with K_C
|
||||
//
|
||||
// This is, however, trickier than it sounds for two reasons. First,
|
||||
// we want to keep the number of HTTPS requests to an aboslute minimum
|
||||
// (like 1 or 2 per browser session). Second, the HTTPS request at
|
||||
// startup might fail, for example the user might be offline or a URL
|
||||
// fetch might need to be issued before the HTTPS request has
|
||||
// completed.
|
||||
//
|
||||
// We implement the following policy:
|
||||
//
|
||||
// - Firefox will issue at most two HTTPS getkey requests per session
|
||||
// - Firefox will issue one HTTPS getkey request at startup if more than 24
|
||||
// hours has passed since the last getkey request.
|
||||
// - Firefox will serialize to disk any key it gets
|
||||
// - Firefox will fall back on this serialized key until it has a
|
||||
// fresh key
|
||||
// - The front-end can respond with a flag in a lookup request that tells
|
||||
// the client to re-key. Firefox will issue a new HTTPS getkey request
|
||||
// at this time if it has only issued one before
|
||||
|
||||
// We store the user key in this file. The key can be used to verify signed
|
||||
// server updates.
|
||||
const kKeyFilename = "urlclassifierkey3.txt";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
/**
|
||||
* A key manager for UrlCrypto. There should be exactly one of these
|
||||
* per appplication, and all UrlCrypto's should share it. This is
|
||||
* currently implemented by having the manager attach itself to the
|
||||
* UrlCrypto's prototype at startup. We could've opted for a global
|
||||
* instead, but I like this better, even though it is spooky action
|
||||
* at a distance.
|
||||
* XXX: Should be an XPCOM service
|
||||
*
|
||||
* @param opt_keyFilename String containing the name of the
|
||||
* file we should serialize keys to/from. Used
|
||||
* mostly for testing.
|
||||
*
|
||||
* @param opt_testing Boolean indicating whether we are testing. If we
|
||||
* are, then we skip trying to read the old key from
|
||||
* file and automatically trying to rekey; presumably
|
||||
* the tester will drive these manually.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function PROT_UrlCryptoKeyManager(opt_keyFilename, opt_testing) {
|
||||
this.debugZone = "urlcryptokeymanager";
|
||||
this.testing_ = !!opt_testing;
|
||||
this.clientKey_ = null; // Base64-encoded, as fetched from server
|
||||
this.clientKeyArray_ = null; // Base64-decoded into an array of numbers
|
||||
this.wrappedKey_ = null; // Opaque websafe base64-encoded server key
|
||||
this.rekeyTries_ = 0;
|
||||
this.updating_ = false;
|
||||
|
||||
// Don't do anything until keyUrl_ is set.
|
||||
this.keyUrl_ = null;
|
||||
|
||||
this.keyFilename_ = opt_keyFilename ?
|
||||
opt_keyFilename : kKeyFilename;
|
||||
|
||||
this.onNewKey_ = null;
|
||||
|
||||
// Convenience properties
|
||||
this.MAX_REKEY_TRIES = PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES;
|
||||
this.CLIENT_KEY_NAME = PROT_UrlCryptoKeyManager.CLIENT_KEY_NAME;
|
||||
this.WRAPPED_KEY_NAME = PROT_UrlCryptoKeyManager.WRAPPED_KEY_NAME;
|
||||
|
||||
if (!this.testing_) {
|
||||
this.maybeLoadOldKey();
|
||||
}
|
||||
}
|
||||
|
||||
// Do ***** NOT ***** set this higher; HTTPS is expensive
|
||||
PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES = 2;
|
||||
|
||||
// Base pref for keeping track of when we updated our key.
|
||||
// We store the time as seconds since the epoch.
|
||||
PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF = "urlclassifier.keyupdatetime.";
|
||||
|
||||
// Once every 30 days (interval in seconds)
|
||||
PROT_UrlCryptoKeyManager.KEY_MIN_UPDATE_TIME = 30 * 24 * 60 * 60;
|
||||
|
||||
// These are the names the server will respond with in protocol4 format
|
||||
PROT_UrlCryptoKeyManager.CLIENT_KEY_NAME = "clientkey";
|
||||
PROT_UrlCryptoKeyManager.WRAPPED_KEY_NAME = "wrappedkey";
|
||||
|
||||
/**
|
||||
* Called to get ClientKey
|
||||
* @returns urlsafe-base64-encoded client key or null if we haven't gotten one.
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.getClientKey = function() {
|
||||
return this.clientKey_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a UrlCrypto to get the current K_C
|
||||
*
|
||||
* @returns Array of numbers making up the client key or null if we
|
||||
* have no key
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.getClientKeyArray = function() {
|
||||
return this.clientKeyArray_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a UrlCrypto to get WrappedKey
|
||||
*
|
||||
* @returns Opaque base64-encoded WrappedKey or null if we haven't
|
||||
* gotten one
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.getWrappedKey = function() {
|
||||
return this.wrappedKey_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the key url. When we do this, we go ahead and rekey.
|
||||
* @param keyUrl String
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.setKeyUrl = function(keyUrl) {
|
||||
// If it's the same key url, do nothing.
|
||||
if (keyUrl == this.keyUrl_)
|
||||
return;
|
||||
|
||||
this.keyUrl_ = keyUrl;
|
||||
this.rekeyTries_ = 0;
|
||||
|
||||
// Check to see if we should make a new getkey request.
|
||||
var prefs = new G_Preferences(PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF);
|
||||
var nextRekey = prefs.getPref(this.getPrefName_(this.keyUrl_), 0);
|
||||
if (nextRekey < parseInt(Date.now() / 1000, 10)) {
|
||||
this.reKey();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a url, return the pref value to use (pref contains last update time).
|
||||
* We basically use the url up until query parameters. This avoids duplicate
|
||||
* pref entries as version number changes over time.
|
||||
* @param url String getkey URL
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.getPrefName_ = function(url) {
|
||||
var queryParam = url.indexOf("?");
|
||||
if (queryParam != -1) {
|
||||
return url.substring(0, queryParam);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the manager to re-key. For safety, this method still obeys the
|
||||
* max-tries limit. Clients should generally use maybeReKey() if they
|
||||
* want to try a re-keying: it's an error to call reKey() after we've
|
||||
* hit max-tries, but not an error to call maybeReKey().
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.reKey = function() {
|
||||
if (this.updating_) {
|
||||
G_Debug(this, "Already re-keying, ignoring this request");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.rekeyTries_ > this.MAX_REKEY_TRIES)
|
||||
throw new Error("Have already rekeyed " + this.rekeyTries_ + " times");
|
||||
|
||||
this.rekeyTries_++;
|
||||
|
||||
G_Debug(this, "Attempting to re-key");
|
||||
// If the keyUrl isn't set, we don't do anything.
|
||||
if (!this.testing_ && this.keyUrl_) {
|
||||
this.fetcher_ = new PROT_XMLFetcher();
|
||||
this.fetcher_.get(this.keyUrl_, BindToObject(this.onGetKeyResponse, this));
|
||||
this.updating_ = true;
|
||||
|
||||
// Calculate the next time we're allowed to re-key.
|
||||
var prefs = new G_Preferences(PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF);
|
||||
var nextRekey = parseInt(Date.now() / 1000, 10)
|
||||
+ PROT_UrlCryptoKeyManager.KEY_MIN_UPDATE_TIME;
|
||||
prefs.setPref(this.getPrefName_(this.keyUrl_), nextRekey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to re-key if we haven't already hit our limit. It's OK to call
|
||||
* this method multiple times, even if we've already tried to rekey
|
||||
* more than the max. It will simply refuse to do so.
|
||||
*
|
||||
* @returns Boolean indicating if it actually issued a rekey request (that
|
||||
* is, if we haven' already hit the max)
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.maybeReKey = function() {
|
||||
if (this.rekeyTries_ > this.MAX_REKEY_TRIES) {
|
||||
G_Debug(this, "Not re-keying; already at max");
|
||||
return false;
|
||||
}
|
||||
|
||||
this.reKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the existing set of keys. Resets the rekeyTries variable to
|
||||
* allow a rekey to succeed.
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.dropKey = function() {
|
||||
this.rekeyTries_ = 0;
|
||||
this.replaceKey_(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Boolean indicating if we have a key we can use
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.hasKey = function() {
|
||||
return this.clientKey_ != null && this.wrappedKey_ != null;
|
||||
}
|
||||
|
||||
PROT_UrlCryptoKeyManager.prototype.unUrlSafe = function(key)
|
||||
{
|
||||
return key ? key.replace(/-/g, "+").replace(/_/g, "/") : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new key and serialize it to disk.
|
||||
*
|
||||
* @param clientKey String containing the base64-encoded client key
|
||||
* we wish to use
|
||||
*
|
||||
* @param wrappedKey String containing the opaque base64-encoded WrappedKey
|
||||
* the server gave us (i.e., K_C encrypted with K_S)
|
||||
*
|
||||
* @returns Promise of a boolean indicating whether we succeeded in replacing
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.replaceKey_ = function(clientKey,
|
||||
wrappedKey) {
|
||||
if (this.clientKey_)
|
||||
G_Debug(this, "Replacing " + this.clientKey_ + " with " + clientKey);
|
||||
|
||||
this.clientKey_ = clientKey;
|
||||
this.clientKeyArray_ = Array.map(atob(this.unUrlSafe(clientKey)),
|
||||
function(c) { return c.charCodeAt(0); });
|
||||
this.wrappedKey_ = wrappedKey;
|
||||
|
||||
let promise = this.serializeKey_(this.clientKey_, this.wrappedKey_);
|
||||
|
||||
return promise.then(() => {
|
||||
if (this.onNewKey_) {
|
||||
this.onNewKey_();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to write the key to disk so we can fall back on it. Fail
|
||||
* silently if we cannot. The keys are serialized in protocol4 format.
|
||||
*
|
||||
* @returns Promise of a boolean indicating whether we succeeded in serializing
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.serializeKey_ = function() {
|
||||
|
||||
var map = {};
|
||||
map[this.CLIENT_KEY_NAME] = this.clientKey_;
|
||||
map[this.WRAPPED_KEY_NAME] = this.wrappedKey_;
|
||||
|
||||
let keypath = OS.Path.join(OS.Constants.Path.profileDir, this.keyFilename_);
|
||||
|
||||
// if we have an invalid client key or wrapped key, we remove the
|
||||
// invalid keyfile from disk
|
||||
if (!this.clientKey_ || !this.wrappedKey_) {
|
||||
return OS.File.remove(keypath).then(() => false,
|
||||
e => {
|
||||
if (!e.becauseNoSuchFile)
|
||||
throw e;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
let data = (new G_Protocol4Parser()).serialize(map);
|
||||
|
||||
let encoder = new TextEncoder();
|
||||
let array = encoder.encode(data);
|
||||
let promise = OS.File.writeAtomic(keypath, array, { tmpPath: keypath + ".tmp",
|
||||
flush: false });
|
||||
return promise.then(() => true,
|
||||
e => {
|
||||
G_Error(this, "Failed to serialize new key: " + e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when we've received a protocol4 response to our getkey
|
||||
* request. Try to parse it and set this key as the new one if we can.
|
||||
*
|
||||
* @param responseText String containing the protocol4 getkey response
|
||||
*
|
||||
* @returns Promise of a boolean indicating whether we succeeded in setting
|
||||
* the new key
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.onGetKeyResponse = function(responseText) {
|
||||
|
||||
var response = (new G_Protocol4Parser).parse(responseText);
|
||||
var clientKey = response[this.CLIENT_KEY_NAME];
|
||||
var wrappedKey = response[this.WRAPPED_KEY_NAME];
|
||||
|
||||
this.updating_ = false;
|
||||
this.fetcher_ = null;
|
||||
|
||||
if (response && clientKey && wrappedKey) {
|
||||
G_Debug(this, "Got new key from: " + responseText);
|
||||
return this.replaceKey_(clientKey, wrappedKey);
|
||||
} else {
|
||||
G_Debug(this, "Not a valid response for /newkey");
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the callback to be called whenever we get a new key.
|
||||
*
|
||||
* @param callback The callback.
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.onNewKey = function(callback)
|
||||
{
|
||||
this.onNewKey_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to read a key we've previously serialized from disk, so
|
||||
* that we can fall back on it in case we can't get one from the
|
||||
* server. If we get a key, only use it if we don't already have one
|
||||
* (i.e., if our startup HTTPS request died or hasn't yet completed).
|
||||
*
|
||||
* This method should be invoked early, like when the user's profile
|
||||
* becomes available.
|
||||
*
|
||||
* @returns Promise of a boolean indicating whether we succeeded in
|
||||
* loading old key
|
||||
*/
|
||||
PROT_UrlCryptoKeyManager.prototype.maybeLoadOldKey = function() {
|
||||
let keypath = OS.Path.join(OS.Constants.Path.profileDir, this.keyFilename_);
|
||||
|
||||
let decoder = new TextDecoder();
|
||||
let promise = OS.File.read(keypath);
|
||||
return promise.then(array => {
|
||||
let oldKey = decoder.decode(array);
|
||||
if (!oldKey) {
|
||||
G_Debug(this, "Couldn't find old key.");
|
||||
return false;
|
||||
}
|
||||
|
||||
oldKey = (new G_Protocol4Parser).parse(oldKey);
|
||||
var clientKey = oldKey[this.CLIENT_KEY_NAME];
|
||||
var wrappedKey = oldKey[this.WRAPPED_KEY_NAME];
|
||||
|
||||
if (oldKey && clientKey && wrappedKey && !this.hasKey()) {
|
||||
G_Debug(this, "Read old key from disk.");
|
||||
return this.replaceKey_(clientKey, wrappedKey);
|
||||
}
|
||||
}, e => {
|
||||
G_Debug(this, "Caught " + e + " trying to read keyfile");
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
PROT_UrlCryptoKeyManager.prototype.shutdown = function() {
|
||||
if (this.fetcher_) {
|
||||
this.fetcher_.cancel();
|
||||
this.fetcher_ = null;
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ interface nsIUrlClassifierCallback : nsISupports {
|
||||
* clients streaming updates to the url-classifier (usually
|
||||
* nsUrlClassifierStreamUpdater.
|
||||
*/
|
||||
[scriptable, uuid(bbb33c65-e783-476c-8db0-6ddb91826c07)]
|
||||
[scriptable, uuid(9fa11561-5816-4e1b-bcc9-b629ca05cce6)]
|
||||
interface nsIUrlClassifierUpdateObserver : nsISupports {
|
||||
/**
|
||||
* The update requested a new URL whose contents should be downloaded
|
||||
@ -36,18 +36,9 @@ interface nsIUrlClassifierUpdateObserver : nsISupports {
|
||||
* @param url The url that was requested.
|
||||
* @param table The table name that this URL's contents will be associated
|
||||
* with. This should be passed back to beginStream().
|
||||
* @param serverMAC The server-supplied MAC of the data at this URL. This
|
||||
* should be passed back to beginStream().
|
||||
*/
|
||||
void updateUrlRequested(in ACString url,
|
||||
in ACString table,
|
||||
in ACString serverMAC);
|
||||
|
||||
/**
|
||||
* The server has requested that the client get a new client key for
|
||||
* MAC requests.
|
||||
*/
|
||||
void rekeyRequested();
|
||||
in ACString table);
|
||||
|
||||
/**
|
||||
* A stream update has completed.
|
||||
@ -75,7 +66,7 @@ interface nsIUrlClassifierUpdateObserver : nsISupports {
|
||||
* It provides async methods for querying and updating the database. As the
|
||||
* methods complete, they call the callback function.
|
||||
*/
|
||||
[scriptable, uuid(e326ec41-46fd-4127-ad3c-3c58b2cdf196)]
|
||||
[scriptable, uuid(8a389f21-f821-4e29-9c6b-3de6f33cd7cf)]
|
||||
interface nsIUrlClassifierDBService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -134,12 +125,9 @@ interface nsIUrlClassifierDBService : nsISupports
|
||||
*
|
||||
* @param updater The update observer tied to this update.
|
||||
* @param tables A comma-separated list of tables included in this update.
|
||||
* @param clientKey The client key for calculating an update's MAC,
|
||||
* or empty to ignore MAC.
|
||||
*/
|
||||
void beginUpdate(in nsIUrlClassifierUpdateObserver updater,
|
||||
in ACString tables,
|
||||
in ACString clientKey);
|
||||
in ACString tables);
|
||||
|
||||
/**
|
||||
* Begin a stream update. This should be called once per url being
|
||||
@ -147,12 +135,8 @@ interface nsIUrlClassifierDBService : nsISupports
|
||||
*
|
||||
* @param table The table the contents of this stream will be associated
|
||||
* with, or empty for the initial stream.
|
||||
* @param serverMAC The MAC specified by the update server for this stream.
|
||||
* If the server has not specified a MAC (which is the case
|
||||
* for the initial stream), this will be empty.
|
||||
*/
|
||||
void beginStream(in ACString table,
|
||||
in ACString serverMAC);
|
||||
void beginStream(in ACString table);
|
||||
|
||||
/**
|
||||
* Update the table incrementally.
|
||||
|
@ -7,7 +7,7 @@
|
||||
/**
|
||||
* This interface is implemented by nsIUrlClassifierHashCompleter clients.
|
||||
*/
|
||||
[scriptable, uuid(bbd6c954-7cb4-4447-bc55-8cefd1ceed89)]
|
||||
[scriptable, uuid(da16de40-df26-414d-bde7-c4faf4504868)]
|
||||
interface nsIUrlClassifierHashCompleterCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -21,13 +21,10 @@ interface nsIUrlClassifierHashCompleterCallback : nsISupports
|
||||
* The name of the table that this hash belongs to.
|
||||
* @param chunkId
|
||||
* The database chunk that this hash belongs to.
|
||||
* @param trusted
|
||||
* The completion was verified with a MAC and can be cached.
|
||||
*/
|
||||
void completion(in ACString hash,
|
||||
in ACString table,
|
||||
in uint32_t chunkId,
|
||||
in boolean trusted);
|
||||
in uint32_t chunkId);
|
||||
|
||||
/**
|
||||
* The completion is complete. This method is called once per
|
||||
@ -62,12 +59,6 @@ interface nsIUrlClassifierHashCompleter : nsISupports
|
||||
*/
|
||||
void complete(in ACString partialHash,
|
||||
in nsIUrlClassifierHashCompleterCallback callback);
|
||||
|
||||
/**
|
||||
* Set the client and wrapped key for verified updates.
|
||||
*/
|
||||
void setKeys(in ACString clientKey, in ACString wrappedKey);
|
||||
|
||||
/**
|
||||
* The URL for the gethash request
|
||||
*/
|
||||
|
@ -11,7 +11,7 @@
|
||||
* downloading the whole update and then updating the sqlite database, we
|
||||
* update tables as the data is streaming in.
|
||||
*/
|
||||
[scriptable, uuid(daf3038a-556c-47d3-a3d2-36caa9a762a0)]
|
||||
[scriptable, uuid(79e6b710-ce68-4639-ac6b-7d293af424a1)]
|
||||
interface nsIUrlClassifierStreamUpdater : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -27,7 +27,6 @@ interface nsIUrlClassifierStreamUpdater : nsISupports
|
||||
* @param aRequestTables Comma-separated list of tables included in this
|
||||
* update.
|
||||
* @param aRequestBody The body for the request.
|
||||
* @param aClientKey The client key for checking the update's MAC.
|
||||
* @param aSuccessCallback Called after a successful update.
|
||||
* @param aUpdateErrorCallback Called for problems applying the update
|
||||
* @param aDownloadErrorCallback Called if we get an http error or a
|
||||
@ -35,7 +34,6 @@ interface nsIUrlClassifierStreamUpdater : nsISupports
|
||||
*/
|
||||
boolean downloadUpdates(in ACString aRequestTables,
|
||||
in ACString aRequestBody,
|
||||
in ACString aClientKey,
|
||||
in nsIUrlClassifierCallback aSuccessCallback,
|
||||
in nsIUrlClassifierCallback aUpdateErrorCallback,
|
||||
in nsIUrlClassifierCallback aDownloadErrorCallback);
|
||||
|
@ -18,7 +18,7 @@ interface nsIUrlListManagerCallback : nsISupports {
|
||||
};
|
||||
|
||||
|
||||
[scriptable, uuid(5b4645b6-f9ca-4cb1-a821-2bdb3c3902f8)]
|
||||
[scriptable, uuid(62484bb5-bf7e-4988-9055-8803b16b48a1)]
|
||||
interface nsIUrlListManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -26,12 +26,6 @@ interface nsIUrlListManager : nsISupports
|
||||
*/
|
||||
void setUpdateUrl(in ACString url);
|
||||
|
||||
/**
|
||||
* Set the URL we use to get keys used to decrypt URLs in
|
||||
* enchash tables.
|
||||
*/
|
||||
void setKeyUrl(in ACString url);
|
||||
|
||||
/**
|
||||
* Set the URL that we will query for complete hashes after a partial
|
||||
* hash match.
|
||||
@ -43,8 +37,7 @@ interface nsIUrlListManager : nsISupports
|
||||
* string of the format provider_name-semantic_type-table_type. For
|
||||
* example, goog-white-enchash or goog-black-url.
|
||||
*/
|
||||
boolean registerTable(in ACString tableName,
|
||||
in boolean requireMac);
|
||||
boolean registerTable(in ACString tableName);
|
||||
|
||||
/**
|
||||
* Turn on update checking for a table. I.e., during the next server
|
||||
|
@ -181,9 +181,6 @@ private:
|
||||
nsCOMPtr<nsIUrlClassifierUpdateObserver> mUpdateObserver;
|
||||
bool mInStream;
|
||||
|
||||
// The client key with which the data from the server will be MAC'ed.
|
||||
nsCString mUpdateClientKey;
|
||||
|
||||
// The number of noise entries to add to the set of lookup results.
|
||||
uint32_t mGethashNoise;
|
||||
|
||||
@ -422,7 +419,6 @@ nsUrlClassifierDBServiceWorker::ResetUpdate()
|
||||
mUpdateWait = 0;
|
||||
mUpdateStatus = NS_OK;
|
||||
mUpdateObserver = nullptr;
|
||||
mUpdateClientKey.Truncate();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -434,8 +430,7 @@ nsUrlClassifierDBServiceWorker::SetHashCompleter(const nsACString &tableName,
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBServiceWorker::BeginUpdate(nsIUrlClassifierUpdateObserver *observer,
|
||||
const nsACString &tables,
|
||||
const nsACString &clientKey)
|
||||
const nsACString &tables)
|
||||
{
|
||||
LOG(("nsUrlClassifierDBServiceWorker::BeginUpdate [%s]", PromiseFlatCString(tables).get()));
|
||||
|
||||
@ -454,19 +449,12 @@ nsUrlClassifierDBServiceWorker::BeginUpdate(nsIUrlClassifierUpdateObserver *obse
|
||||
mUpdateObserver = observer;
|
||||
SplitTables(tables, mUpdateTables);
|
||||
|
||||
if (!clientKey.IsEmpty()) {
|
||||
rv = nsUrlClassifierUtils::DecodeClientKey(clientKey, mUpdateClientKey);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
LOG(("clientKey present, marking update key"));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Called from the stream updater.
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table,
|
||||
const nsACString &serverMAC)
|
||||
nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table)
|
||||
{
|
||||
LOG(("nsUrlClassifierDBServiceWorker::BeginStream"));
|
||||
|
||||
@ -486,17 +474,6 @@ nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table,
|
||||
|
||||
mProtocolParser->Init(mCryptoHash);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// If we're expecting a MAC, create the nsICryptoHMAC component now.
|
||||
if (!mUpdateClientKey.IsEmpty()) {
|
||||
LOG(("Expecting MAC in this stream"));
|
||||
rv = mProtocolParser->InitHMAC(mUpdateClientKey, serverMAC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
LOG(("No MAC in this stream"));
|
||||
}
|
||||
|
||||
if (!table.IsEmpty()) {
|
||||
mProtocolParser->SetCurrentTable(table);
|
||||
}
|
||||
@ -560,7 +537,6 @@ nsUrlClassifierDBServiceWorker::FinishStream()
|
||||
|
||||
mInStream = false;
|
||||
|
||||
mProtocolParser->FinishHMAC();
|
||||
if (NS_SUCCEEDED(mProtocolParser->Status())) {
|
||||
if (mProtocolParser->UpdateWait()) {
|
||||
mUpdateWait = mProtocolParser->UpdateWait();
|
||||
@ -570,7 +546,7 @@ nsUrlClassifierDBServiceWorker::FinishStream()
|
||||
mProtocolParser->Forwards();
|
||||
for (uint32_t i = 0; i < forwards.Length(); i++) {
|
||||
const ProtocolParser::ForwardedUpdate &forward = forwards[i];
|
||||
mUpdateObserver->UpdateUrlRequested(forward.url, forward.table, forward.mac);
|
||||
mUpdateObserver->UpdateUrlRequested(forward.url, forward.table);
|
||||
}
|
||||
// Hold on to any TableUpdate objects that were created by the
|
||||
// parser.
|
||||
@ -581,18 +557,12 @@ nsUrlClassifierDBServiceWorker::FinishStream()
|
||||
}
|
||||
mUpdateObserver->StreamFinished(mProtocolParser->Status(), 0);
|
||||
|
||||
// Only reset if MAC was OK
|
||||
if (NS_SUCCEEDED(mUpdateStatus)) {
|
||||
if (mProtocolParser->ResetRequested()) {
|
||||
mClassifier->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Rekey will cause update to fail (can't check MACs)
|
||||
if (mProtocolParser->RekeyRequested()) {
|
||||
mUpdateObserver->RekeyRequested();
|
||||
}
|
||||
|
||||
mProtocolParser = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
@ -908,11 +878,10 @@ nsUrlClassifierLookupCallback::CompletionFinished(nsresult status)
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierLookupCallback::Completion(const nsACString& completeHash,
|
||||
const nsACString& tableName,
|
||||
uint32_t chunkId,
|
||||
bool verified)
|
||||
uint32_t chunkId)
|
||||
{
|
||||
LOG(("nsUrlClassifierLookupCallback::Completion [%p, %s, %d, %d]",
|
||||
this, PromiseFlatCString(tableName).get(), chunkId, verified));
|
||||
LOG(("nsUrlClassifierLookupCallback::Completion [%p, %s, %d]",
|
||||
this, PromiseFlatCString(tableName).get(), chunkId));
|
||||
mozilla::safebrowsing::Completion hash;
|
||||
hash.Assign(completeHash);
|
||||
|
||||
@ -923,15 +892,13 @@ nsUrlClassifierLookupCallback::Completion(const nsACString& completeHash,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (verified) {
|
||||
CacheResult result;
|
||||
result.entry.addChunk = chunkId;
|
||||
result.entry.complete = hash;
|
||||
result.table = tableName;
|
||||
CacheResult result;
|
||||
result.entry.addChunk = chunkId;
|
||||
result.entry.complete = hash;
|
||||
result.table = tableName;
|
||||
|
||||
// OK if this fails, we just won't cache the item.
|
||||
mCacheResults->AppendElement(result);
|
||||
}
|
||||
// OK if this fails, we just won't cache the item.
|
||||
mCacheResults->AppendElement(result);
|
||||
|
||||
// Check if this matched any of our results.
|
||||
for (uint32_t i = 0; i < mResults->Length(); i++) {
|
||||
@ -1329,8 +1296,7 @@ nsUrlClassifierDBService::SetHashCompleter(const nsACString &tableName,
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::BeginUpdate(nsIUrlClassifierUpdateObserver *observer,
|
||||
const nsACString &updateTables,
|
||||
const nsACString &clientKey)
|
||||
const nsACString &updateTables)
|
||||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
@ -1343,16 +1309,15 @@ nsUrlClassifierDBService::BeginUpdate(nsIUrlClassifierUpdateObserver *observer,
|
||||
nsCOMPtr<nsIUrlClassifierUpdateObserver> proxyObserver =
|
||||
new UrlClassifierUpdateObserverProxy(observer);
|
||||
|
||||
return mWorkerProxy->BeginUpdate(proxyObserver, updateTables, clientKey);
|
||||
return mWorkerProxy->BeginUpdate(proxyObserver, updateTables);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::BeginStream(const nsACString &table,
|
||||
const nsACString &serverMAC)
|
||||
nsUrlClassifierDBService::BeginStream(const nsACString &table)
|
||||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
return mWorkerProxy->BeginStream(table, serverMAC);
|
||||
return mWorkerProxy->BeginStream(table);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -30,8 +30,6 @@ const BACKOFF_TIME = 5 * 60;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let keyFactory = Cc["@mozilla.org/security/keyobjectfactory;1"]
|
||||
.getService(Ci.nsIKeyObjectFactory);
|
||||
|
||||
function HashCompleter() {
|
||||
// This is a HashCompleterRequest and is used by multiple calls to |complete|
|
||||
@ -39,13 +37,6 @@ function HashCompleter() {
|
||||
// started, this is set to null again.
|
||||
this._currentRequest = null;
|
||||
|
||||
// Key used in the HMAC process by the client to verify the request has not
|
||||
// been tampered with. It is stored as a binary blob.
|
||||
this._clientKey = "";
|
||||
// Key used in the HMAC process and sent remotely to the server in the URL
|
||||
// of the request. It is stored as a base64 string.
|
||||
this._wrappedKey = "";
|
||||
|
||||
// Whether we have been informed of a shutdown by the xpcom-shutdown event.
|
||||
this._shuttingDown = false;
|
||||
|
||||
@ -110,10 +101,6 @@ HashCompleter.prototype = {
|
||||
}
|
||||
|
||||
let url = this._getHashUrl;
|
||||
if (this._clientKey) {
|
||||
this._currentRequest.clientKey = this._clientKey;
|
||||
url += "&wrkey=" + this._wrappedKey;
|
||||
}
|
||||
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
this._currentRequest.setURI(uri);
|
||||
@ -127,32 +114,6 @@ HashCompleter.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// When a rekey has been requested, we can only clear our keys and make
|
||||
// unauthenticated requests.
|
||||
// The HashCompleter does not handle the rekeying but instead sends a
|
||||
// notification to have listeners do the work.
|
||||
rekeyRequested: function HC_rekeyRequested() {
|
||||
this.setKeys("", "");
|
||||
|
||||
Services.obs.notifyObservers(this, "url-classifier-rekey-requested", null);
|
||||
},
|
||||
|
||||
// setKeys expects clientKey and wrappedKey to be url safe, base64 strings.
|
||||
// When called with an empty client string, setKeys resets both the client
|
||||
// key and wrapped key.
|
||||
setKeys: function HC_setKeys(aClientKey, aWrappedKey) {
|
||||
if (aClientKey == "") {
|
||||
this._clientKey = "";
|
||||
this._wrappedKey = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// The decoding of clientKey was originally done by using
|
||||
// nsUrlClassifierUtils::DecodeClientKey.
|
||||
this._clientKey = atob(unUrlsafeBase64(aClientKey));
|
||||
this._wrappedKey = aWrappedKey;
|
||||
},
|
||||
|
||||
get gethashUrl() {
|
||||
return this._getHashUrl;
|
||||
},
|
||||
@ -232,14 +193,6 @@ function HashCompleterRequest(aCompleter) {
|
||||
this._channel = null;
|
||||
// Response body of hash completion. Created in onDataAvailable.
|
||||
this._response = "";
|
||||
// Client key when HMAC is used.
|
||||
this._clientKey = "";
|
||||
// Request was rescheduled, possibly due to a "e:pleaserekey" request from
|
||||
// the server.
|
||||
this._rescheduled = false;
|
||||
// Whether the request was encrypted. This is also used as the |trusted|
|
||||
// parameter to the nsIUrlClassifierHashCompleterCallback.
|
||||
this._verified = false;
|
||||
// Whether we have been informed of a shutdown by the xpcom-shutdown event.
|
||||
this._shuttingDown = false;
|
||||
}
|
||||
@ -351,73 +304,18 @@ HashCompleterRequest.prototype = {
|
||||
}
|
||||
|
||||
let start = 0;
|
||||
if (this._clientKey) {
|
||||
start = this.handleMAC(start);
|
||||
|
||||
if (this._rescheduled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let length = this._response.length;
|
||||
while (start != length)
|
||||
start = this.handleTable(start);
|
||||
},
|
||||
|
||||
// This parses and confirms that the MAC in the response matches the expected
|
||||
// value. This throws an error if the MAC does not match or otherwise, returns
|
||||
// the index after the MAC header.
|
||||
handleMAC: function HCR_handleMAC(aStart) {
|
||||
this._verified = false;
|
||||
|
||||
let body = this._response.substring(aStart);
|
||||
|
||||
// We have to deal with the index of the new line character instead of
|
||||
// splitting the string as there could be new line characters in the data
|
||||
// parts.
|
||||
let newlineIndex = body.indexOf("\n");
|
||||
if (newlineIndex == -1) {
|
||||
throw errorWithStack();
|
||||
}
|
||||
|
||||
let serverMAC = body.substring(0, newlineIndex);
|
||||
if (serverMAC == "e:pleaserekey") {
|
||||
this.rescheduleItems();
|
||||
|
||||
this._completer.rekeyRequested();
|
||||
return this._response.length;
|
||||
}
|
||||
|
||||
serverMAC = unUrlsafeBase64(serverMAC);
|
||||
|
||||
let keyObject = keyFactory.keyFromString(Ci.nsIKeyObject.HMAC,
|
||||
this._clientKey);
|
||||
|
||||
let data = body.substring(newlineIndex + 1).split("")
|
||||
.map(function(x) x.charCodeAt(0));
|
||||
|
||||
let hmac = Cc["@mozilla.org/security/hmac;1"]
|
||||
.createInstance(Ci.nsICryptoHMAC);
|
||||
hmac.init(Ci.nsICryptoHMAC.SHA1, keyObject);
|
||||
hmac.update(data, data.length);
|
||||
let clientMAC = hmac.finish(true);
|
||||
|
||||
if (clientMAC != serverMAC) {
|
||||
throw errorWithStack();
|
||||
}
|
||||
|
||||
this._verified = true;
|
||||
|
||||
return aStart + newlineIndex + 1;
|
||||
},
|
||||
|
||||
// This parses a table entry in the response body and calls |handleItem|
|
||||
// for complete hash in the table entry. Like |handleMAC|, it returns the
|
||||
// index in |_response| right after the table it parsed.
|
||||
// for complete hash in the table entry.
|
||||
handleTable: function HCR_handleTable(aStart) {
|
||||
let body = this._response.substring(aStart);
|
||||
|
||||
// Like in handleMAC, we deal with new line indexes as there could be
|
||||
// deal with new line indexes as there could be
|
||||
// new line characters in the data parts.
|
||||
let newlineIndex = body.indexOf("\n");
|
||||
if (newlineIndex == -1) {
|
||||
@ -473,7 +371,7 @@ HashCompleterRequest.prototype = {
|
||||
for (let j = 0; j < request.responses.length; j++) {
|
||||
let response = request.responses[j];
|
||||
request.callback.completion(response.completeHash, response.tableName,
|
||||
response.chunkId, this._verified);
|
||||
response.chunkId);
|
||||
}
|
||||
|
||||
request.callback.completionFinished(Cr.NS_OK);
|
||||
@ -486,23 +384,6 @@ HashCompleterRequest.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// rescheduleItems is called after a "e:pleaserekey" response. It is meant
|
||||
// to be called after |rekeyRequested| has been called as it re-calls
|
||||
// the HashCompleter with |complete| for all the items on this request.
|
||||
rescheduleItems: function HCR_rescheduleItems() {
|
||||
for (let i = 0; i < this._requests[i]; i++) {
|
||||
let request = this._requests[i];
|
||||
try {
|
||||
this._completer.complete(request.partialHash, request.callback);
|
||||
}
|
||||
catch (err) {
|
||||
request.callback.completionFinished(err);
|
||||
}
|
||||
}
|
||||
|
||||
this._rescheduled = true;
|
||||
},
|
||||
|
||||
onDataAvailable: function HCR_onDataAvailable(aRequest, aContext,
|
||||
aInputStream, aOffset, aCount) {
|
||||
let sis = Cc["@mozilla.org/scriptableinputstream;1"].
|
||||
@ -545,19 +426,13 @@ HashCompleterRequest.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._rescheduled) {
|
||||
if (success) {
|
||||
this.notifySuccess();
|
||||
} else {
|
||||
this.notifyFailure(aStatusCode);
|
||||
}
|
||||
if (success) {
|
||||
this.notifySuccess();
|
||||
} else {
|
||||
this.notifyFailure(aStatusCode);
|
||||
}
|
||||
},
|
||||
|
||||
set clientKey(aVal) {
|
||||
this._clientKey = aVal;
|
||||
},
|
||||
|
||||
observe: function HCR_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic != "xpcom-shutdown") {
|
||||
return;
|
||||
|
@ -21,7 +21,6 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
#include ./content/moz/protocol4.js
|
||||
|
||||
#include ./content/request-backoff.js
|
||||
#include ./content/url-crypto-key-manager.js
|
||||
#include ./content/xml-fetcher.js
|
||||
|
||||
// Expose this whole component.
|
||||
|
@ -24,7 +24,6 @@ function Init() {
|
||||
modScope.G_Alarm = jslib.G_Alarm;
|
||||
modScope.BindToObject = jslib.BindToObject;
|
||||
modScope.PROT_XMLFetcher = jslib.PROT_XMLFetcher;
|
||||
modScope.PROT_UrlCryptoKeyManager = jslib.PROT_UrlCryptoKeyManager;
|
||||
modScope.RequestBackoff = jslib.RequestBackoff;
|
||||
|
||||
// We only need to call Init once.
|
||||
|
@ -61,34 +61,32 @@ UrlClassifierDBServiceWorkerProxy::SetHashCompleter
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierDBServiceWorkerProxy::BeginUpdate
|
||||
(nsIUrlClassifierUpdateObserver* aUpdater,
|
||||
const nsACString& aTables,
|
||||
const nsACString& aClientKey)
|
||||
const nsACString& aTables)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = new BeginUpdateRunnable(mTarget, aUpdater,
|
||||
aTables, aClientKey);
|
||||
aTables);
|
||||
return DispatchToWorkerThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierDBServiceWorkerProxy::BeginUpdateRunnable::Run()
|
||||
{
|
||||
mTarget->BeginUpdate(mUpdater, mTables, mClientKey);
|
||||
mTarget->BeginUpdate(mUpdater, mTables);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierDBServiceWorkerProxy::BeginStream(const nsACString& aTable,
|
||||
const nsACString& aServerMAC)
|
||||
UrlClassifierDBServiceWorkerProxy::BeginStream(const nsACString& aTable)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
new BeginStreamRunnable(mTarget, aTable, aServerMAC);
|
||||
new BeginStreamRunnable(mTarget, aTable);
|
||||
return DispatchToWorkerThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierDBServiceWorkerProxy::BeginStreamRunnable::Run()
|
||||
{
|
||||
mTarget->BeginStream(mTable, mServerMAC);
|
||||
mTarget->BeginStream(mTable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -222,32 +220,17 @@ NS_IMPL_ISUPPORTS1(UrlClassifierUpdateObserverProxy,
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierUpdateObserverProxy::UpdateUrlRequested
|
||||
(const nsACString& aURL,
|
||||
const nsACString& aTable,
|
||||
const nsACString& aServerMAC)
|
||||
const nsACString& aTable)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
new UpdateUrlRequestedRunnable(mTarget, aURL, aTable, aServerMAC);
|
||||
new UpdateUrlRequestedRunnable(mTarget, aURL, aTable);
|
||||
return NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierUpdateObserverProxy::UpdateUrlRequestedRunnable::Run()
|
||||
{
|
||||
mTarget->UpdateUrlRequested(mURL, mTable, mServerMAC);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierUpdateObserverProxy::RekeyRequested()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = new RekeyRequestedRunnable(mTarget);
|
||||
return NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierUpdateObserverProxy::RekeyRequestedRunnable::Run()
|
||||
{
|
||||
mTarget->RekeyRequested();
|
||||
mTarget->UpdateUrlRequested(mURL, mTable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -69,12 +69,10 @@ public:
|
||||
public:
|
||||
BeginUpdateRunnable(nsIUrlClassifierDBServiceWorker* aTarget,
|
||||
nsIUrlClassifierUpdateObserver* aUpdater,
|
||||
const nsACString& aTables,
|
||||
const nsACString& aClientKey)
|
||||
const nsACString& aTables)
|
||||
: mTarget(aTarget)
|
||||
, mUpdater(aUpdater)
|
||||
, mTables(aTables)
|
||||
, mClientKey(aClientKey)
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
@ -82,25 +80,23 @@ public:
|
||||
private:
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> mTarget;
|
||||
nsCOMPtr<nsIUrlClassifierUpdateObserver> mUpdater;
|
||||
nsCString mTables, mClientKey;
|
||||
nsCString mTables;
|
||||
};
|
||||
|
||||
class BeginStreamRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
BeginStreamRunnable(nsIUrlClassifierDBServiceWorker* aTarget,
|
||||
const nsACString& aTable,
|
||||
const nsACString& aServerMAC)
|
||||
const nsACString& aTable)
|
||||
: mTarget(aTarget)
|
||||
, mTable(aTable)
|
||||
, mServerMAC(aServerMAC)
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> mTarget;
|
||||
nsCString mTable, mServerMAC;
|
||||
nsCString mTable;
|
||||
};
|
||||
|
||||
class UpdateStreamRunnable : public nsRunnable
|
||||
@ -234,32 +230,17 @@ public:
|
||||
public:
|
||||
UpdateUrlRequestedRunnable(const nsMainThreadPtrHandle<nsIUrlClassifierUpdateObserver>& aTarget,
|
||||
const nsACString& aURL,
|
||||
const nsACString& aTable,
|
||||
const nsACString& aServerMAC)
|
||||
const nsACString& aTable)
|
||||
: mTarget(aTarget)
|
||||
, mURL(aURL)
|
||||
, mTable(aTable)
|
||||
, mServerMAC(aServerMAC)
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<nsIUrlClassifierUpdateObserver> mTarget;
|
||||
nsCString mURL, mTable, mServerMAC;
|
||||
};
|
||||
|
||||
class RekeyRequestedRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RekeyRequestedRunnable(const nsMainThreadPtrHandle<nsIUrlClassifierUpdateObserver>& aTarget)
|
||||
: mTarget(aTarget)
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<nsIUrlClassifierUpdateObserver> mTarget;
|
||||
nsCString mURL, mTable;
|
||||
};
|
||||
|
||||
class StreamFinishedRunnable : public nsRunnable
|
||||
|
@ -101,8 +101,7 @@ nsUrlClassifierStreamUpdater::SetUpdateUrl(const nsACString & aUpdateUrl)
|
||||
nsresult
|
||||
nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
|
||||
const nsACString & aRequestBody,
|
||||
const nsACString & aStreamTable,
|
||||
const nsACString & aServerMAC)
|
||||
const nsACString & aStreamTable)
|
||||
{
|
||||
nsresult rv;
|
||||
uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
|
||||
@ -141,7 +140,6 @@ nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mStreamTable = aStreamTable;
|
||||
mServerMAC = aServerMAC;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -149,8 +147,7 @@ nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
|
||||
nsresult
|
||||
nsUrlClassifierStreamUpdater::FetchUpdate(const nsACString & aUpdateUrl,
|
||||
const nsACString & aRequestBody,
|
||||
const nsACString & aStreamTable,
|
||||
const nsACString & aServerMAC)
|
||||
const nsACString & aStreamTable)
|
||||
{
|
||||
LOG(("(pre) Fetching update from %s\n", PromiseFlatCString(aUpdateUrl).get()));
|
||||
|
||||
@ -163,14 +160,13 @@ nsUrlClassifierStreamUpdater::FetchUpdate(const nsACString & aUpdateUrl,
|
||||
|
||||
LOG(("(post) Fetching update from %s\n", urlSpec.get()));
|
||||
|
||||
return FetchUpdate(uri, aRequestBody, aStreamTable, aServerMAC);
|
||||
return FetchUpdate(uri, aRequestBody, aStreamTable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierStreamUpdater::DownloadUpdates(
|
||||
const nsACString &aRequestTables,
|
||||
const nsACString &aRequestBody,
|
||||
const nsACString &aClientKey,
|
||||
nsIUrlClassifierCallback *aSuccessCallback,
|
||||
nsIUrlClassifierCallback *aUpdateErrorCallback,
|
||||
nsIUrlClassifierCallback *aDownloadErrorCallback,
|
||||
@ -210,7 +206,7 @@ nsUrlClassifierStreamUpdater::DownloadUpdates(
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
rv = mDBService->BeginUpdate(this, aRequestTables, aClientKey);
|
||||
rv = mDBService->BeginUpdate(this, aRequestTables);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
LOG(("already updating, skipping update"));
|
||||
*_retval = false;
|
||||
@ -233,7 +229,7 @@ nsUrlClassifierStreamUpdater::DownloadUpdates(
|
||||
//LOG(("requestBody: %s", aRequestBody.Data()));
|
||||
|
||||
LOG(("Calling into FetchUpdate"));
|
||||
return FetchUpdate(mUpdateUrl, aRequestBody, EmptyCString(), EmptyCString());
|
||||
return FetchUpdate(mUpdateUrl, aRequestBody, EmptyCString());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -241,8 +237,7 @@ nsUrlClassifierStreamUpdater::DownloadUpdates(
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierStreamUpdater::UpdateUrlRequested(const nsACString &aUrl,
|
||||
const nsACString &aTable,
|
||||
const nsACString &aServerMAC)
|
||||
const nsACString &aTable)
|
||||
{
|
||||
LOG(("Queuing requested update from %s\n", PromiseFlatCString(aUrl).get()));
|
||||
|
||||
@ -261,25 +256,10 @@ nsUrlClassifierStreamUpdater::UpdateUrlRequested(const nsACString &aUrl,
|
||||
update->mUrl = NS_LITERAL_CSTRING("http://") + aUrl;
|
||||
}
|
||||
update->mTable = aTable;
|
||||
update->mServerMAC = aServerMAC;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierStreamUpdater::RekeyRequested()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (!observerService)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return observerService->NotifyObservers(static_cast<nsIUrlClassifierStreamUpdater*>(this),
|
||||
"url-classifier-rekey-requested",
|
||||
nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierStreamUpdater::FetchNext()
|
||||
{
|
||||
@ -290,7 +270,7 @@ nsUrlClassifierStreamUpdater::FetchNext()
|
||||
PendingUpdate &update = mPendingUpdates[0];
|
||||
LOG(("Fetching update url: %s\n", update.mUrl.get()));
|
||||
nsresult rv = FetchUpdate(update.mUrl, EmptyCString(),
|
||||
update.mTable, update.mServerMAC);
|
||||
update.mTable);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Error fetching update url: %s\n", update.mUrl.get()));
|
||||
// We can commit the urls that we've applied so far. This is
|
||||
@ -453,12 +433,11 @@ nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request,
|
||||
status = NS_ERROR_ABORT;
|
||||
} else if (NS_SUCCEEDED(status)) {
|
||||
mBeganStream = true;
|
||||
rv = mDBService->BeginStream(mStreamTable, mServerMAC);
|
||||
rv = mDBService->BeginStream(mStreamTable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mStreamTable.Truncate();
|
||||
mServerMAC.Truncate();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -55,13 +55,11 @@ private:
|
||||
// Fetches an update for a single table.
|
||||
nsresult FetchUpdate(nsIURI *aURI,
|
||||
const nsACString &aRequestBody,
|
||||
const nsACString &aTable,
|
||||
const nsACString &aServerMAC);
|
||||
const nsACString &aTable);
|
||||
// Dumb wrapper so we don't have to create URIs.
|
||||
nsresult FetchUpdate(const nsACString &aURI,
|
||||
const nsACString &aRequestBody,
|
||||
const nsACString &aTable,
|
||||
const nsACString &aServerMAC);
|
||||
const nsACString &aTable);
|
||||
|
||||
// Fetches the next table, from mPendingUpdates.
|
||||
nsresult FetchNext();
|
||||
@ -72,7 +70,6 @@ private:
|
||||
bool mBeganStream;
|
||||
nsCOMPtr<nsIURI> mUpdateUrl;
|
||||
nsCString mStreamTable;
|
||||
nsCString mServerMAC;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIUrlClassifierDBService> mDBService;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
@ -80,7 +77,6 @@ private:
|
||||
struct PendingUpdate {
|
||||
nsCString mUrl;
|
||||
nsCString mTable;
|
||||
nsCString mServerMAC;
|
||||
};
|
||||
nsTArray<PendingUpdate> mPendingUpdates;
|
||||
|
||||
|
@ -362,54 +362,3 @@ nsUrlClassifierUtils::ShouldURLEscape(const unsigned char c) const
|
||||
{
|
||||
return c <= 32 || c == '%' || c >=127;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsUrlClassifierUtils::UnUrlsafeBase64(nsACString &str)
|
||||
{
|
||||
nsACString::iterator iter, end;
|
||||
str.BeginWriting(iter);
|
||||
str.EndWriting(end);
|
||||
while (iter != end) {
|
||||
if (*iter == '-') {
|
||||
*iter = '+';
|
||||
} else if (*iter == '_') {
|
||||
*iter = '/';
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsUrlClassifierUtils::DecodeClientKey(const nsACString &key,
|
||||
nsACString &_retval)
|
||||
{
|
||||
// Client key is sent in urlsafe base64, we need to decode it first.
|
||||
nsAutoCString base64(key);
|
||||
UnUrlsafeBase64(base64);
|
||||
|
||||
// PL_Base64Decode doesn't null-terminate unless we let it allocate,
|
||||
// so we need to calculate the length ourselves.
|
||||
uint32_t destLength;
|
||||
destLength = base64.Length();
|
||||
if (destLength > 0 && base64[destLength - 1] == '=') {
|
||||
if (destLength > 1 && base64[destLength - 2] == '=') {
|
||||
destLength -= 2;
|
||||
} else {
|
||||
destLength -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
destLength = ((destLength * 3) / 4);
|
||||
_retval.SetLength(destLength);
|
||||
if (destLength != _retval.Length())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (!PL_Base64Decode(base64.BeginReading(), base64.Length(),
|
||||
_retval.BeginWriting())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -73,14 +73,6 @@ public:
|
||||
bool allowOctal,
|
||||
nsACString & _retval);
|
||||
|
||||
// Convert an urlsafe base64 string to a normal base64 string.
|
||||
// This method will leave an already-normal base64 string alone.
|
||||
static void UnUrlsafeBase64(nsACString & str);
|
||||
|
||||
// Takes an urlsafe-base64 encoded client key and gives back binary
|
||||
// key data
|
||||
static nsresult DecodeClientKey(const nsACString & clientKey,
|
||||
nsACString & _retval);
|
||||
private:
|
||||
// Disallow copy constructor
|
||||
nsUrlClassifierUtils(const nsUrlClassifierUtils&);
|
||||
|
Loading…
Reference in New Issue
Block a user