зеркало из https://github.com/mozilla/gecko-dev.git
262 строки
8.9 KiB
JavaScript
262 строки
8.9 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/. */
|
|
// sjs for remote about:newtab (bug 1226928)
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
Cu.import("resource://gre/modules/NetUtil.jsm");
|
|
Cu.import("resource://gre/modules/FileUtils.jsm");
|
|
Cu.importGlobalProperties(["URLSearchParams"]);
|
|
|
|
const path = "browser/dom/security/test/contentverifier/";
|
|
|
|
const goodFileName = "file_about_newtab.html";
|
|
const goodFileBase = path + goodFileName;
|
|
const goodFile = FileUtils.getDir("TmpD", [], true);
|
|
goodFile.append(goodFileName);
|
|
const goodSignature = path + "file_about_newtab_good_signature";
|
|
const goodX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\"";
|
|
|
|
const scriptFileName = "script.js";
|
|
const cssFileName = "style.css";
|
|
const badFile = path + "file_about_newtab_bad.html";
|
|
const brokenSignature = path + "file_about_newtab_broken_signature";
|
|
const badSignature = path + "file_about_newtab_bad_signature";
|
|
const badX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=bad\"";
|
|
const httpX5UString = "\"http://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\"";
|
|
|
|
const sriFile = path + "file_about_newtab_sri.html";
|
|
const sriSignature = path + "file_about_newtab_sri_signature";
|
|
|
|
const badCspFile = path + "file_about_newtab_bad_csp.html";
|
|
const badCspSignature = path + "file_about_newtab_bad_csp_signature";
|
|
|
|
// This cert chain is copied from
|
|
// security/manager/ssl/tests/unit/test_content_signing/
|
|
// using the certificates
|
|
// * content_signing_remote_newtab_ee.pem
|
|
// * content_signing_int.pem
|
|
// * content_signing_root.pem
|
|
const goodCertChainPath = path + "goodChain.pem";
|
|
|
|
const tempFileNames = [goodFileName, scriptFileName, cssFileName];
|
|
|
|
// we copy the file to serve as newtab to a temp directory because
|
|
// we modify it during tests.
|
|
setupTestFiles();
|
|
|
|
function setupTestFiles() {
|
|
for (let fileName of tempFileNames) {
|
|
let tempFile = FileUtils.getDir("TmpD", [], true);
|
|
tempFile.append(fileName);
|
|
if (!tempFile.exists()) {
|
|
let fileIn = getFileName(path + fileName, "CurWorkD");
|
|
fileIn.copyTo(FileUtils.getDir("TmpD", [], true), "");
|
|
}
|
|
}
|
|
}
|
|
|
|
function getFileName(filePath, dir) {
|
|
// Since it's relative to the cwd of the test runner, we start there and
|
|
// append to get to the actual path of the file.
|
|
let testFile =
|
|
Cc["@mozilla.org/file/directory_service;1"].
|
|
getService(Components.interfaces.nsIProperties).
|
|
get(dir, Components.interfaces.nsILocalFile);
|
|
let dirs = filePath.split("/");
|
|
for (let i = 0; i < dirs.length; i++) {
|
|
testFile.append(dirs[i]);
|
|
}
|
|
return testFile;
|
|
}
|
|
|
|
function loadFile(file) {
|
|
// Load a file to return it.
|
|
let testFileStream =
|
|
Cc["@mozilla.org/network/file-input-stream;1"]
|
|
.createInstance(Components.interfaces.nsIFileInputStream);
|
|
testFileStream.init(file, -1, 0, 0);
|
|
return NetUtil.readInputStreamToString(testFileStream,
|
|
testFileStream.available());
|
|
}
|
|
|
|
function appendToFile(aFile, content) {
|
|
try {
|
|
let file = FileUtils.openFileOutputStream(aFile, FileUtils.MODE_APPEND |
|
|
FileUtils.MODE_WRONLY);
|
|
file.write(content, content.length);
|
|
file.close();
|
|
} catch (e) {
|
|
dump(">>> Error in appendToFile "+e);
|
|
return "Error";
|
|
}
|
|
return "Done";
|
|
}
|
|
|
|
function truncateFile(aFile, length) {
|
|
let fileIn = loadFile(aFile);
|
|
fileIn = fileIn.slice(0, -length);
|
|
|
|
try {
|
|
let file = FileUtils.openFileOutputStream(aFile, FileUtils.MODE_WRONLY |
|
|
FileUtils.MODE_TRUNCATE);
|
|
file.write(fileIn, fileIn.length);
|
|
file.close();
|
|
} catch (e) {
|
|
dump(">>> Error in truncateFile "+e);
|
|
return "Error";
|
|
}
|
|
return "Done";
|
|
}
|
|
|
|
function cleanupTestFiles() {
|
|
for (let fileName of tempFileNames) {
|
|
let tempFile = FileUtils.getDir("TmpD", [], true);
|
|
tempFile.append(fileName);
|
|
tempFile.remove(true);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* handle requests of the following form:
|
|
* sig=good&key=good&file=good&header=good&cached=no to serve pages with
|
|
* content signatures
|
|
*
|
|
* it further handles invalidateFile=yep and validateFile=yep to change the
|
|
* served file
|
|
*/
|
|
function handleRequest(request, response) {
|
|
let params = new URLSearchParams(request.queryString);
|
|
let x5uType = params.get("x5u");
|
|
let signatureType = params.get("sig");
|
|
let fileType = params.get("file");
|
|
let headerType = params.get("header");
|
|
let cached = params.get("cached");
|
|
let invalidateFile = params.get("invalidateFile");
|
|
let validateFile = params.get("validateFile");
|
|
let resource = params.get("resource");
|
|
let x5uParam = params.get("x5u");
|
|
|
|
if (params.get("cleanup")) {
|
|
cleanupTestFiles();
|
|
response.setHeader("Content-Type", "text/html", false);
|
|
response.write("Done");
|
|
return;
|
|
}
|
|
|
|
if (resource) {
|
|
if (resource == "script") {
|
|
response.setHeader("Content-Type", "application/javascript", false);
|
|
response.write(loadFile(getFileName(scriptFileName, "TmpD")));
|
|
} else { // resource == "css1" || resource == "css2"
|
|
response.setHeader("Content-Type", "text/css", false);
|
|
response.write(loadFile(getFileName(cssFileName, "TmpD")));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// if invalidateFile is set, this doesn't actually return a newtab page
|
|
// but changes the served file to invalidate the signature
|
|
// NOTE: make sure to make the file valid again afterwards!
|
|
if (invalidateFile) {
|
|
let r = "Done";
|
|
for (let fileName of tempFileNames) {
|
|
if (appendToFile(getFileName(fileName, "TmpD"), "!") != "Done") {
|
|
r = "Error";
|
|
}
|
|
}
|
|
response.setHeader("Content-Type", "text/html", false);
|
|
response.write(r);
|
|
return;
|
|
}
|
|
|
|
// if validateFile is set, this doesn't actually return a newtab page
|
|
// but changes the served file to make the signature valid again
|
|
if (validateFile) {
|
|
let r = "Done";
|
|
for (let fileName of tempFileNames) {
|
|
if (truncateFile(getFileName(fileName, "TmpD"), 1) != "Done") {
|
|
r = "Error";
|
|
}
|
|
}
|
|
response.setHeader("Content-Type", "text/html", false);
|
|
response.write(r);
|
|
return;
|
|
}
|
|
|
|
// we have to return the certificate chain on request for the x5u parameter
|
|
if (x5uParam && x5uParam == "default") {
|
|
response.setHeader("Cache-Control", "max-age=216000", false);
|
|
response.setHeader("Content-Type", "text/plain", false);
|
|
response.write(loadFile(getFileName(goodCertChainPath, "CurWorkD")));
|
|
return;
|
|
}
|
|
|
|
// avoid confusing cache behaviours
|
|
if (!cached) {
|
|
response.setHeader("Cache-Control", "no-cache", false);
|
|
} else {
|
|
response.setHeader("Cache-Control", "max-age=3600", false);
|
|
}
|
|
|
|
// send HTML to test allowed/blocked behaviours
|
|
response.setHeader("Content-Type", "text/html", false);
|
|
|
|
// set signature header and key for Content-Signature header
|
|
/* By default a good content-signature header is returned. Any broken return
|
|
* value has to be indicated in the url.
|
|
*/
|
|
let csHeader = "";
|
|
let x5uString = goodX5UString;
|
|
let signature = goodSignature;
|
|
let file = goodFile;
|
|
if (x5uType == "bad") {
|
|
x5uString = badX5UString;
|
|
} else if (x5uType == "http") {
|
|
x5uString = httpX5UString;
|
|
}
|
|
if (signatureType == "bad") {
|
|
signature = badSignature;
|
|
} else if (signatureType == "broken") {
|
|
signature = brokenSignature;
|
|
} else if (signatureType == "sri") {
|
|
signature = sriSignature;
|
|
} else if (signatureType == "bad-csp") {
|
|
signature = badCspSignature;
|
|
}
|
|
if (fileType == "bad") {
|
|
file = getFileName(badFile, "CurWorkD");
|
|
} else if (fileType == "sri") {
|
|
file = getFileName(sriFile, "CurWorkD");
|
|
} else if (fileType == "bad-csp") {
|
|
file = getFileName(badCspFile, "CurWorkD");
|
|
}
|
|
|
|
if (headerType == "good") {
|
|
// a valid content-signature header
|
|
csHeader = "x5u=" + x5uString + ";p384ecdsa=" +
|
|
loadFile(getFileName(signature, "CurWorkD"));
|
|
} else if (headerType == "error") {
|
|
// this content-signature header is missing ; before p384ecdsa
|
|
csHeader = "x5u=" + x5uString + "p384ecdsa=" +
|
|
loadFile(getFileName(signature, "CurWorkD"));
|
|
} else if (headerType == "errorInX5U") {
|
|
// this content-signature header is missing the keyid directive
|
|
csHeader = "x6u=" + x5uString + ";p384ecdsa=" +
|
|
loadFile(getFileName(signature, "CurWorkD"));
|
|
} else if (headerType == "errorInSignature") {
|
|
// this content-signature header is missing the p384ecdsa directive
|
|
csHeader = "x5u=" + x5uString + ";p385ecdsa=" +
|
|
loadFile(getFileName(signature, "CurWorkD"));
|
|
}
|
|
|
|
if (csHeader) {
|
|
response.setHeader("Content-Signature", csHeader, false);
|
|
}
|
|
let result = loadFile(file);
|
|
|
|
response.write(result);
|
|
}
|