tenfourfox/netwerk/protocol/http/PackagedAppUtils.js

116 lines
3.7 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() {
this.packageIdentifier = '';
this.packageOrigin = '';
}
var 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, aDeveloperMode) {
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 {
// Remove header
let manifestBody = aManifest.substr(aManifest.indexOf('\r\n\r\n') + 4);
debug("manifestBody: " + manifestBody);
// Parse manifest, store resource hashes
let manifestObj = JSON.parse(manifestBody);
this.packageIdentifier = manifestObj["package-identifier"];
this.packageOrigin = manifestObj["moz-package-origin"];
this.resources = manifestObj["moz-resources"];
// Base64 decode
signature = atob(signature);
} catch (e) {
debug("Manifest 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";
}
let trustedRoot = aDeveloperMode ? Ci.nsIX509CertDB.DeveloperImportedRoot
: Ci.nsIX509CertDB.PrivilegedPackageRoot;
certDb.verifySignedManifestAsync(trustedRoot, 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]);