-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1890696 [wpt PR 45638] - Subresource Integrity support for ES mod…
…ules, using importmaps, a=testonly Automatic update from web-platform-tests Subresource Integrity support for ES modules, using importmaps (#45638) SRI support for ES modules enables using them in documents that require SRI for certain scripts for security reasons, as well as with the move overarching require-sri-for CSP directive. This CL implements whatwg/html#10269 based on https://github.com/guybedford/import-maps-extensions#integrity I2P: https://groups.google.com/a/chromium.org/g/blink-dev/c/O2UR3kb-HcI/m/7Jh7_GYsAAAJ?utm_medium=email&utm_source=footer Change-Id: Ida563334048d013ffc658f9783f9401930dd4689 Bug: 334251999 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5441822 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Yoav Weiss (@Shopify) <yoavweiss@chromium.org> Cr-Commit-Position: refs/heads/main@{#1297376} Co-authored-by: Yoav Weiss <yoavweiss@chromium.org> -- wpt-commits: 7daf23a6329f4577bc3723d5e25eae8eae26e710 wpt-pr: 45638
- Loading branch information
1 parent
12b5d15
commit 57f4cab
Showing
7 changed files
with
502 additions
and
3 deletions.
There are no files selected for viewing
87 changes: 87 additions & 0 deletions
87
testing/web-platform/tests/import-maps/dynamic-integrity.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
let log; | ||
</script> | ||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"./resources/log.js?pipe=sub&name=ResolvesToBadHash": "./resources/log.js?pipe=sub&name=BadHash", | ||
"./resources/log.js?pipe=sub&name=ResolvesToNoHash": "./resources/log.js?pipe=sub&name=NoHash", | ||
"./resources/log.js?pipe=sub&name=GoodHash": "./resources/log.js?pipe=sub&name=GoodHash", | ||
"bare": "./resources/log.js?pipe=sub&name=BareURL", | ||
"bare2": "./resources/log.js?pipe=sub&name=F" | ||
}, | ||
"integrity": { | ||
"./resources/log.js?pipe=sub&name=BadHash": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ResolvesToNoHash": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=GoodHash": "sha384-SwfgBqInhSlLziU454cYhGgwPpae+d3VHZcY+vjZIO/gxRGt2u3Jsfyvure/Ww0u", | ||
"./resources/log.js?pipe=sub&name=InvalidExtra": "sha384-WsKk8nzJFPhk/4pWR4LYoPhEu3xaAc6PdIm4vmqoZVWqEgMYmZgOg9XJKxgD1+8v foobar-rOJN8igD0+jW6lwNN3+InhXTgQztVHlq/HJ0riswXp8kMoiIDx5JpmCwuVem6Ll9q2LFNSu1xq23bsBMMQk1rg==", | ||
"./resources/log.js?pipe=sub&name=Suffix": "sha384-lbOWldbmji7sCHI/L8iVJ+elmFIMp41p+aYOLxqQfZMqtoFeHFVe/ASRA0IyZ1/9?foobar", | ||
"./resources/log.js?pipe=sub&name=Multiple": "sha384-foobar sha512-rOJN8igD0+jW6lwNN3+InhXTgQztVHlq/HJ0riswXp8kMoiIDx5JpmCwuVem6Ll9q2LFNSu1xq23bsBMMQk1rg==", | ||
"./resources/log.js?pipe=sub&name=BadHashWithNoImport": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=BareURL": "sha384-foobar", | ||
"bare2": "sha384-foobar", | ||
"resources/log.js?pipe=sub&name=Bare": "sha384-foobar" | ||
} | ||
} | ||
</script> | ||
<script type="module"> | ||
const test_not_loaded = (url, description) => { | ||
promise_test(async t => { | ||
log = []; | ||
const promise = import(url); | ||
await promise_rejects_js(t, TypeError, promise); | ||
assert_array_equals(log, []); | ||
}, description); | ||
}; | ||
|
||
const test_loaded = (url, log_expectation, description) => { | ||
promise_test(async t => { | ||
log = []; | ||
await import(url); | ||
assert_array_equals(log, log_expectation); | ||
}, description); | ||
}; | ||
|
||
test_not_loaded("./resources/log.js?pipe=sub&name=ResolvesToBadHash", | ||
'script was not loaded, as its resolved URL failed its integrity check'); | ||
|
||
test_loaded("./resources/log.js?pipe=sub&name=ResolvesToNoHash", ["log:NoHash"], | ||
'script was loaded, as its resolved URL had no integrity check, despite' + | ||
' its specifier having one'); | ||
|
||
test_loaded("./resources/log.js?pipe=sub&name=GoodHash", ["log:GoodHash"], | ||
'script was loaded, as its integrity check passed'); | ||
|
||
test_not_loaded("./resources/log.js?pipe=sub&name=BadHashWithNoImport", | ||
'Script with no import definition was not loaded, as it failed its' + | ||
' integrity check'); | ||
|
||
test_not_loaded("bare", | ||
'Bare specifier script was not loaded, as it failed its integrity check'); | ||
|
||
test_loaded("bare2", ["log:F"], | ||
'Bare specifier used for integrity loaded, as its definition should have' + | ||
' used the URL'); | ||
|
||
test_loaded("./resources/log.js?pipe=sub&name=InvalidExtra", | ||
["log:InvalidExtra"], | ||
'script was loaded, as its integrity check passed, despite having an extra' + | ||
' invalid hash'); | ||
|
||
test_loaded("./resources/log.js?pipe=sub&name=Suffix", ["log:Suffix"], | ||
'script was loaded, as its integrity check passed, despite having an' + | ||
' invalid suffix'); | ||
|
||
test_loaded("./resources/log.js?pipe=sub&name=Multiple", ["log:Multiple"], | ||
'script was loaded, as its integrity check passed given multiple hashes.' + | ||
' This also makes sure that the larger hash is picked.'); | ||
|
||
test_loaded("./resources/log.js?pipe=sub&name=Bare",["log:Bare"], | ||
'script was loaded, as its integrity check was ignored, as it was defined' + | ||
' using a URL that looks like a bare specifier'); | ||
</script> | ||
|
37 changes: 37 additions & 0 deletions
37
testing/web-platform/tests/import-maps/no-referencing-script-integrity-valid.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
let log = []; | ||
</script> | ||
<script type="importmap"> | ||
{ | ||
"integrity": { | ||
"./resources/log.js?pipe=sub&name=NoReferencingScriptValidCheck": "sha384-5eRmXQSBE6H5ENdymdZxcyiIfJL1dxtH8p+hOelZY7Jzk+gt0gYyemrGY0cEaThF" | ||
} | ||
} | ||
</script> | ||
<script> | ||
let promiseResolve; | ||
let promiseReject; | ||
let promise = new Promise((resolve, reject) => { | ||
promiseResolve = resolve; | ||
promiseReject = reject; | ||
}); | ||
</script> | ||
</head> | ||
<body> | ||
<img src="/images/green.png?2" | ||
onload="import('./resources/log.js?pipe=sub&name=NoReferencingScriptValidCheck').then(promiseResolve).catch(promiseReject)"> | ||
<script> | ||
promise_test(async () => { | ||
await promise; | ||
assert_equals(log.length, 1); | ||
assert_equals(log[0], "log:NoReferencingScriptValidCheck"); | ||
}, "Script was loaded as its valid integrity check passed"); | ||
</script> | ||
</body> | ||
</html> | ||
|
34 changes: 34 additions & 0 deletions
34
testing/web-platform/tests/import-maps/no-referencing-script-integrity.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
let log = []; | ||
</script> | ||
<script type="importmap"> | ||
{ | ||
"integrity": { | ||
"./resources/log.js?pipe=sub&name=NoReferencingScriptInvalidCheck": "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" | ||
} | ||
} | ||
</script> | ||
<script> | ||
let promiseResolve; | ||
let promiseReject; | ||
let promise = new Promise((resolve, reject) => { | ||
promiseResolve = resolve; | ||
promiseReject = reject; | ||
}); | ||
</script> | ||
</head> | ||
<body> | ||
<img src="/images/green.png" | ||
onload="import('./resources/log.js?pipe=sub&name=NoReferencingScriptInvalidCheck').then(promiseResolve).catch(promiseReject)"> | ||
<script type="module"> | ||
promise_test(async t => { | ||
await promise_rejects_js(t, TypeError, promise); | ||
}, "Script was not loaded as its integrity check failed"); | ||
</script> | ||
</body> | ||
</html> |
161 changes: 161 additions & 0 deletions
161
testing/web-platform/tests/import-maps/nonimport-integrity.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
let log = []; | ||
</script> | ||
<script type="importmap"> | ||
{ | ||
"integrity": { | ||
"./resources/log.js?pipe=sub&name=ModuleNoIntegrity": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ModuleIntegrity": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ModuleEmptyIntegrity": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ModuleBadIntegrityAttribute": "sha384-COhDkp+ybIZ9wz9hUaSJ5NzKcn8wOMZMpsACZfTeEdBRtNcX5yWJnFn+lIK77Tay", | ||
"./resources/log.js?pipe=sub&name=ModulePreloadNoIntegrity": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ModulePreloadIntegrity": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ModulePreloadEmptyIntegrity": "sha384-foobar", | ||
"./resources/log.js?pipe=sub&name=ModulePreloadBadIntegrityAttribute": "sha384-026dlUs9+KSmPb0Uc7oUPOlWBO67o7vSFdfLJZWEVTvKCly5NXO8+CsOXl54ZBqJ", | ||
"./resources/log.js?pipe=sub&name=NonModule": "sha384-foobar", | ||
"/images/green.png": "sha384-foobar" | ||
} | ||
} | ||
</script> | ||
<script type="module"> | ||
promise_test(async t => { | ||
log = []; | ||
const script = document.createElement("script"); | ||
script.type = "module"; | ||
script.src = "./resources/log.js?pipe=sub&name=ModuleNoIntegrity"; | ||
const promise = new Promise((resolve, reject) => { | ||
script.onload = resolve; | ||
script.onerror = () => { reject(Error()); }; | ||
}); | ||
document.head.appendChild(script); | ||
await promise_rejects_js(t, Error, promise); | ||
}, "Script was not loaded as its integrity check was not ignored"); | ||
|
||
promise_test(async () => { | ||
log = []; | ||
const script = document.createElement("script"); | ||
script.type = "module"; | ||
script.integrity = "sha384-QtZrhNFOSmHASHnBdmGg+zrVz5hjukCBakaqwT2pcG7w+QTa/niK16csP6kXAeXI"; | ||
script.src = "./resources/log.js?pipe=sub&name=ModuleIntegrity"; | ||
const promise = new Promise((resolve, reject) => { | ||
script.onload = resolve; | ||
script.onerror = reject; | ||
}); | ||
document.head.appendChild(script); | ||
await promise; | ||
assert_equals(log.length, 1); | ||
assert_equals(log[0], "log:ModuleIntegrity"); | ||
}, "Script was loaded as its correct integrity attribute was not ignored"); | ||
|
||
promise_test(async () => { | ||
log = []; | ||
const script = document.createElement("script"); | ||
script.type = "module"; | ||
script.integrity = ""; | ||
script.src = "./resources/log.js?pipe=sub&name=ModuleEmptyIntegrity"; | ||
const promise = new Promise((resolve, reject) => { | ||
script.onload = resolve; | ||
script.onerror = reject; | ||
}); | ||
document.head.appendChild(script); | ||
await promise; | ||
assert_equals(log.length, 1); | ||
assert_equals(log[0], "log:ModuleEmptyIntegrity"); | ||
}, "Script was loaded as its empty integrity attribute was not ignored"); | ||
|
||
promise_test(async t => { | ||
log = []; | ||
const script = document.createElement("script"); | ||
script.type = "module"; | ||
script.integrity = "sha384-foobar"; | ||
script.src = "./resources/log.js?pipe=sub&name=ModuleBadIntegrityAttribute"; | ||
const promise = new Promise((resolve, reject) => { | ||
script.onload = resolve; | ||
script.onerror = () => { reject(Error()); }; | ||
}); | ||
document.head.appendChild(script); | ||
await promise_rejects_js(t, Error, promise); | ||
}, "Script was not loaded as its bad integrity attribute was not overridden"); | ||
|
||
promise_test(async t => { | ||
const link = document.createElement("link"); | ||
link.rel = "modulepreload"; | ||
link.href = "./resources/log.js?pipe=sub&name=ModulePreloadNoIntegrity"; | ||
const promise = new Promise((resolve, reject) => { | ||
link.onload = resolve; | ||
link.onerror = () => { reject(Error()); }; | ||
}); | ||
document.head.appendChild(link); | ||
await promise_rejects_js(t, Error, promise); | ||
}, "Modulepreload was not loaded as its integrity check was not ignored"); | ||
|
||
promise_test(async () => { | ||
const link = document.createElement("link"); | ||
link.rel = "modulepreload"; | ||
link.integrity = "sha384-iDG3WysExtjWvD9QwQrC7nGXRvO0jM+r7Z2cOLMDO2geMlEtmN9j9xfqHfzT45+9"; | ||
link.href = "./resources/log.js?pipe=sub&name=ModulePreloadIntegrity"; | ||
const promise = new Promise((resolve, reject) => { | ||
link.onload = resolve; | ||
link.onerror = reject; | ||
}); | ||
document.head.appendChild(link); | ||
await promise; | ||
}, "Modulepreload was loaded as its correct integrity attribute was not ignored"); | ||
|
||
promise_test(async () => { | ||
const link = document.createElement("link"); | ||
link.rel = "modulepreload"; | ||
link.integrity = ""; | ||
link.href = "./resources/log.js?pipe=sub&name=ModulePreloadEmptyIntegrity"; | ||
const promise = new Promise((resolve, reject) => { | ||
link.onload = resolve; | ||
link.onerror = reject; | ||
}); | ||
document.head.appendChild(link); | ||
await promise; | ||
}, "Modulepreload was loaded as its empty integrity attribute was not ignored"); | ||
|
||
promise_test(async t => { | ||
const link = document.createElement("link"); | ||
link.rel = "modulepreload"; | ||
link.integrity = "sha384-foobar"; | ||
link.href = "./resources/log.js?pipe=sub&name=ModulePreloadBadIntegrityAttribute"; | ||
const promise = new Promise((resolve, reject) => { | ||
link.onload = resolve; | ||
link.onerror = () => { reject(Error()); }; | ||
}); | ||
document.head.appendChild(link); | ||
await promise_rejects_js(t, Error, promise); | ||
}, "Modulepreload was not loaded as its bad integrity attribute was not ignored"); | ||
|
||
promise_test(async () => { | ||
log = []; | ||
const script = document.createElement("script"); | ||
script.src = "./resources/log.js?pipe=sub&name=NonModule"; | ||
const promise = new Promise((resolve, reject) => { | ||
script.onload = resolve; | ||
script.onerror = reject; | ||
}); | ||
document.head.appendChild(script); | ||
await promise; | ||
assert_equals(log.length, 1); | ||
assert_equals(log[0], "log:NonModule"); | ||
}, "Classic script was loaded as its integrity check was ignored"); | ||
|
||
promise_test(async () => { | ||
const img = document.createElement("img"); | ||
const promise = new Promise((resolve, reject) => { | ||
img.onload = resolve; | ||
img.onerror = reject; | ||
}); | ||
img.src = "/images/green.png"; | ||
document.head.appendChild(img); | ||
await promise; | ||
}, "Image was loaded as its integrity check was ignored"); | ||
</script> | ||
</head> |
68 changes: 68 additions & 0 deletions
68
testing/web-platform/tests/import-maps/static-integrity.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
let log = []; | ||
</script> | ||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"./resources/log.js?pipe=sub&name=A": "./resources/log.js?pipe=sub&name=B", | ||
"./resources/log.js?pipe=sub&name=C": "./resources/log.js?pipe=sub&name=D" | ||
}, | ||
"integrity": { | ||
"./resources/log.js?pipe=sub&name=B": "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7", | ||
"./resources/log.js?pipe=sub&name=D": "sha384-rxZqznFuOnvObm6JJKVmwzBXrsRG25IepqKDFHGhtitRu9YPjxPpRPMIu2hzvtxF", | ||
"./resources/log.js?pipe=sub&name=X": "sha384-mCon9M46vUfNK2Wb3yjvBmpBw/3hwB+wMYS8IzDBng+7//R5Qao35E1azo4gFVzx", | ||
"./resources/log.js?pipe=sub&name=Y": "sha384-u0yaFlBF39Au++qcn+MGL/Ml7UmuVfLymNJAz6Yyi4RqyUfWelcuAzVyE8Shs9xn", | ||
"./resources/log.js?pipe=sub&name=Z": "sha384-u0yaFlBF39Au++qcn+MGL/Ml7UmuVfLymNJAz6Yyi4RqyUfWelcuAzVyE8Shs9xn" | ||
} | ||
} | ||
</script> | ||
<script type="module"> | ||
import './resources/log.js?pipe=sub&name=A'; | ||
</script> | ||
<script type="module"> | ||
test(t => { | ||
assert_array_equals(log, []); | ||
}, 'Static script did not load as it failed its integrity check'); | ||
log = []; | ||
</script> | ||
<script type="module"> | ||
import './resources/log.js?pipe=sub&name=C'; | ||
</script> | ||
<script type="module"> | ||
test(t => { | ||
assert_array_equals(log, ["log:D"]); | ||
}, 'Static script loaded as its integrity check passed'); | ||
log = []; | ||
</script> | ||
<script type="module"> | ||
import './resources/log.js?pipe=sub&name=X'; | ||
</script> | ||
<script type="module"> | ||
test(t => { | ||
assert_array_equals(log, []); | ||
}, 'Static script did not load as it failed its integrity check, even' + | ||
' without an import defined'); | ||
log = []; | ||
</script> | ||
<script type="module"> | ||
import './resources/log.js?pipe=sub&name=Y'; | ||
</script> | ||
<script type="module"> | ||
test(t => { | ||
assert_array_equals(log, ["log:Y"]); | ||
}, 'Static script loaded as its integrity check passed without an import' + | ||
' defined'); | ||
log = []; | ||
</script> | ||
<script type="module" src="./resources/log.js?pipe=sub&name=Z">; | ||
</script> | ||
<script type="module"> | ||
test(t => { | ||
assert_array_equals(log, []); | ||
}, 'HTML-based module script did not load as its integrity check failed.'); | ||
log = []; | ||
</script> |
Oops, something went wrong.