mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Verify downloads leveraging nsICryptoHash.
This commit is contained in:
parent
aa61ada928
commit
7e80080b48
@ -85,6 +85,9 @@ const nsIUpdateService = Components.interfaces.nsIUpdateService;
|
||||
const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
|
||||
const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString;
|
||||
const nsIIncrementalDownload = Components.interfaces.nsIIncrementalDownload;
|
||||
const nsIFileInputStream = Components.interfaces.nsIFileInputStream;
|
||||
const nsIFileOutputStream = Components.interfaces.nsIFileOutputStream;
|
||||
const nsICryptoHash = Components.interfaces.nsICryptoHash;
|
||||
|
||||
const Node = Components.interfaces.nsIDOMNode;
|
||||
|
||||
@ -103,6 +106,17 @@ function LOG(string) {
|
||||
gConsole.logStringMessage(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string containing binary values to hex.
|
||||
*/
|
||||
function binaryToHex(input) {
|
||||
var result = "";
|
||||
for (var i = 0; i < input.length; ++i) {
|
||||
result += input.charCodeAt(i).toString(16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a File URL spec for a nsIFile
|
||||
* @param file
|
||||
@ -239,7 +253,7 @@ function stripPrefix(string, prefix) {
|
||||
function writeStringToFile(file, text) {
|
||||
var fos =
|
||||
Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
createInstance(nsIFileOutputStream);
|
||||
var modeFlags = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE;
|
||||
if (!file.exists())
|
||||
file.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
@ -259,7 +273,7 @@ function writeStringToFile(file, text) {
|
||||
function readStringFromFile(file) {
|
||||
var fis =
|
||||
Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
createInstance(nsIFileInputStream);
|
||||
var modeFlags = MODE_RDONLY;
|
||||
if (!file.exists())
|
||||
return null;
|
||||
@ -780,7 +794,8 @@ Checker.prototype = {
|
||||
function Downloader() {
|
||||
}
|
||||
Downloader.prototype = {
|
||||
_request: null,
|
||||
_patch: null, // UpdatePatch
|
||||
_request: null, // nsIIncrementalDownload
|
||||
|
||||
/**
|
||||
*
|
||||
@ -825,6 +840,42 @@ Downloader.prototype = {
|
||||
return readStringFromFile(statusFile);
|
||||
},
|
||||
|
||||
/**
|
||||
* Verify the downloaded file. We assume that the download is complete at
|
||||
* this point.
|
||||
*/
|
||||
_verifyDownload: function() {
|
||||
var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(nsIFileInputStream);
|
||||
fileStream.init(this._request.destination, MODE_RDONLY, PERMS_FILE, 0);
|
||||
|
||||
try {
|
||||
var hash = Components.classes["@mozilla.org/security/hash;1"].
|
||||
createInstance(nsICryptoHash);
|
||||
const map = {
|
||||
"MD2" : nsICryptoHash.MD2,
|
||||
"MD5" : nsICryptoHash.MD5,
|
||||
"SHA1" : nsICryptoHash.SHA1,
|
||||
"SHA256" : nsICryptoHash.SHA256,
|
||||
"SHA384" : nsICryptoHash.SHA384,
|
||||
"SHA512" : nsICryptoHash.SHA512
|
||||
};
|
||||
var hashfunction = this._patch.hashfunction.toUpperCase();
|
||||
if (!(hashfunction in map))
|
||||
return false;
|
||||
hash.init(map[hashfunction]);
|
||||
hash.updateFromStream(fileStream, -1);
|
||||
digest = binaryToHex(hash.finish(false));
|
||||
} catch (e) {
|
||||
LOG("failed to compute hash of downloaded update archive");
|
||||
digest = "";
|
||||
}
|
||||
|
||||
fileStream.close();
|
||||
|
||||
return digest == this._patch.hashvalue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Select the patch to use given the current state of updateDir and the given
|
||||
* set of update patches.
|
||||
@ -963,8 +1014,8 @@ Downloader.prototype = {
|
||||
|
||||
// This function may return null, which indicates that there are no patches
|
||||
// to download.
|
||||
var patch = this._selectPatch(update, updateDir);
|
||||
if (!patch) {
|
||||
this._patch = this._selectPatch(update, updateDir);
|
||||
if (!this._patch) {
|
||||
LOG("no patch to download");
|
||||
return;
|
||||
}
|
||||
@ -974,7 +1025,7 @@ Downloader.prototype = {
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var uri = ios.newURI(patch.url, null, null);
|
||||
var uri = ios.newURI(this._patch.url, null, null);
|
||||
|
||||
this._request =
|
||||
Components.classes["@mozilla.org/network/incremental-download;1"].
|
||||
@ -1048,16 +1099,24 @@ Downloader.prototype = {
|
||||
request.QueryInterface(nsIIncrementalDownload);
|
||||
LOG("Downloader.onStopRequest: " + request.URI.spec + ", status = " + status);
|
||||
|
||||
if (Components.isSuccessCode(status)) {
|
||||
var state;
|
||||
if (this._verifyDownload()) {
|
||||
state = STATE_PENDING;
|
||||
} else {
|
||||
LOG("download verification failed");
|
||||
state = STATE_FAILED;
|
||||
// TODO: use more informative error code here
|
||||
status = Components.results.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
this._writeStatusFile(this._getUpdatesDir(), state);
|
||||
}
|
||||
|
||||
var listenerCount = this._listeners.length;
|
||||
for (var i = 0; i < listenerCount; ++i)
|
||||
this._listeners[i].onStopRequest(request, context, status);
|
||||
|
||||
this._request = null;
|
||||
|
||||
if (Components.isSuccessCode(status)) {
|
||||
// TODO: Verify download
|
||||
this._writeStatusFile(this._getUpdatesDir(), STATE_PENDING);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1072,12 +1131,6 @@ Downloader.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function Verifier() {
|
||||
}
|
||||
Verifier.prototype = {
|
||||
|
||||
};
|
||||
|
||||
function TimerManager() {
|
||||
}
|
||||
TimerManager.prototype = {
|
||||
|
Loading…
Reference in New Issue
Block a user