Skip to content

Commit b2fdca1

Browse files
authored
Add subresource integrity support to import maps
Based on https://github.com/guybedford/import-maps-extensions#proposal.
1 parent 2312c6b commit b2fdca1

File tree

1 file changed

+184
-27
lines changed

1 file changed

+184
-27
lines changed

source

Lines changed: 184 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,6 +2705,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
27052705

27062706
<ul class="brief">
27072707
<li><dfn data-x-href="https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata">parse integrity metadata</dfn></li>
2708+
<li><dfn data-x-href="https://w3c.github.io/webappsec-subresource-integrity/#the-integrity-attribute">the requirements of the integrity attribute</dfn></li>
27082709
<li><dfn data-x-href="https://w3c.github.io/webappsec-subresource-integrity/#get-the-strongest-metadata">get the strongest metadata from set</dfn></li>
27092710
</ul>
27102711
</dd>
@@ -26985,6 +26986,10 @@ document.body.appendChild(wbr);</code></pre>
2698526986
data-x="attr-link-integrity">integrity</code> attribute, if it is specified, or the empty string
2698626987
otherwise.</p></li>
2698726988

26989+
<li><p>If <var>el</var> does not have an <code data-x="attr-link-integrity">integrity</code>
26990+
attribute, then set <var>integrity metadata</var> to the result of <span>resolving a module
26991+
integrity metadata</span> with <var>url</var> and <var>settings object</var>.</p></li>
26992+
2698826993
<li><p>Let <var>referrer policy</var> be the current state of <var>el</var>'s <code
2698926994
data-x="attr-link-referrerpolicy">referrerpolicy</code> attribute.</p></li>
2699026995

@@ -62618,6 +62623,12 @@ o............A....e
6261862623

6261962624
<dt>"<code data-x="">module</code>"</dt>
6262062625
<dd>
62626+
<p>If <var>el</var> does not have an <code data-x="attr-script-integrity">integrity</code>
62627+
attribute, then set <var>options</var>'s <span
62628+
data-x="concept-script-fetch-options-integrity">integrity metadata</span> to the result of
62629+
<span>resolving a module integrity metadata</span> with <var>url</var> and
62630+
<var>settings object</var>.</p>
62631+
6262162632
<p><span>Fetch an external module script graph</span> given <var>url</var>, <var>settings
6262262633
object</var>, <var>options</var>, and <var>onComplete</var>.</p>
6262362634
</dd>
@@ -106255,12 +106266,51 @@ document.querySelector("button").addEventListener("click", bound);
106255106266
<span data-x="concept-script-fetch-options-fetch-priority">fetch priority</span>.</p></dd>
106256106267
</dl>
106257106268

106258-
<p>For any given <span>script fetch options</span> <var>options</var>, the <dfn>descendant script
106259-
fetch options</dfn> are a new <span>script fetch options</span> whose <span data-x="struct
106260-
item">items</span> all have the same values, except for the <span
106261-
data-x="concept-script-fetch-options-integrity">integrity metadata</span>, which is instead the
106262-
empty string, and the <span data-x="concept-script-fetch-options-fetch-priority">fetch
106263-
priority</span>, which is instead "<code data-x="">auto</code>".</p>
106269+
<p>To <dfn>get the descendant script fetch options</dfn> given a <span>script fetch options</span>
106270+
<var>originalOptions</var>, a <span>URL</span> <var>url</var>, and an <span>environment settings
106271+
object</span> <var>settingsObject</var>:</p>
106272+
106273+
<ol>
106274+
<li><p>Let <var>newOptions</var> be a copy of <var>originalOptions</var>.</p></li>
106275+
106276+
<li><p>Let <var>integrity</var> be the empty string.</p></li>
106277+
106278+
<li><p>If <var>settingsObject</var>'s <span
106279+
data-x="concept-settings-object-global">global object</span> is a <code>Window</code> object,
106280+
then set <var>integrity</var> to the result of <span>resolving a module integrity metadata</span>
106281+
with <var>url</var> and <var>settingsObject</var>.</p></li>
106282+
106283+
<li><p>Set <var>newOptions</var>'s <span
106284+
data-x="concept-script-fetch-options-integrity">integrity metadata</span> to
106285+
<var>integrity</var>.</p></li>
106286+
106287+
<li><p>Set <var>newOptions</var>'s <span
106288+
data-x="concept-script-fetch-options-fetch-priority">fetch priority</span> to "<code
106289+
data-x="">auto</code>".</p></li>
106290+
106291+
<li><p>Return <var>newOptions</var>.</p></li>
106292+
</ol>
106293+
106294+
<p>To <dfn data-x="resolving a module integrity metadata">resolve a module
106295+
integrity metadata</dfn>, given a <span>URL</span> <var>url</var> and an <span>environment
106296+
settings object</span> <var>settingsObject</var>:</p>
106297+
106298+
<ol>
106299+
<li><p><span>Assert</span>: <var>settingsObject</var>'s <span
106300+
data-x="concept-settings-object-global">global object</span> is a <code>Window</code>
106301+
object.</p></li>
106302+
106303+
<li><p>Let <var>map</var> be <var>settingsObject</var>'s <span
106304+
data-x="concept-settings-object-global">global object</span>'s <span
106305+
data-x="concept-window-import-map">import map</span>.</p></li>
106306+
106307+
<li><p>If <var>map</var>'s <span
106308+
data-x="concept-import-map-integrity">integrity</span>[<var>url</var>] does not <span
106309+
data-x="map exists">exist</span>, then return the empty string.</p></li>
106310+
106311+
<li><p>Return <var>map</var>'s <span
106312+
data-x="concept-import-map-integrity">integrity</span>[<var>url</var>].</p></li>
106313+
</ol>
106264106314

106265106315
<hr>
106266106316

@@ -108344,6 +108394,29 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
108344108394
</table>
108345108395
</div>
108346108396

108397+
<div class="example" id="example-import-map-integrity">
108398+
<p>Import maps can also be used to provide modules with integrity metadata to be used in
108399+
<cite>Subresource Integrity</cite> checks. <ref>SRI</ref>
108400+
</p>
108401+
108402+
<p>The following import map illustrates this:</p>
108403+
108404+
<pre><code class="json" data-x="">{
108405+
"imports": {
108406+
"a": "/a-1.mjs",
108407+
"b": "/b-1.mjs",
108408+
"c": "/c-1.mjs"
108409+
},
108410+
"integrity": {
108411+
"/a-1.mjs": "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7",
108412+
"/d-1.mjs": "sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk"
108413+
}
108414+
}</code></pre>
108415+
<p>The above example provides integrity metadata to be enforced on the modules <code
108416+
data-x="">/a-1.mjs</code> and <code data-x="">/d-1.mjs</code>, even if the latter is not defined
108417+
as an import in the map.</p>
108418+
</div>
108419+
108347108420
<hr>
108348108421

108349108422
<p>The <span>child text content</span> of a <code>script</code> element representing an
@@ -108353,11 +108426,13 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
108353108426
<ul>
108354108427
<li><p>It must be valid JSON. <ref>JSON</ref></p></li>
108355108428

108356-
<li><p>The JSON must represent a JSON object, with at most the two keys "<code
108357-
data-x="">imports</code>" and "<code data-x="">scopes</code>".</p></li>
108429+
<li><p>The JSON must represent a JSON object, with at most the three keys "<code
108430+
data-x="">imports</code>", "<code data-x="">scopes</code>", and "<code
108431+
data-x="">integrity</code>".</p></li>
108358108432

108359-
<li><p>The values corresponding to the "<code data-x="">imports</code>" and "<code
108360-
data-x="">scopes</code>" keys, if present, must themselves be JSON objects.</p></li>
108433+
<li><p>The values corresponding to the "<code data-x="">imports</code>", "<code
108434+
data-x="">scopes</code>", and "<code data-x="">integrity</code>" keys, if present,
108435+
must themselves be JSON objects.</p></li>
108361108436

108362108437
<li><p>The value corresponding to the "<code data-x="">imports</code>" key, if present, must be
108363108438
a <span>valid module specifier map</span>.</p></li>
@@ -108366,6 +108441,10 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
108366108441
JSON object, whose keys are <span data-x="valid URL string">valid URL strings</span> and whose
108367108442
values are <span data-x="valid module specifier map">valid module specifier
108368108443
maps</span>.</p></li>
108444+
108445+
<li><p>The value corresponding to the "<code data-x="">integrity</code>" key, if present, must
108446+
be a JSON object, whose keys are <span data-x="valid URL string">valid URL strings</span> and
108447+
whose values fit <span>the requirements of the integrity attribute</span>.</p></li>
108369108448
</ul>
108370108449

108371108450
<p>A <dfn>valid module specifier map</dfn> is a JSON object that meets the following
@@ -108389,22 +108468,30 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
108389108468

108390108469
<h5>Import map processing model</h5>
108391108470

108392-
<p>Formally, an <dfn>import map</dfn> is a <span>struct</span> with two <span data-x="struct
108471+
<p>Formally, an <dfn>import map</dfn> is a <span>struct</span> with three <span data-x="struct
108393108472
item">items</span>:</p>
108394108473

108395108474
<ul>
108396108475
<li><p><dfn data-x="concept-import-map-imports">imports</dfn>, a <span>module specifier
108397-
map</span>; and</p></li>
108476+
map</span>;</p></li>
108398108477

108399108478
<li><p><dfn data-x="concept-import-map-scopes">scopes</dfn>, an <span>ordered map</span> of
108400108479
<span data-x="URL">URLs</span> to <span data-x="module specifier map">module specifier
108401-
maps</span>.</p>
108480+
maps</span>; and</p></li>
108481+
108482+
<li><p><dfn data-x="concept-import-map-integrity">integrity</dfn>, a <span>module integrity
108483+
map</span>.</p></li>
108402108484
</ul>
108403108485

108404108486
<p>A <dfn>module specifier map</dfn> is an <span>ordered map</span> whose <span data-x="map
108405108487
key">keys</span> are <span data-x="string">strings</span> and whose <span data-x="map
108406108488
value">values</span> are either <span data-x="URL">URLs</span> or nulls.</p>
108407108489

108490+
<p>A <dfn>module integrity map</dfn> is an <span>ordered map</span> whose <span data-x="map
108491+
key">keys</span> are <span data-x="URL">URLs</span> and whose <span data-x="map
108492+
value">values</span> are <span data-x="string">strings</span> that will be used as <span
108493+
data-x="concept-request-integrity-metadata">integrity metadata</span>.</p>
108494+
108408108495
<p>An <dfn>empty import map</dfn> is an <span>import map</span> with its <span
108409108496
data-x="concept-import-map-imports">imports</span> and <span
108410108497
data-x="concept-import-map-scopes">scopes</span> both being empty maps.</p>
@@ -108478,20 +108565,40 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
108478108565
</ol>
108479108566
</li>
108480108567

108568+
<li><p>Let <var>normalizedIntegrity</var> be an empty <span>ordered map</span>.</p></li>
108569+
108570+
<li>
108571+
<p>If <var>parsed</var>["<code data-x="">integrity</code>"] <span data-x="map
108572+
exists">exists</span>, then:</p>
108573+
108574+
<ol>
108575+
<li><p>If <var>parsed</var>["<code data-x="">integrity</code>"] is not an <span>ordered
108576+
map</span>, then throw a <code>TypeError</code> indicating that the value for the "<code
108577+
data-x="">integrity</code>" top-level key needs to be a JSON object.</p></li>
108578+
108579+
<li><p>Set <var>normalizedIntegrity</var> to the result of <span>normalizing a module
108580+
integrity map</span> given <var>parsed</var>["<code data-x="">integrity</code>"] and
108581+
<var>baseURL</var>.</p></li>
108582+
</ol>
108583+
</li>
108584+
108481108585
<li>
108482108586
<p>If <var>parsed</var>'s <span data-x="map key">keys</span> <span data-x="list
108483-
contains">contains</span> any items besides "<code data-x="">imports</code>" or "<code
108484-
data-x="">scopes</code>", then the user agent should <span>report a warning to the
108485-
console</span> indicating that an invalid top-level key was present in the import map.</p>
108587+
contains">contains</span> any items besides "<code data-x="">imports</code>", "<code
108588+
data-x="">scopes</code>", or "<code data-x="">integrity</code>", then the user agent should
108589+
<span>report a warning to the console</span> indicating that an invalid top-level key was
108590+
present in the import map.</p>
108486108591

108487108592
<p class="note">This can help detect typos. It is not an error, because that would prevent any
108488108593
future extensions from being added backward-compatibly.</p>
108489108594
</li>
108490108595

108491108596
<li><p>Return an <span>import map</span> whose <span
108492-
data-x="concept-import-map-imports">imports</span> are <var>sortedAndNormalizedImports</var> and
108597+
data-x="concept-import-map-imports">imports</span> are <var>sortedAndNormalizedImports</var>,
108493108598
whose <span data-x="concept-import-map-scopes">scopes</span> are
108494-
<var>sortedAndNormalizedScopes</var>.</p></li>
108599+
<var>sortedAndNormalizedScopes</var>, and whose <span
108600+
data-x="concept-import-map-integrity">integrity</span> are
108601+
<var>normalizedIntegrity</var>.</p></li>
108495108602
</ol>
108496108603

108497108604
<div class="example" id="example-import-map-normalization">
@@ -108640,6 +108747,57 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
108640108747
turn gives "<code data-x="">foo/bar/</code>" a higher priority than "<code data-x="">foo/</code>"
108641108748
during <span data-x="resolve a module specifier">module specifier resolution</span>.</p>
108642108749

108750+
<p>To <dfn data-x="normalizing a module integrity map">normalize a module integrity map</dfn>,
108751+
given an <span>ordered map</span> <var>originalMap</var>:</p>
108752+
108753+
<ol>
108754+
<li><p>Let <var>normalized</var> be an empty <span>ordered map</span>.</p></li>
108755+
108756+
<li>
108757+
<p><span data-x="list iterate">For each</span> <var>key</var> → <var>value</var> of
108758+
<var>originalMap</var>:</p>
108759+
108760+
<ol>
108761+
<li>
108762+
<p>Let <var>resolvedURL</var> be the result of <span>resolving a URL-like module
108763+
specifier</span> given <var>key</var> and <var>baseURL</var>.</p>
108764+
108765+
<p class="note">Unlike "<code data-x="">imports</code>", keys of the integrity map are treated
108766+
as URLs, not module specifiers. However, we use the <span data-x="resolving a URL-like module
108767+
specifier">resolve a URL-like module specifier</span> algorithm to prohibit "bare" relative
108768+
URLs like <code data-x="">foo</code>, which could be mistaken for module specifiers.</p>
108769+
</li>
108770+
108771+
<li>
108772+
<p>If <var>resolvedURL</var> is null, then:</p>
108773+
108774+
<ol>
108775+
<li><p>The user agent may <span>report a warning to the console</span> indicating that
108776+
the key failed to resolve.</p></li>
108777+
108778+
<li><p><span>Continue</span>.</p></li>
108779+
</ol>
108780+
</li>
108781+
108782+
<li>
108783+
<p>If <var>value</var> is not a <span>string</span>, then:</p>
108784+
108785+
<ol>
108786+
<li><p>The user agent may <span>report a warning to the console</span> indicating that
108787+
<span data-x="concept-request-integrity-metadata">integrity metadata</span> values need to
108788+
be <span data-x="string">strings</span>.</p></li>
108789+
108790+
<li><p><span>Continue</span>.</p></li>
108791+
</ol>
108792+
</li>
108793+
108794+
<li><p>Set <var>normalized</var>[<var>resolvedURL</var>] to <var>value</var>.</p></li>
108795+
</ol>
108796+
</li>
108797+
108798+
<li><p>Return <var>normalized</var>.</p></li>
108799+
</ol>
108800+
108643108801
<p>To <dfn data-x="normalizing a specifier key">normalize a specifier key</dfn>, given a <span>string</span> <var>specifierKey</var> and a <span>URL</span> <var>baseURL</var>:</p>
108644108802

108645108803
<ol>
@@ -109271,7 +109429,7 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
109271109429

109272109430
<li><p>Let <var>referencingScript</var> be null.</p></li>
109273109431

109274-
<li><p>Let <var>fetchOptions</var> be the <span>default classic script fetch
109432+
<li><p>Let <var>originalFetchOptions</var> be the <span>default classic script fetch
109275109433
options</span>.</p></li>
109276109434

109277109435
<li><p>Let <var>fetchReferrer</var> be "<code data-x="">client</code>".</p></li>
@@ -109286,16 +109444,11 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
109286109444
<li><p>Set <var>settingsObject</var> to <var>referencingScript</var>'s <span
109287109445
data-x="concept-script-settings-object">settings object</span>.</p></li>
109288109446

109289-
<li><p>Set <var>fetchOptions</var> to the new <span>descendant script fetch options</span> for
109290-
<var>referencingScript</var>'s <span data-x="concept-script-script-fetch-options">fetch
109291-
options</span>.</p></li>
109292-
109293-
<li><p><span>Assert</span>: <var>fetchOptions</var> is not null, as
109294-
<var>referencingScript</var> is a <span>classic script</span> or a <span>JavaScript module
109295-
script</span>.</p></li>
109296-
109297109447
<li><p>Set <var>fetchReferrer</var> to <var>referencingScript</var>'s <span
109298109448
data-x="concept-script-base-url">base URL</span>.</p></li>
109449+
109450+
<li><p>Set <var>originalFetchOptions</var> to <var>referencingScript</var>'s <span
109451+
data-x="concept-script-script-fetch-options">fetch options</span>.</p></li>
109299109452
</ol>
109300109453

109301109454
<div class="example">
@@ -109334,6 +109487,10 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
109334109487
</ol>
109335109488
</li>
109336109489

109490+
<li><p>Let <var>fetchOptions</var> be the result of <span data-x="get the descendant script
109491+
fetch options">getting the descendant script fetch options</span> given
109492+
<var>originalFetchOptions</var>, <var>settingsObject</var>, and <var>url</var>.</p></li>
109493+
109337109494
<li><p>Let <var>destination</var> be <code data-x="">"script"</code>.</p></li>
109338109495

109339109496
<li><p>Let <var>fetchClient</var> be <var>settingsObject</var>.</p></li>

0 commit comments

Comments
 (0)