@@ -56,12 +56,53 @@ _flutter.loader = null;
5656 });
5757 }
5858
59+ /**
60+ * Handles the creation of a TrustedTypes `policy` that validates URLs based
61+ * on an (optional) incoming array of RegExes.
62+ */
63+ class FlutterTrustedTypesPolicy {
64+ /**
65+ * Constructs the policy.
66+ * @param {[RegExp]} validPatterns the patterns to test URLs
67+ * @param {String} policyName the policy name (optional)
68+ */
69+ constructor(validPatterns, policyName = "flutter-js") {
70+ const patterns = validPatterns || [
71+ /\.dart\.js$/,
72+ /^flutter_service_worker.js$/
73+ ];
74+ if (window.trustedTypes) {
75+ this.policy = trustedTypes.createPolicy(policyName, {
76+ createScriptURL: function(url) {
77+ const parsed = new URL(url, window.location);
78+ const file = parsed.pathname.split("/").pop();
79+ const matches = patterns.some((pattern) => pattern.test(file));
80+ if (matches) {
81+ return parsed.toString();
82+ }
83+ console.error(
84+ "URL rejected by TrustedTypes policy",
85+ policyName, ":", url, "(download prevented)");
86+ }
87+ });
88+ }
89+ }
90+ }
91+
5992 /**
6093 * Handles loading/reloading Flutter's service worker, if configured.
6194 *
6295 * @see: https://developers.google.com/web/fundamentals/primers/service-workers
6396 */
6497 class FlutterServiceWorkerLoader {
98+ /**
99+ * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
100+ * @param {TrustedTypesPolicy | undefined} policy
101+ */
102+ setTrustedTypesPolicy(policy) {
103+ this._ttPolicy = policy;
104+ }
105+
65106 /**
66107 * Returns a Promise that resolves when the latest Flutter service worker,
67108 * configured by `settings` has been loaded and activated.
@@ -84,8 +125,14 @@ _flutter.loader = null;
84125 timeoutMillis = 4000,
85126 } = settings;
86127
128+ // Apply the TrustedTypes policy, if present.
129+ let url = serviceWorkerUrl;
130+ if (this._ttPolicy != null) {
131+ url = this._ttPolicy.createScriptURL(url);
132+ }
133+
87134 const serviceWorkerActivation = navigator.serviceWorker
88- .register(serviceWorkerUrl )
135+ .register(url )
89136 .then(this._getNewServiceWorker)
90137 .then(this._waitForServiceWorkerActivation);
91138
@@ -173,6 +220,14 @@ _flutter.loader = null;
173220 this._scriptLoaded = false;
174221 }
175222
223+ /**
224+ * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
225+ * @param {TrustedTypesPolicy | undefined} policy
226+ */
227+ setTrustedTypesPolicy(policy) {
228+ this._ttPolicy = policy;
229+ }
230+
176231 /**
177232 * Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
178233 * user-specified `onEntrypointLoaded` callback with an EngineInitializer
@@ -262,7 +317,12 @@ _flutter.loader = null;
262317 _createScriptTag(url) {
263318 const scriptTag = document.createElement("script");
264319 scriptTag.type = "application/javascript";
265- scriptTag.src = url;
320+ // Apply TrustedTypes validation, if available.
321+ let trustedUrl = url;
322+ if (this._ttPolicy != null) {
323+ trustedUrl = this._ttPolicy.createScriptURL(url);
324+ }
325+ scriptTag.src = trustedUrl;
266326 return scriptTag;
267327 }
268328 }
@@ -285,9 +345,13 @@ _flutter.loader = null;
285345 async loadEntrypoint(options) {
286346 const { serviceWorker, ...entrypoint } = options || {};
287347
348+ // A Trusted Types policy that is going to be used by the loader.
349+ const flutterTT = new FlutterTrustedTypesPolicy();
350+
288351 // The FlutterServiceWorkerLoader instance could be injected as a dependency
289352 // (and dynamically imported from a module if not present).
290353 const serviceWorkerLoader = new FlutterServiceWorkerLoader();
354+ serviceWorkerLoader.setTrustedTypesPolicy(flutterTT.policy);
291355 await serviceWorkerLoader.loadServiceWorker(serviceWorker).catch(e => {
292356 // Regardless of what happens with the injection of the SW, the show must go on
293357 console.warn("Exception while loading service worker:", e);
@@ -296,6 +360,7 @@ _flutter.loader = null;
296360 // The FlutterEntrypointLoader instance could be injected as a dependency
297361 // (and dynamically imported from a module if not present).
298362 const entrypointLoader = new FlutterEntrypointLoader();
363+ entrypointLoader.setTrustedTypesPolicy(flutterTT.policy);
299364 // Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
300365 this.didCreateEngineInitializer =
301366 entrypointLoader.didCreateEngineInitializer.bind(entrypointLoader);
0 commit comments