<!DOCTYPE html>
<meta charset=utf-8>
<title>Subresource Integrity</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/sriharness.js"></script>
<script src="/common/utils.js"></script>
<script src="sri-test-helpers.sub.js"></script>

<div id="log"></div>

<div id="container"></div>
<script>
    var style_tests = [];
    style_tests.execute = function() {
        if (this.length > 0) {
            this.shift().execute();
        }
    }
    add_result_callback(function(res) {
        if (res.name.startsWith("Style: ")) {
          style_tests.execute();
        }
    });

    // Script tests
    new SRIScriptTest(
        true,
        "Same-origin with correct sha256 hash.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with correct sha384 hash.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha384-cINXh+nCzEHPWzXS7eoT+vYMBpyqczOybRLNU3XAButFWCRhHT5hLByIbPRqIm2f"
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with correct sha512 hash.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha512-KZdenhzBd7X7Q/vmaOSyvFz1CGdoVt26xzCZjlkU9lfBEK+V/ougGys7iYDi0+tOHIQSQa87bIqx95R7GU7I9Q=="
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with empty integrity.",
        `${same_origin_prefix}script.js?${token()}`,
        ""
    ).execute();

    new SRIScriptTest(
        false,
        "Same-origin with incorrect hash.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
    ).execute();

    // Scripts with integrity attribute changed after #prepare-a-script.
    new SRIScriptTest(
        false,
        "Same-origin with incorrect integrity => cleared after prepare.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead",
        undefined,
        undefined,
        null
    ).execute();

    new SRIScriptTest(
        false,
        "Same-origin with incorrect integrity => set to correct hash after prepare.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead",
        undefined,
        undefined,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with empty integrity => set to incorrect hash after prepare.",
        `${same_origin_prefix}script.js?${token()}`,
        "",
        undefined,
        undefined,
        "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with correct integrity => set to incorrect hash after prepare.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
        undefined,
        undefined,
        "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with multiple sha256 hashes, including correct.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA= sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with multiple sha256 hashes, including unknown algorithm.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA= foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with sha256 mismatch, sha512 match",
        `${same_origin_prefix}script.js?${token()}`,
        "sha512-KZdenhzBd7X7Q/vmaOSyvFz1CGdoVt26xzCZjlkU9lfBEK+V/ougGys7iYDi0+tOHIQSQa87bIqx95R7GU7I9Q== sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
    ).execute();

    new SRIScriptTest(
        false,
        "Same-origin with sha256 match, sha512 mismatch",
        `${same_origin_prefix}script.js?${token()}`,
        "sha512-deadbeefspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg== sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
    ).execute();

    new SRIScriptTest(
        true,
        "<crossorigin='anonymous'> with correct hash, ACAO: *",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
        "anonymous"
    ).execute();

    new SRIScriptTest(
        false,
        "<crossorigin='anonymous'> with incorrect hash, ACAO: *",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
        "sha256-deadbeefcSLlbFZCj1OACLxTxVck2TOrBTEdUbwz1yU=",
        "anonymous"
    ).execute();

    new SRIScriptTest(
        true,
        "<crossorigin='use-credentials'> with correct hash, CORS-eligible",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Credentials,true)|header(Access-Control-Allow-Origin,${location.origin})`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
        "use-credentials"
    ).execute();

    new SRIScriptTest(
        false,
        "<crossorigin='use-credentials'> with incorrect hash CORS-eligible",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Credentials,true)|header(Access-Control-Allow-Origin,${location.origin})`,
        "sha256-deadbeef2S+pTRZgiw3DWrhC6JLDlt2zRyGpwH7unU8=",
        "use-credentials"
    ).execute();

    new SRIScriptTest(
        false,
        "<crossorigin='anonymous'> with CORS-ineligible resource",
        `${xorigin_prefix}script.js?${token()}`, /* no ACAO header makes this CORS-ineligible */
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
        "anonymous"
    ).execute();

    new SRIScriptTest(
        false,
        "Cross-origin, not CORS request, with correct hash",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
    ).execute();

    new SRIScriptTest(
        false,
        "Cross-origin, not CORS request, with hash mismatch",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
        "sha256-deadbeef01Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0="
    ).execute();

    new SRIScriptTest(
        true,
        "Cross-origin, empty integrity",
        `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
        ""
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with correct hash, options.",
        `${same_origin_prefix}script.js?${token()}`,
        "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=?foo=bar?spam=eggs"
    ).execute();

    new SRIScriptTest(
        true,
        "Same-origin with unknown algorithm only.",
        `${same_origin_prefix}script.js?${token()}`,
        "foo666-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E="
    ).execute();

    // Style tests
    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct sha256 hash",
        {
            href: "style.css?1",
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct sha384 hash",
        {
            href: "style.css?2",
            integrity: "sha384-wDAWxH4tOWBwAwHfBn9B7XuNmFxHTMeigAMwn0iVQ0zq3FtmYMLxihcGnU64CwcX"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct sha512 hash",
        {
            href: "style.css?3",
            integrity: "sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w=="
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with empty integrity",
        {
            href: "style.css?4",
            integrity: ""
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "Same-origin with incorrect hash.",
        {
            href: "style.css?5",
            integrity: "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with multiple sha256 hashes, including correct.",
        {
            href: "style.css?6",
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4= sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with multiple sha256 hashes, including unknown algorithm.",
        {
            href: "style.css?7",
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4= foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with sha256 mismatch, sha512 match",
        {
            href: "style.css?8",
            integrity: "sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w== sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "Same-origin with sha256 match, sha512 mismatch",
        {
            href: "style.css?9",
            integrity: "sha512-deadbeef9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2== sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "<crossorigin='anonymous'> with correct hash, ACAO: *",
        {
            href: xorigin_anon_style + '&1',
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
            crossorigin: "anonymous"
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "<crossorigin='anonymous'> with incorrect hash, ACAO: *",
        {
            href: xorigin_anon_style + '&2',
            integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk=",
            crossorigin: "anonymous"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "<crossorigin='use-credentials'> with correct hash, CORS-eligible",
        {
            href: xorigin_creds_style + '&1',
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
            crossorigin: "use-credentials"
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "<crossorigin='use-credentials'> with incorrect hash CORS-eligible",
        {
            href: xorigin_creds_style + '&2',
            integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk=",
            crossorigin: "use-credentials"
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "<crossorigin='anonymous'> with CORS-ineligible resource",
        {
            href: xorigin_ineligible_style + '&1',
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
            crossorigin: "anonymous"
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "Cross-origin, not CORS request, with correct hash",
        {
            href: xorigin_anon_style + '&3',
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
        }
    );

    new SRIStyleTest(
        style_tests,
        false,
        "Cross-origin, not CORS request, with hash mismatch",
        {
            href: xorigin_anon_style + '&4',
            integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk="
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Cross-origin, empty integrity",
        {
            href: xorigin_anon_style + '&5',
            integrity: ""
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct hash, options.",
        {
            href: "style.css?10",
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=?foo=bar?spam=eggs"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with unknown algorithm only.",
        {
            href: "style.css?11",
            integrity: "foo666-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=?foo=bar?spam=eggs"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct sha256 hash, rel='stylesheet license'",
        {
            href: "style.css?12",
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
            rel: "stylesheet license"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct sha256 hash, rel='license stylesheet'",
        {
            href: "style.css?13",
            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
            rel: "license stylesheet"
        }
    );

    new SRIStyleTest(
        style_tests,
        true,
        "Same-origin with correct sha256 and sha512 hash, rel='alternate stylesheet' enabled",
        {
            href: "alternate.css?1",
            title: "alt",
            type: "text/css",
            class: "alternate",
            disabled: "disabled",
            rel: "alternate stylesheet",
            integrity: "sha256-phbz83bWhnLig+d2VPKrRrTRyhqoDRo1ruGqZLZ0= sha512-8OYEB7ktnzcb6h+kB9CUIuc8qvKIyLpygRJdQSEEycRy74dUsB+Yu9rSjpOPjRUblle8WWX9Gn7v39LK2Oceig==",
        },
        function (link, container) {
            var alternate = document.querySelector('link.alternate');
            alternate.disabled = false;
        },
        "rgb(255, 0, 0)"
    );

    new SRIStyleTest(
        style_tests,
        false,
        "Same-origin with incorrect sha256 and sha512 hash, rel='alternate stylesheet' enabled",
        {
            href: "alternate.css?2",
            title: "alt",
            type: "text/css",
            class: "alternate",
            disabled: "disabled",
            rel: "alternate stylesheet",
            integrity: "sha256-fail83bWhnLig+d2VPKrRrTRyhqoDRo1ruGqZLZ0= sha512-failB7ktnzcb6h+kB9CUIuc8qvKIyLpygRJdQSEEycRy74dUsB+Yu9rSjpOPjRUblle8WWX9Gn7v39LK2Oceig==",
        },
        function (link, container) {
            var alternate = document.querySelector('link.alternate');
            alternate.disabled = false;
        }
    );

    style_tests.execute();

</script>
<!-- TODO check cache-poisoned resources, transfer-encoding, 3xx redirect
   to resource with matching hash, and cross-origin leakage test as in sec5.3.
    -->
