summaryrefslogtreecommitdiffstats
path: root/devtools/shared/gcli/commands/security.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/gcli/commands/security.js')
-rw-r--r--devtools/shared/gcli/commands/security.js328
1 files changed, 328 insertions, 0 deletions
diff --git a/devtools/shared/gcli/commands/security.js b/devtools/shared/gcli/commands/security.js
new file mode 100644
index 000000000..eeed03c61
--- /dev/null
+++ b/devtools/shared/gcli/commands/security.js
@@ -0,0 +1,328 @@
+/* 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/. */
+
+/**
+ * The Security devtool supports the following arguments:
+ * * Security CSP
+ * Provides feedback about the current CSP
+ *
+ * * Security referrer
+ * Provides information about the current referrer policy
+ */
+
+"use strict";
+
+const { Cc, Ci, Cu, CC } = require("chrome");
+const l10n = require("gcli/l10n");
+const CSP = Cc["@mozilla.org/cspcontext;1"].getService(Ci.nsIContentSecurityPolicy);
+
+const GOOD_IMG_SRC = "chrome://browser/content/gcli_sec_good.svg";
+const MOD_IMG_SRC = "chrome://browser/content/gcli_sec_moderate.svg";
+const BAD_IMG_SRC = "chrome://browser/content/gcli_sec_bad.svg";
+
+
+// special handling within policy
+const POLICY_REPORT_ONLY = "report-only"
+
+// special handling of directives
+const DIR_UPGRADE_INSECURE = "upgrade-insecure-requests";
+const DIR_BLOCK_ALL_MIXED_CONTENT = "block-all-mixed-content";
+
+// special handling of sources
+const SRC_UNSAFE_INLINE = "'unsafe-inline'";
+const SRC_UNSAFE_EVAL = "'unsafe-eval'";
+
+const WILDCARD_MSG = l10n.lookup("securityCSPRemWildCard");
+const XSS_WARNING_MSG = l10n.lookup("securityCSPPotentialXSS");
+const NO_CSP_ON_PAGE_MSG = l10n.lookup("securityCSPNoCSPOnPage");
+const CONTENT_SECURITY_POLICY_MSG = l10n.lookup("securityCSPHeaderOnPage");
+const CONTENT_SECURITY_POLICY_REPORT_ONLY_MSG = l10n.lookup("securityCSPROHeaderOnPage");
+
+const NEXT_URI_HEADER = l10n.lookup("securityReferrerNextURI");
+const CALCULATED_REFERRER_HEADER = l10n.lookup("securityReferrerCalculatedReferrer");
+/* The official names from the W3C Referrer Policy Draft http://www.w3.org/TR/referrer-policy/ */
+const REFERRER_POLICY_NAMES = [ "None When Downgrade (default)", "None", "Origin Only", "Origin When Cross-Origin", "Unsafe URL" ];
+
+exports.items = [
+ {
+ // --- General Security information
+ name: "security",
+ description: l10n.lookup("securityPrivacyDesc"),
+ manual: l10n.lookup("securityManual")
+ },
+ {
+ // --- CSP specific Security information
+ item: "command",
+ runAt: "server",
+ name: "security csp",
+ description: l10n.lookup("securityCSPDesc"),
+ manual: l10n.lookup("securityCSPManual"),
+ returnType: "securityCSPInfo",
+ exec: function(args, context) {
+
+ var cspJSON = context.environment.document.nodePrincipal.cspJSON;
+ var cspOBJ = JSON.parse(cspJSON);
+
+ var outPolicies = [];
+
+ var policies = cspOBJ["csp-policies"];
+
+ // loop over all the different policies
+ for (var csp in policies) {
+ var curPolicy = policies[csp];
+
+ // loop over all the directive-values within that policy
+ var outDirectives = [];
+ var outHeader = CONTENT_SECURITY_POLICY_MSG;
+ for (var dir in curPolicy) {
+ var curDir = curPolicy[dir];
+
+ // when iterating properties within the obj we might also
+ // encounter the 'report-only' flag, which is not a csp directive.
+ if (dir === POLICY_REPORT_ONLY) {
+ outHeader = curPolicy[POLICY_REPORT_ONLY] === true ?
+ CONTENT_SECURITY_POLICY_REPORT_ONLY_MSG :
+ CONTENT_SECURITY_POLICY_MSG;
+ continue;
+ }
+
+ // loop over all the directive-sources within that directive
+ var outSrcs = [];
+
+ // special case handling for the directives
+ // upgrade-insecure-requests and block-all-mixed-content
+ // which do not include any srcs
+ if (dir === DIR_UPGRADE_INSECURE ||
+ dir === DIR_BLOCK_ALL_MIXED_CONTENT) {
+ outSrcs.push({
+ icon: GOOD_IMG_SRC,
+ src: "", // no src
+ desc: "" // no description
+ });
+ }
+
+ for (var src in curDir) {
+ var curSrc = curDir[src];
+
+ // the default icon and descritpion of the directive-src
+ var outIcon = GOOD_IMG_SRC;
+ var outDesc = "";
+
+ if (curSrc.indexOf("*") > -1) {
+ outIcon = MOD_IMG_SRC;
+ outDesc = WILDCARD_MSG;
+ }
+ if (curSrc == SRC_UNSAFE_INLINE || curSrc == SRC_UNSAFE_EVAL) {
+ outIcon = BAD_IMG_SRC;
+ outDesc = XSS_WARNING_MSG;
+ }
+ outSrcs.push({
+ icon: outIcon,
+ src: curSrc,
+ desc: outDesc
+ });
+ }
+ // append info about that directive to the directives array
+ outDirectives.push({
+ dirValue: dir,
+ dirSrc: outSrcs
+ });
+ }
+ // append info about the policy to the policies array
+ outPolicies.push({
+ header: outHeader,
+ directives: outDirectives
+ });
+ }
+ return outPolicies;
+ }
+ },
+ {
+ item: "converter",
+ from: "securityCSPInfo",
+ to: "view",
+ exec: function(cspInfo, context) {
+ var url = context.environment.target.url;
+
+ if (cspInfo.length == 0) {
+ return context.createView({
+ html:
+ "<table class='gcli-csp-detail' cellspacing='10' valign='top'>" +
+ " <tr>" +
+ " <td> <img src='chrome://browser/content/gcli_sec_bad.svg' width='20px' /> </td> " +
+ " <td>" + NO_CSP_ON_PAGE_MSG + " <b>" + url + "</b></td>" +
+ " </tr>" +
+ "</table>"});
+ }
+
+ return context.createView({
+ html:
+ "<table class='gcli-csp-detail' cellspacing='10' valign='top'>" +
+ // iterate all policies
+ " <tr foreach='csp in ${cspinfo}' >" +
+ " <td> ${csp.header} <b>" + url + "</b><br/><br/>" +
+ " <table class='gcli-csp-dir-detail' valign='top'>" +
+ // >> iterate all directives
+ " <tr foreach='dir in ${csp.directives}' >" +
+ " <td valign='top'> ${dir.dirValue} </td>" +
+ " <td valign='top'>" +
+ " <table class='gcli-csp-src-detail' valign='top'>" +
+ // >> >> iterate all srs
+ " <tr foreach='src in ${dir.dirSrc}' >" +
+ " <td valign='center' width='20px'> <img src= \"${src.icon}\" width='20px' /> </td> " +
+ " <td valign='center' width='200px'> ${src.src} </td>" +
+ " <td valign='center'> ${src.desc} </td>" +
+ " </tr>" +
+ " </table>" +
+ " </td>" +
+ " </tr>" +
+ " </table>" +
+ " </td>" +
+ " </tr>" +
+ "</table>",
+ data: {
+ cspinfo: cspInfo,
+ }
+ });
+ }
+ },
+ {
+ // --- Referrer Policy specific Security information
+ item: "command",
+ runAt: "server",
+ name: "security referrer",
+ description: l10n.lookup("securityReferrerPolicyDesc"),
+ manual: l10n.lookup("securityReferrerPolicyManual"),
+ returnType: "securityReferrerPolicyInfo",
+ exec: function(args, context) {
+ var doc = context.environment.document;
+
+ var referrerPolicy = doc.referrerPolicy;
+
+ var pageURI = doc.documentURIObject;
+ var sameDomainReferrer = "";
+ var otherDomainReferrer = "";
+ var downgradeReferrer = "";
+ var otherDowngradeReferrer = "";
+ var origin = pageURI.prePath;
+
+ switch (referrerPolicy) {
+ case Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER:
+ // sends no referrer
+ sameDomainReferrer
+ = otherDomainReferrer
+ = downgradeReferrer
+ = otherDowngradeReferrer
+ = "(no referrer)";
+ break;
+ case Ci.nsIHttpChannel.REFERRER_POLICY_ORIGIN:
+ // only sends the origin of the referring URL
+ sameDomainReferrer
+ = otherDomainReferrer
+ = downgradeReferrer
+ = otherDowngradeReferrer
+ = origin;
+ break;
+ case Ci.nsIHttpChannel.REFERRER_POLICY_ORIGIN_WHEN_XORIGIN:
+ // same as default, but reduced to ORIGIN when cross-origin.
+ sameDomainReferrer = pageURI.spec;
+ otherDomainReferrer
+ = downgradeReferrer
+ = otherDowngradeReferrer
+ = origin;
+ break;
+ case Ci.nsIHttpChannel.REFERRER_POLICY_UNSAFE_URL:
+ // always sends the referrer, even on downgrade.
+ sameDomainReferrer
+ = otherDomainReferrer
+ = downgradeReferrer
+ = otherDowngradeReferrer
+ = pageURI.spec;
+ break;
+ case Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE:
+ // default state, doesn't send referrer from https->http
+ sameDomainReferrer = otherDomainReferrer = pageURI.spec;
+ downgradeReferrer = otherDowngradeReferrer = "(no referrer)";
+ break;
+ default:
+ // this is a new referrer policy which we do not know about
+ sameDomainReferrer
+ = otherDomainReferrer
+ = downgradeReferrer
+ = otherDowngradeReferrer
+ = "(unknown Referrer Policy)";
+ break;
+ }
+
+ var sameDomainUri = origin + "/*";
+
+ var referrerUrls = [
+ // add the referrer uri 'referrer' we would send when visiting 'uri'
+ {
+ uri: pageURI.scheme+'://example.com/',
+ referrer: otherDomainReferrer,
+ description: l10n.lookup('securityReferrerPolicyOtherDomain')},
+ {
+ uri: sameDomainUri,
+ referrer: sameDomainReferrer,
+ description: l10n.lookup('securityReferrerPolicySameDomain')}
+ ];
+
+ if (pageURI.schemeIs('https')) {
+ // add the referrer we would send on downgrading http->https
+ if (sameDomainReferrer != downgradeReferrer) {
+ referrerUrls.push({
+ uri: "http://"+pageURI.hostPort+"/*",
+ referrer: downgradeReferrer,
+ description:
+ l10n.lookup('securityReferrerPolicySameDomainDowngrade')
+ });
+ }
+ if (otherDomainReferrer != otherDowngradeReferrer) {
+ referrerUrls.push({
+ uri: "http://example.com/",
+ referrer: otherDowngradeReferrer,
+ description:
+ l10n.lookup('securityReferrerPolicyOtherDomainDowngrade')
+ });
+ }
+ }
+
+ return {
+ header: l10n.lookupFormat("securityReferrerPolicyReportHeader",
+ [pageURI.spec]),
+ policyName: REFERRER_POLICY_NAMES[referrerPolicy],
+ urls: referrerUrls
+ }
+ }
+ },
+ {
+ item: "converter",
+ from: "securityReferrerPolicyInfo",
+ to: "view",
+ exec: function(referrerPolicyInfo, context) {
+ return context.createView({
+ html:
+ "<div class='gcli-referrer-policy'>" +
+ " <strong> ${rpi.header} </strong> <br />" +
+ " ${rpi.policyName} <br />" +
+ " <table class='gcli-referrer-policy-detail' cellspacing='10' >" +
+ " <tr>" +
+ " <th> " + NEXT_URI_HEADER + " </th>" +
+ " <th> " + CALCULATED_REFERRER_HEADER + " </th>" +
+ " </tr>" +
+ // iterate all policies
+ " <tr foreach='nextURI in ${rpi.urls}' >" +
+ " <td> ${nextURI.description} (e.g., ${nextURI.uri}) </td>" +
+ " <td> ${nextURI.referrer} </td>" +
+ " </tr>" +
+ " </table>" +
+ "</div>",
+ data: {
+ rpi: referrerPolicyInfo,
+ }
+ });
+ }
+ }
+];