Skip to content

Commit

Permalink
Prevent type: "javascript" import asessions
Browse files Browse the repository at this point in the history
This was the original intent of the import assertions integration, but type: "javascript" was unintentionally allowed to work due to a bug involving the spec's internal use of the "javascript" module type for JavaScript module scripts.

Fixes #7342.
  • Loading branch information
dandclark authored Nov 23, 2021
1 parent bb7bde0 commit c447169
Showing 1 changed file with 99 additions and 70 deletions.
169 changes: 99 additions & 70 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -91367,14 +91367,12 @@ document.querySelector("button").addEventListener("click", bound);
we only asked for "<code data-x="">type</code>" assertions in
<span>HostGetSupportedImportAssertions</span>.</p></li>

<li><p>If <var>moduleRequest</var>.[[Assertions]] has a <span>Record</span> <var>entry</var>
such that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then let <var>module
type</var> be <var>entry</var>.[[Value]]. Otherwise let <var>module type</var> be "<code
data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be the result of running the <span>module type from module
request</span> steps given <var>moduleRequest</var>.</p></li>

<li><p>If the result of running the <span>module type allowed</span> steps given <var>module
type</var> and <var>settings object</var> is false, then asynchronously complete this algorithm
with null, and return.</p></li>
<li><p>If the result of running the <span>module type allowed</span> steps given
<var>moduleType</var> and <var>settings object</var> is false, then asynchronously complete this
algorithm with null, and return.</p></li>

<li><p><span>Fetch a single module script</span> given <var>url</var>, <var>settings
object</var>, "<code data-x="">script</code>", <var>options</var>, <var>settings object</var>,
Expand All @@ -91386,7 +91384,7 @@ document.querySelector("button").addEventListener("click", bound);
<li><p>If <var>result</var> is null, asynchronously complete this algorithm with null, and
return.</p></li>

<li><p>Let <var>visited set</var> be « (<var>url</var>, <var>module type</var>) ».</p></li>
<li><p>Let <var>visited set</var> be « (<var>url</var>, <var>moduleType</var>) ».</p></li>

<li><p><span data-x="fetch the descendants of and link a module script">Fetch the
descendants of and link</span> <var>result</var> given <var>settings object</var>,
Expand Down Expand Up @@ -91734,20 +91732,18 @@ document.querySelector("button").addEventListener("click", bound);
href="#validate-requested-module-specifiers">previously successful</a> with these same two
arguments.</p></li>

<li><p>If <var>requested</var>.[[Assertions]] has a <span>Record</span> <var>entry</var> such
that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then let <var>module type</var>
be <var>entry</var>.[[Value]]. Otherwise let <var>module type</var> be "<code
data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be the result of running the <span>module type from module
request</span> steps given <var>requested</var>.</p></li>

<li>
<p>If <var>visited set</var> does not <span data-x="list contains">contain</span>
(<var>url</var>, <var>module type</var>), then:</p>
(<var>url</var>, <var>moduleType</var>), then:</p>

<ol>
<li><p><span data-x="list append">Append</span> <var>requested</var> to
<var>moduleRequests</var>.</p></li>

<li><p><span data-x="set append">Append</span> (<var>url</var>, <var>module type</var>) to
<li><p><span data-x="set append">Append</span> (<var>url</var>, <var>moduleType</var>) to
<var>visited set</var>.</p></li>
</ol>
</li>
Expand Down Expand Up @@ -91800,13 +91796,11 @@ document.querySelector("button").addEventListener("click", bound);
href="#validate-requested-module-specifiers">previously successful</a> with these same two
arguments.</p></li>

<li><p>If <var>moduleRequest</var>.[[Assertions]] has a <span>Record</span> <var>entry</var>
such that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then let <var>module
type</var> be <var>entry</var>.[[Value]]. Otherwise let <var>module type</var> be "<code
data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be the result of running the <span>module type from module
request</span> steps given <var>moduleRequest</var>.</p></li>

<li><p>Assert: <var>visited set</var> <span data-x="list contains">contains</span>
(<var>url</var>, <var>module type</var>).</p></li>
(<var>url</var>, <var>moduleType</var>).</p></li>

<li><p><span>Fetch a single module script</span> given <var>url</var>, <var>fetch client settings
object</var>, <var>destination</var>, <var>options</var>, <var>module map settings object</var>,
Expand Down Expand Up @@ -91837,41 +91831,33 @@ document.querySelector("button").addEventListener("click", bound);
complete with either null (on failure) or a <span>module script</span> (on success).</p>

<ol>
<li><p>Let <var>module type</var> be "<code data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be "<code data-x="">javascript</code>".</p></li>

<li>
<p>If <var>moduleRequest</var> was given and <var>moduleRequest</var>.[[Assertions]] has a
<span>Record</span> <var>entry</var> such that <var>entry</var>.[[Key]] is "<code
data-x="">type</code>", then:</p>

<ol>
<li><p>Assert: No more than one such <span>Record</span> exists.</p></li>
<li><p>If <var>moduleRequest</var> was given, then set <var>moduleType</var> to the result of
running the <span>module type from module request</span> steps given
<var>moduleRequest</var>.</p></li>

<li><p>Set <var>module type</var> to <var>entry</var>.[[Value]].</p></li>
</ol>
</li>

<li><p>Assert: the result of running the <span>module type allowed</span> steps given <var>module
type</var> and <var>module map settings object</var> is true. Otherwise we would not have reached
this point because a failure would have been raised when inspecting
<li><p>Assert: the result of running the <span>module type allowed</span> steps given
<var>moduleType</var> and <var>module map settings object</var> is true. Otherwise we would not
have reached this point because a failure would have been raised when inspecting
<var>moduleRequest</var>.[[Assertions]] in <a
href="#validate-requested-module-specifiers">create a JavaScript module script</a> or
<span>fetch an import() module script graph</span>.</p></li>

<li><p>Let <var>moduleMap</var> be <var>module map settings object</var>'s <span
data-x="concept-settings-object-module-map">module map</span>.</p></li>

<li><p>If <var>moduleMap</var>[(<var>url</var>, <var>module type</var>)] is
<li><p>If <var>moduleMap</var>[(<var>url</var>, <var>moduleType</var>)] is
"<code data-x="">fetching</code>", wait <span>in parallel</span> until that entry's value
changes, then <span>queue a task</span> on the <span>networking task source</span> to proceed
with running the following steps.</p></li>

<li><p>If <var>moduleMap</var>[(<var>url</var>, <var>module type</var>)] <span
<li><p>If <var>moduleMap</var>[(<var>url</var>, <var>moduleType</var>)] <span
data-x="map exists">exists</span>, asynchronously complete this algorithm with
<var>moduleMap</var>[<var>url</var> / <var>module type</var>], and return.</p></li>
<var>moduleMap</var>[<var>url</var> / <var>moduleType</var>], and return.</p></li>

<li><p><span data-x="map set">Set</span> <var>moduleMap</var>[(<var>url</var>, <var>module
type</var>)] to "<code data-x="">fetching</code>".</p></li>
<li><p><span data-x="map set">Set</span> <var>moduleMap</var>[(<var>url</var>,
<var>moduleType</var>)] to "<code data-x="">fetching</code>".</p></li>

<li><p>Let <var>request</var> be a new <span data-x="concept-request">request</span> whose
<span data-x="concept-request-url">URL</span> is <var>url</var>, <span
Expand Down Expand Up @@ -91921,8 +91907,9 @@ document.querySelector("button").addEventListener("click", bound);
<span>ok status</span>.</p></li>
</ul>

<p>then <span data-x="map set">set</span> <var>moduleMap</var>[(<var>url</var>, <var>module
type</var>)] to null, asynchronously complete this algorithm with null, and return.</p>
<p>then <span data-x="map set">set</span> <var>moduleMap</var>[(<var>url</var>,
<var>moduleType</var>)] to null, asynchronously complete this algorithm with null, and
return.</p>
</li>

<li><p>Let <var>source text</var> be the result of <span data-x="UTF-8 decode">UTF-8
Expand All @@ -91934,26 +91921,26 @@ document.querySelector("button").addEventListener("click", bound);

<li><p>Let <var>module script</var> be null.</p></li>

<li><p>If <var>MIME type</var> is a <span>JavaScript MIME type</span> and <var>module type</var>
<li><p>If <var>MIME type</var> is a <span>JavaScript MIME type</span> and <var>moduleType</var>
is "<code data-x="">javascript</code>", then set <var>module script</var> to the result of
<span>creating a JavaScript module script</span> given <var>source text</var>, <var>module map
settings object</var>, <var>response</var>'s <span data-x="concept-response-url">url</span>, and
<var>options</var>.</p></li>

<li><p>If the <span>MIME type essence</span> of <var>MIME type</var> is "<code>text/css</code>"
and <var>module type</var> is "<code data-x="">css</code>", then set <var>module script</var> to
and <var>moduleType</var> is "<code data-x="">css</code>", then set <var>module script</var> to
the result of <span>creating a CSS module script</span> given <var>source text</var> and
<var>module map settings object</var>.</p></li>

<li><p>If <var>MIME type essence</var> is a <span>JSON MIME type</span> and <var>module
type</var> is "<code data-x="">json</code>", then set <var>module script</var> to the result of
<li><p>If <var>MIME type essence</var> is a <span>JSON MIME type</span> and <var>moduleType</var>
is "<code data-x="">json</code>", then set <var>module script</var> to the result of
<span>creating a JSON module script</span> given <var>source text</var> and <var>module map
settings object</var>.</p></li>

<li>
<p><span data-x="map set">Set</span> <var>moduleMap</var>[(<var>url</var>, <var>module
type</var>)] to <var>module script</var>, and asynchronously complete this algorithm with
<var>module script</var>.</p>
<p><span data-x="map set">Set</span> <var>moduleMap</var>[(<var>url</var>,
<var>moduleType</var>)] to <var>module script</var>, and asynchronously complete this algorithm
with <var>module script</var>.</p>

<p class="note">It is intentional that the <span>module map</span> is keyed by the <span
data-x="concept-request-url">request URL</span>, whereas the <span
Expand Down Expand Up @@ -91997,13 +91984,11 @@ document.querySelector("button").addEventListener("click", bound);
href="#validate-requested-module-specifiers">marked as itself having a parse
error</a>.)</p></li>

<li><p>If <var>moduleRequest</var>.[[Assertions]] has a <span>Record</span> <var>entry</var>
such that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then let <var>module
type</var> be <var>entry</var>.[[Value]]. Otherwise let <var>module type</var> be "<code
data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be the result of running the <span>module type from module
request</span> steps given <var>moduleRequest</var>.</p></li>

<li><p>Let <var>childModule</var> be <var>moduleMap</var>[(<var>childURL</var>, <var>module
type</var>)].</p></li>
<li><p>Let <var>childModule</var> be <var>moduleMap</var>[(<var>childURL</var>,
<var>moduleType</var>)].</p></li>

<li><p>Assert: <var>childModule</var> is a <span>module script</span> (i.e., it is not "<code
data-x="">fetching</code>" or null); by now all <span data-x="module script">module
Expand Down Expand Up @@ -92146,14 +92131,12 @@ document.querySelector("button").addEventListener("click", bound);
a module specifier</span> given <var>script</var>'s <span data-x="concept-script-base-url">base
URL</span> and <var>requested</var>.[[Specifier]].</p></li>

<li><p>If <var>requested</var>.[[Assertions]] has a <span>Record</span> <var>entry</var> such
that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then let <var>module type</var>
be <var>entry</var>.[[Value]]. Otherwise let <var>module type</var> be "<code
data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be the result of running the <span>module type from module
request</span> steps given <var>requested</var>.</p></li>

<li>
<p>If <var>url</var> is failure, or if the result of running the <span>module type
allowed</span> steps given <var>module type</var> and <var>settings</var> is false, then:</p>
allowed</span> steps given <var>moduleType</var> and <var>settings</var> is false, then:</p>
<ol>
<li><p>Let <var>error</var> be a new <code>TypeError</code> exception.</p></li>

Expand Down Expand Up @@ -92245,16 +92228,45 @@ document.querySelector("button").addEventListener("click", bound);
<li><p>Return <var>script</var>.</p></li>
</ol>

<p>The <dfn>module type allowed</dfn> steps, given a <span>string</span> <var>module type</var>
<p>The <dfn>module type from module request</dfn> steps, given a <span>ModuleRequest
Record</span> <var>moduleRequest</var>, are as follows:</p>

<ol>
<li><p>Let <var>moduleType</var> be "<code data-x="">javascript</code>".</p></li>

<li>
<p>If <var>moduleRequest</var>.[[Assertions]] has a <span>Record</span> <var>entry</var> such
that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then:</p>

<ol>
<li>
<p>If <var>entry</var>.[[Value]] is "<code data-x="">javascript</code>", then set
<var>moduleType</var> to null.</p>

<p class="note">This specification uses the "<code data-x="">javascript</code>" module type
internally for <span data-x="JavaScript module script">JavaScript module scripts</span>, so
this step is needed to prevent modules from being imported using a "<code
data-x="">javascript</code>" type assertion (a null <var>moduleType</var> will cause the
<span>module type allowed</span> check to fail).</p>
</li>

<li><p>Otherwise, set <var>moduleType</var> to <var>entry</var>.[[Value]].</p></li>
</ol>
</li>

<li><p>Return <var>moduleType</var>.</p></li>
</ol>

<p>The <dfn>module type allowed</dfn> steps, given a <span>string</span> <var>moduleType</var>
and an <span>environment settings object</span> <var>settings</var>, are as follows:</p>

<ol>
<li><p>If <var>module type</var> is not "<code data-x="">javascript</code>", "<code
<li><p>If <var>moduleType</var> is not "<code data-x="">javascript</code>", "<code
data-x="">css</code>", or "<code data-x="">json</code>", then return false.</p></li>

<li><p>If <var>module type</var> is "<code data-x="">css</code>" and the
<li><p>If <var>moduleType</var> is "<code data-x="">css</code>" and the
<code>CSSStyleSheet</code> interface is not <span data-x="idl-exposed">exposed</span> in
<var>setting</var>'s <span data-x="environment settings object's Realm">Realm</span>, then
<var>settings</var>'s <span data-x="environment settings object's Realm">Realm</span>, then
return false.</p></li>

<li><p>Return true.</p></li>
Expand Down Expand Up @@ -93157,6 +93169,25 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
the correct type from succeeding.</p>
</div>

<div class="example">
<p>JavaScript module scripts are the default import type when importing from another JavaScript
module; that is, when an <code data-x="">import</code> statement lacks a <code
data-x="">type</code> import assertion the imported module script's type will be JavaScript.
Attempting to import a JavaScript resource using an <code data-x="">import</code> statement with
a <code data-x="">type</code> import assertion will fail:</p>

<pre><code class="html">&lt;script type="module">
// All of the following will fail, assuming that the imported .mjs files are served with a
// JavaScript MIME type. JavaScript module scripts are the default and cannot be imported with
// any import type assertion.
import foo from "./foo.mjs" assert { type: "javascript" };
import foo2 from "./foo2.mjs" assert { type: "js" };
import foo3 from "./foo3.mjs" assert { type: "" };
await import("./foo4.mjs", { assert: { type: null } });
await import("./foo5.mjs", { assert: { type: undefined } });
&lt;/script></code></pre>
</div>

<div w-nodev>

<p>To <dfn>resolve a module specifier</dfn> given a <span>URL</span> <var>base URL</var> and a
Expand Down Expand Up @@ -93394,14 +93425,12 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
same two arguments (either <a href="#validate-requested-module-specifiers">while creating the
corresponding module script</a>, or in <span>fetch an import() module script graph</span>).</p></li>

<li><p>If <var>moduleRequest</var>.[[Assertions]] has a <span>Record</span> <var>entry</var> such
that <var>entry</var>.[[Key]] is "<code data-x="">type</code>", then let <var>module type</var>
be <var>entry</var>.[[Value]]. Otherwise let <var>module type</var> be "<code
data-x="">javascript</code>".</p></li>
<li><p>Let <var>moduleType</var> be the result of running the <span>module type from module
request</span> steps given <var>moduleRequest</var>.</p></li>

<li><p>Let <var>resolved module script</var> be <var>moduleMap</var>[(<var>url</var>, <var>module
type</var>)]. (This entry must <span data-x="map exists">exist</span> for us to have gotten to
this point.)</p></li>
<li><p>Let <var>resolved module script</var> be <var>moduleMap</var>[(<var>url</var>,
<var>moduleType</var>)]. (This entry must <span data-x="map exists">exist</span> for us to have
gotten to this point.)</p></li>

<li><p>Assert: <var>resolved module script</var> is a <span>module script</span> (i.e., is not
null or "<code data-x="">fetching</code>").</p></li>
Expand Down

0 comments on commit c447169

Please sign in to comment.