@@ -56,12 +56,53 @@ _flutter.loader = null;
56
56
});
57
57
}
58
58
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
+
59
92
/**
60
93
* Handles loading/reloading Flutter's service worker, if configured.
61
94
*
62
95
* @see: https://developers.google.com/web/fundamentals/primers/service-workers
63
96
*/
64
97
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
+
65
106
/**
66
107
* Returns a Promise that resolves when the latest Flutter service worker,
67
108
* configured by `settings` has been loaded and activated.
@@ -84,8 +125,14 @@ _flutter.loader = null;
84
125
timeoutMillis = 4000,
85
126
} = settings;
86
127
128
+ // Apply the TrustedTypes policy, if present.
129
+ let url = serviceWorkerUrl;
130
+ if (this._ttPolicy != null) {
131
+ url = this._ttPolicy.createScriptURL(url);
132
+ }
133
+
87
134
const serviceWorkerActivation = navigator.serviceWorker
88
- .register(serviceWorkerUrl )
135
+ .register(url )
89
136
.then(this._getNewServiceWorker)
90
137
.then(this._waitForServiceWorkerActivation);
91
138
@@ -173,6 +220,14 @@ _flutter.loader = null;
173
220
this._scriptLoaded = false;
174
221
}
175
222
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
+
176
231
/**
177
232
* Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
178
233
* user-specified `onEntrypointLoaded` callback with an EngineInitializer
@@ -262,7 +317,12 @@ _flutter.loader = null;
262
317
_createScriptTag(url) {
263
318
const scriptTag = document.createElement("script");
264
319
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;
266
326
return scriptTag;
267
327
}
268
328
}
@@ -285,9 +345,13 @@ _flutter.loader = null;
285
345
async loadEntrypoint(options) {
286
346
const { serviceWorker, ...entrypoint } = options || {};
287
347
348
+ // A Trusted Types policy that is going to be used by the loader.
349
+ const flutterTT = new FlutterTrustedTypesPolicy();
350
+
288
351
// The FlutterServiceWorkerLoader instance could be injected as a dependency
289
352
// (and dynamically imported from a module if not present).
290
353
const serviceWorkerLoader = new FlutterServiceWorkerLoader();
354
+ serviceWorkerLoader.setTrustedTypesPolicy(flutterTT.policy);
291
355
await serviceWorkerLoader.loadServiceWorker(serviceWorker).catch(e => {
292
356
// Regardless of what happens with the injection of the SW, the show must go on
293
357
console.warn("Exception while loading service worker:", e);
@@ -296,6 +360,7 @@ _flutter.loader = null;
296
360
// The FlutterEntrypointLoader instance could be injected as a dependency
297
361
// (and dynamically imported from a module if not present).
298
362
const entrypointLoader = new FlutterEntrypointLoader();
363
+ entrypointLoader.setTrustedTypesPolicy(flutterTT.policy);
299
364
// Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
300
365
this.didCreateEngineInitializer =
301
366
entrypointLoader.didCreateEngineInitializer.bind(entrypointLoader);
0 commit comments