Files
tubestation/netwerk/protocol/http/PackagedAppUtils.js
2015-09-18 11:50:37 +08:00

110 lines
3.4 KiB
JavaScript

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
'use strict';
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const PACKAGEDAPPUTILS_CONTRACTID = "@mozilla.org/network/packaged-app-utils;1";
const PACKAGEDAPPUTILS_CID = Components.ID("{fe8f1c2e-3c13-11e5-9a3f-bbf47d1e6697}");
function PackagedAppUtils() {
}
let DEBUG = 0
function debug(s) {
if (DEBUG) {
dump("-*- PackagedAppUtils: " + s + "\n");
}
}
PackagedAppUtils.prototype = {
classID: PACKAGEDAPPUTILS_CID,
contractID: PACKAGEDAPPUTILS_CONTRACTID,
classDescription: "Packaged App Utils",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPackagedAppUtils]),
verifyManifest: function(aHeader, aManifest, aCallback) {
debug("Manifest: " + aManifest);
// parse signature from header
let signature;
const signatureField = "manifest-signature: ";
for (let item of aHeader.split('\r\n')) {
if (item.substr(0, signatureField.length) == signatureField) {
signature = item.substr(signatureField.length);
break;
}
}
if (!signature) {
debug("No signature in header");
aCallback.fireVerifiedEvent(true, false);
return;
}
debug("Signature: " + signature);
try {
// Base64 decode
signature = atob(signature);
// Remove header
let manifestBody = aManifest.substr(aManifest.indexOf('\r\n\r\n') + 4);
debug("manifestBody: " + manifestBody);
// Parse manifest, store resource hashes
this.resources = JSON.parse(manifestBody)["moz-resources"];
} catch (e) {
debug("JSON parsing failure");
aCallback.fireVerifiedEvent(true, false);
return;
}
let manifestStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
let signatureStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
manifestStream.setData(aManifest, aManifest.length);
signatureStream.setData(signature, signature.length);
let certDb;
try {
certDb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
} catch (e) {
debug("nsIX509CertDB error: " + e);
// unrecoverable error, don't bug the user
throw "CERTDB_ERROR";
}
certDb.verifySignedManifestAsync(
Ci.nsIX509CertDB.PrivilegedPackageRoot, manifestStream, signatureStream,
function(aRv, aCert) {
aCallback.fireVerifiedEvent(true, Components.isSuccessCode(aRv));
});
},
checkIntegrity: function(aFileName, aHashValue, aCallback) {
debug("checkIntegrity() " + aFileName + ": " + aHashValue + "\n");
if (!this.resources) {
debug("resource hashes not found");
aCallback.fireVerifiedEvent(false, false);
return;
}
for (let r of this.resources) {
if (r.src === aFileName) {
debug("found integrity = " + r.integrity);
aCallback.fireVerifiedEvent(false, r.integrity === aHashValue);
return;
}
}
aCallback.fireVerifiedEvent(false, false);
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PackagedAppUtils]);