forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			322 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 | 
						|
/* vim: set sts=2 sw=2 et tw=80: */
 | 
						|
"use strict";
 | 
						|
 | 
						|
const cps = Cc["@mozilla.org/addons/content-policy;1"].getService(
 | 
						|
  Ci.nsIAddonContentPolicy
 | 
						|
);
 | 
						|
 | 
						|
add_task(async function test_csp_validator_flags() {
 | 
						|
  let checkPolicy = (policy, flags, expectedResult, message = null) => {
 | 
						|
    info(`Checking policy: ${policy}`);
 | 
						|
 | 
						|
    let result = cps.validateAddonCSP(policy, flags);
 | 
						|
    equal(result, expectedResult);
 | 
						|
  };
 | 
						|
 | 
						|
  let flags = Ci.nsIAddonContentPolicy;
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' http://localhost",
 | 
						|
    0,
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden http: protocol source",
 | 
						|
    "localhost disallowed"
 | 
						|
  );
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' http://localhost",
 | 
						|
    flags.CSP_ALLOW_LOCALHOST,
 | 
						|
    null,
 | 
						|
    "localhost allowed"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' 'unsafe-eval'",
 | 
						|
    0,
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden 'unsafe-eval' keyword",
 | 
						|
    "eval disallowed"
 | 
						|
  );
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' 'unsafe-eval'",
 | 
						|
    flags.CSP_ALLOW_EVAL,
 | 
						|
    null,
 | 
						|
    "eval allowed"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'",
 | 
						|
    0,
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden 'wasm-unsafe-eval' keyword",
 | 
						|
    "wasm disallowed"
 | 
						|
  );
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'",
 | 
						|
    flags.CSP_ALLOW_WASM,
 | 
						|
    null,
 | 
						|
    "wasm allowed"
 | 
						|
  );
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'",
 | 
						|
    flags.CSP_ALLOW_EVAL,
 | 
						|
    null,
 | 
						|
    "wasm and eval allowed"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' https://example.com",
 | 
						|
    0,
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden https: protocol source",
 | 
						|
    "remote disallowed"
 | 
						|
  );
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self' https://example.com",
 | 
						|
    flags.CSP_ALLOW_REMOTE,
 | 
						|
    null,
 | 
						|
    "remote allowed"
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_csp_validator() {
 | 
						|
  let checkPolicy = (policy, expectedResult, message = null) => {
 | 
						|
    info(`Checking policy: ${policy}`);
 | 
						|
 | 
						|
    let result = cps.validateAddonCSP(
 | 
						|
      policy,
 | 
						|
      Ci.nsIAddonContentPolicy.CSP_ALLOW_ANY
 | 
						|
    );
 | 
						|
    equal(result, expectedResult);
 | 
						|
  };
 | 
						|
 | 
						|
  checkPolicy("script-src 'self';", null);
 | 
						|
 | 
						|
  // In the past, object-src was required to be secure and defaulted to 'self'.
 | 
						|
  // But that is no longer required (see bug 1766881).
 | 
						|
  checkPolicy("script-src 'self'; object-src 'self';", null);
 | 
						|
  checkPolicy("script-src 'self'; object-src https:;", null);
 | 
						|
 | 
						|
  let hash =
 | 
						|
    "'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    `script-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash} 'unsafe-eval'; ` +
 | 
						|
      `object-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash}`,
 | 
						|
    null
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "",
 | 
						|
    "Policy is missing a required \u2018script-src\u2019 directive"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "object-src 'none';",
 | 
						|
    "Policy is missing a required \u2018script-src\u2019 directive"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self' http:",
 | 
						|
    "Policy is missing a required \u2018script-src\u2019 directive",
 | 
						|
    "A strict default-src is required as a fallback if script-src is missing"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self' http:; script-src 'self'",
 | 
						|
    null,
 | 
						|
    "A valid script-src removes the need for a strict default-src fallback"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'",
 | 
						|
    null,
 | 
						|
    "A valid default-src should count as a valid script-src"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src 'self'",
 | 
						|
    null,
 | 
						|
    "A valid default-src should count as a valid script-src"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'; script-src http://example.com",
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden http: protocol source",
 | 
						|
    "A valid default-src should not allow an invalid script-src directive"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "script-src 'none'",
 | 
						|
    "\u2018script-src\u2019 must include the source 'self'"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "script-src 'self' 'unsafe-inline'",
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden 'unsafe-inline' keyword"
 | 
						|
  );
 | 
						|
 | 
						|
  // Localhost is always valid
 | 
						|
  for (let src of [
 | 
						|
    "http://localhost",
 | 
						|
    "https://localhost",
 | 
						|
    "http://127.0.0.1",
 | 
						|
    "https://127.0.0.1",
 | 
						|
  ]) {
 | 
						|
    checkPolicy(`script-src 'self' ${src};`, null);
 | 
						|
  }
 | 
						|
 | 
						|
  let directives = ["script-src", "worker-src"];
 | 
						|
 | 
						|
  for (let [directive, other] of [directives, directives.slice().reverse()]) {
 | 
						|
    for (let src of ["https://*", "https://*.blogspot.com", "https://*"]) {
 | 
						|
      checkPolicy(
 | 
						|
        `${directive} 'self' ${src}; ${other} 'self';`,
 | 
						|
        `https: wildcard sources in \u2018${directive}\u2019 directives must include at least one non-generic sub-domain (e.g., *.example.com rather than *.com)`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    for (let protocol of ["http", "https"]) {
 | 
						|
      checkPolicy(
 | 
						|
        `${directive} 'self' ${protocol}:; ${other} 'self';`,
 | 
						|
        `${protocol}: protocol requires a host in \u2018${directive}\u2019 directives`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    checkPolicy(
 | 
						|
      `${directive} 'self' http://example.com; ${other} 'self';`,
 | 
						|
      `\u2018${directive}\u2019 directive contains a forbidden http: protocol source`
 | 
						|
    );
 | 
						|
 | 
						|
    for (let protocol of ["ftp", "meh"]) {
 | 
						|
      checkPolicy(
 | 
						|
        `${directive} 'self' ${protocol}:; ${other} 'self';`,
 | 
						|
        `\u2018${directive}\u2019 directive contains a forbidden ${protocol}: protocol source`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    checkPolicy(
 | 
						|
      `${directive} 'self' 'nonce-01234'; ${other} 'self';`,
 | 
						|
      `\u2018${directive}\u2019 directive contains a forbidden 'nonce-*' keyword`
 | 
						|
    );
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_csp_validator_extension_pages() {
 | 
						|
  let checkPolicy = (policy, expectedResult, message = null) => {
 | 
						|
    info(`Checking policy: ${policy}`);
 | 
						|
 | 
						|
    // While Schemas.jsm uses Ci.nsIAddonContentPolicy.CSP_ALLOW_WASM, we don't
 | 
						|
    // pass that here because we are only verifying that remote scripts are
 | 
						|
    // blocked here.
 | 
						|
    let result = cps.validateAddonCSP(policy, 0);
 | 
						|
    equal(result, expectedResult);
 | 
						|
  };
 | 
						|
 | 
						|
  checkPolicy("script-src 'self';", null);
 | 
						|
  checkPolicy("script-src 'self'; worker-src 'none'", null);
 | 
						|
  checkPolicy("script-src 'self'; worker-src 'self'", null);
 | 
						|
 | 
						|
  // In the past, object-src was required to be secure and defaulted to 'self'.
 | 
						|
  // But that is no longer required (see bug 1766881).
 | 
						|
  checkPolicy("script-src 'self'; object-src 'self';", null);
 | 
						|
  checkPolicy("script-src 'self'; object-src https:;", null);
 | 
						|
 | 
						|
  let hash =
 | 
						|
    "'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    `script-src 'self' moz-extension://09abcdef blob: filesystem: ${hash}; `,
 | 
						|
    null
 | 
						|
  );
 | 
						|
 | 
						|
  for (let policy of ["", "script-src-elem 'none';", "worker-src 'none';"]) {
 | 
						|
    checkPolicy(
 | 
						|
      policy,
 | 
						|
      "Policy is missing a required \u2018script-src\u2019 directive"
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self' http:; script-src 'self'",
 | 
						|
    null,
 | 
						|
    "A valid script-src removes the need for a strict default-src fallback"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "default-src 'self'",
 | 
						|
    null,
 | 
						|
    "A valid default-src should count as a valid script-src"
 | 
						|
  );
 | 
						|
 | 
						|
  for (let directive of ["script-src", "worker-src"]) {
 | 
						|
    checkPolicy(
 | 
						|
      `default-src 'self'; ${directive} 'self'`,
 | 
						|
      null,
 | 
						|
      `A valid default-src should count as a valid ${directive}`
 | 
						|
    );
 | 
						|
    checkPolicy(
 | 
						|
      `default-src 'self'; ${directive} http://example.com`,
 | 
						|
      `\u2018${directive}\u2019 directive contains a forbidden http: protocol source`,
 | 
						|
      `A valid default-src should not allow an invalid ${directive} directive`
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "script-src 'none'",
 | 
						|
    "\u2018script-src\u2019 must include the source 'self'"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "script-src 'self' 'unsafe-inline';",
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden 'unsafe-inline' keyword"
 | 
						|
  );
 | 
						|
 | 
						|
  checkPolicy(
 | 
						|
    "script-src 'self' 'unsafe-eval';",
 | 
						|
    "\u2018script-src\u2019 directive contains a forbidden 'unsafe-eval' keyword"
 | 
						|
  );
 | 
						|
 | 
						|
  // Localhost is invalid
 | 
						|
  for (let src of [
 | 
						|
    "http://localhost",
 | 
						|
    "https://localhost",
 | 
						|
    "http://127.0.0.1",
 | 
						|
    "https://127.0.0.1",
 | 
						|
  ]) {
 | 
						|
    const protocol = src.split(":")[0];
 | 
						|
    checkPolicy(
 | 
						|
      `script-src 'self' ${src};`,
 | 
						|
      `\u2018script-src\u2019 directive contains a forbidden ${protocol}: protocol source`
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  let directives = ["script-src", "worker-src"];
 | 
						|
 | 
						|
  for (let [directive, other] of [directives, directives.slice().reverse()]) {
 | 
						|
    for (let protocol of ["http", "https"]) {
 | 
						|
      checkPolicy(
 | 
						|
        `${directive} 'self' ${protocol}:; ${other} 'self';`,
 | 
						|
        `${protocol}: protocol requires a host in \u2018${directive}\u2019 directives`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    checkPolicy(
 | 
						|
      `${directive} 'self' https://example.com; ${other} 'self';`,
 | 
						|
      `\u2018${directive}\u2019 directive contains a forbidden https: protocol source`
 | 
						|
    );
 | 
						|
 | 
						|
    checkPolicy(
 | 
						|
      `${directive} 'self' http://example.com; ${other} 'self';`,
 | 
						|
      `\u2018${directive}\u2019 directive contains a forbidden http: protocol source`
 | 
						|
    );
 | 
						|
 | 
						|
    for (let protocol of ["ftp", "meh"]) {
 | 
						|
      checkPolicy(
 | 
						|
        `${directive} 'self' ${protocol}:; ${other} 'self';`,
 | 
						|
        `\u2018${directive}\u2019 directive contains a forbidden ${protocol}: protocol source`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    checkPolicy(
 | 
						|
      `${directive} 'self' 'nonce-01234'; ${other} 'self';`,
 | 
						|
      `\u2018${directive}\u2019 directive contains a forbidden 'nonce-*' keyword`
 | 
						|
    );
 | 
						|
  }
 | 
						|
});
 |