diff options
Diffstat (limited to 'dom/security/test/contentverifier/file_contentserver.sjs')
-rw-r--r-- | dom/security/test/contentverifier/file_contentserver.sjs | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/dom/security/test/contentverifier/file_contentserver.sjs b/dom/security/test/contentverifier/file_contentserver.sjs new file mode 100644 index 0000000000..3ea49cdde2 --- /dev/null +++ b/dom/security/test/contentverifier/file_contentserver.sjs @@ -0,0 +1,261 @@ +/* -*- 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); +} |