Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
88346922
Unverified
Commit
88346922
authored
Oct 21, 2022
by
David Iglesias
Committed by
GitHub
Oct 21, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[web] Use TrustedTypes in flutter.js and other tools (#112969)
parent
782baecc
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
160 additions
and
7 deletions
+160
-7
service_worker_test.dart
dev/bots/service_worker_test.dart
+12
-1
test.dart
dev/bots/test.dart
+2
-0
index_with_flutterjs_el_tt_on.html
...egration_tests/web/web/index_with_flutterjs_el_tt_on.html
+46
-0
bootstrap.dart
packages/flutter_tools/lib/src/web/bootstrap.dart
+29
-2
flutter_js.dart
...flutter_tools/lib/src/web/file_generators/flutter_js.dart
+67
-2
bootstrap_test.dart
.../flutter_tools/test/general.shard/web/bootstrap_test.dart
+4
-2
No files found.
dev/bots/service_worker_test.dart
View file @
88346922
...
@@ -25,12 +25,18 @@ final String _targetWithBlockedServiceWorkers = path.join('lib', 'service_worker
...
@@ -25,12 +25,18 @@ final String _targetWithBlockedServiceWorkers = path.join('lib', 'service_worker
final
String
_targetPath
=
path
.
join
(
_testAppDirectory
,
_target
);
final
String
_targetPath
=
path
.
join
(
_testAppDirectory
,
_target
);
enum
ServiceWorkerTestType
{
enum
ServiceWorkerTestType
{
// Mocks how FF disables service workers.
blockedServiceWorkers
,
blockedServiceWorkers
,
// Drops the main.dart.js directly on the page.
withoutFlutterJs
,
withoutFlutterJs
,
// Uses the standard, promise-based, flutterJS initialization.
withFlutterJs
,
withFlutterJs
,
// Uses the shorthand engineInitializer.autoStart();
withFlutterJsShort
,
withFlutterJsShort
,
// Uses onEntrypointLoaded callback instead of returned promise.
withFlutterJsEntrypointLoadedEvent
,
withFlutterJsEntrypointLoadedEvent
,
// Same as withFlutterJsEntrypointLoadedEvent, but with TrustedTypes enabled.
withFlutterJsTrustedTypesOn
,
// Entrypoint generated by `flutter create`.
// Entrypoint generated by `flutter create`.
generatedEntrypoint
,
generatedEntrypoint
,
}
}
...
@@ -44,10 +50,12 @@ Future<void> main() async {
...
@@ -44,10 +50,12 @@ Future<void> main() async {
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJs
);
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJs
);
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
);
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
);
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
);
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
);
await
runWebServiceWorkerTest
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsTrustedTypesOn
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withoutFlutterJs
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withoutFlutterJs
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJs
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJs
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
);
await
runWebServiceWorkerTestWithCachingResources
(
headless:
false
,
testType:
ServiceWorkerTestType
.
withFlutterJsTrustedTypesOn
);
await
runWebServiceWorkerTestWithGeneratedEntrypoint
(
headless:
false
);
await
runWebServiceWorkerTestWithGeneratedEntrypoint
(
headless:
false
);
await
runWebServiceWorkerTestWithBlockedServiceWorkers
(
headless:
false
);
await
runWebServiceWorkerTestWithBlockedServiceWorkers
(
headless:
false
);
...
@@ -112,6 +120,9 @@ String _testTypeToIndexFile(ServiceWorkerTestType type) {
...
@@ -112,6 +120,9 @@ String _testTypeToIndexFile(ServiceWorkerTestType type) {
case
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
:
case
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
:
indexFile
=
'index_with_flutterjs_entrypoint_loaded.html'
;
indexFile
=
'index_with_flutterjs_entrypoint_loaded.html'
;
break
;
break
;
case
ServiceWorkerTestType
.
withFlutterJsTrustedTypesOn
:
indexFile
=
'index_with_flutterjs_el_tt_on.html'
;
break
;
case
ServiceWorkerTestType
.
generatedEntrypoint
:
case
ServiceWorkerTestType
.
generatedEntrypoint
:
indexFile
=
'generated_entrypoint.html'
;
indexFile
=
'generated_entrypoint.html'
;
break
;
break
;
...
...
dev/bots/test.dart
View file @
88346922
...
@@ -1195,10 +1195,12 @@ Future<void> _runWebLongRunningTests() async {
...
@@ -1195,10 +1195,12 @@ Future<void> _runWebLongRunningTests() async {
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJs
),
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJs
),
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
),
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
),
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
),
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
),
()
=>
runWebServiceWorkerTest
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsTrustedTypesOn
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withoutFlutterJs
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withoutFlutterJs
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJs
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJs
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsShort
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsEntrypointLoadedEvent
),
()
=>
runWebServiceWorkerTestWithCachingResources
(
headless:
true
,
testType:
ServiceWorkerTestType
.
withFlutterJsTrustedTypesOn
),
()
=>
runWebServiceWorkerTestWithGeneratedEntrypoint
(
headless:
true
),
()
=>
runWebServiceWorkerTestWithGeneratedEntrypoint
(
headless:
true
),
()
=>
runWebServiceWorkerTestWithBlockedServiceWorkers
(
headless:
true
),
()
=>
runWebServiceWorkerTestWithBlockedServiceWorkers
(
headless:
true
),
()
=>
_runWebStackTraceTest
(
'profile'
,
'lib/stack_trace.dart'
),
()
=>
_runWebStackTraceTest
(
'profile'
,
'lib/stack_trace.dart'
),
...
...
dev/integration_tests/web/web/index_with_flutterjs_el_tt_on.html
0 → 100644
View file @
88346922
<!DOCTYPE HTML>
<!-- Copyright 2014 The Flutter Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<html>
<head>
<meta
charset=
"UTF-8"
>
<meta
content=
"IE=Edge"
http-equiv=
"X-UA-Compatible"
>
<title>
Integration test. App load with flutter.js and onEntrypointLoaded API. Trusted Types enabled.
</title>
<!-- Enable TrustedTypes for 'script'-->
<meta
http-equiv=
"Content-Security-Policy"
content=
"require-trusted-types-for 'script'"
>
<!-- iOS meta tags & icons -->
<meta
name=
"apple-mobile-web-app-capable"
content=
"yes"
>
<meta
name=
"apple-mobile-web-app-status-bar-style"
content=
"black"
>
<meta
name=
"apple-mobile-web-app-title"
content=
"Web Test"
>
<link
rel=
"manifest"
href=
"manifest.json"
>
<script>
// The value below is injected by flutter build, do not touch.
var
serviceWorkerVersion
=
null
;
</script>
<!-- This script adds the flutter initialization JS code -->
<script
src=
"flutter.js"
defer
></script>
</head>
<body>
<script>
window
.
addEventListener
(
'load'
,
function
(
ev
)
{
// Download main.dart.js
_flutter
.
loader
.
loadEntrypoint
({
onEntrypointLoaded
:
onEntrypointLoaded
,
serviceWorker
:
{
serviceWorkerVersion
:
serviceWorkerVersion
,
}
});
// Once the entrypoint is ready, do things!
async
function
onEntrypointLoaded
(
engineInitializer
)
{
const
appRunner
=
await
engineInitializer
.
initializeEngine
();
appRunner
.
runApp
();
}
});
</script>
</body>
</html>
packages/flutter_tools/lib/src/web/bootstrap.dart
View file @
88346922
...
@@ -94,18 +94,45 @@ document.addEventListener('dart-app-ready', function (e) {
...
@@ -94,18 +94,45 @@ document.addEventListener('dart-app-ready', function (e) {
styleSheet.parentNode.removeChild(styleSheet);
styleSheet.parentNode.removeChild(styleSheet);
});
});
// A map containing the URLs for the bootstrap scripts in debug.
let _scriptUrls = {
"mapper": "
$mapperUrl
",
"requireJs": "
$requireUrl
"
};
// Create a TrustedTypes policy so we can attach Scripts...
let _ttPolicy;
if (window.trustedTypes) {
_ttPolicy = trustedTypes.createPolicy("flutter-tools-bootstrap", {
createScriptURL: (url) => {
let scriptUrl = _scriptUrls[url];
if (!scriptUrl) {
console.error("Unknown Flutter Web bootstrap resource!", url);
}
return scriptUrl;
}
});
}
// Creates a TrustedScriptURL for a given `scriptName`.
// See `_scriptUrls` and `_ttPolicy` above.
function getTTScriptUrl(scriptName) {
let defaultUrl = _scriptUrls[scriptName];
return _ttPolicy ? _ttPolicy.createScriptURL(scriptName) : defaultUrl;
}
// Attach source mapping.
// Attach source mapping.
var mapperEl = document.createElement("script");
var mapperEl = document.createElement("script");
mapperEl.defer = true;
mapperEl.defer = true;
mapperEl.async = false;
mapperEl.async = false;
mapperEl.src =
"
$mapperUrl
"
;
mapperEl.src =
getTTScriptUrl("mapper")
;
document.head.appendChild(mapperEl);
document.head.appendChild(mapperEl);
// Attach require JS.
// Attach require JS.
var requireEl = document.createElement("script");
var requireEl = document.createElement("script");
requireEl.defer = true;
requireEl.defer = true;
requireEl.async = false;
requireEl.async = false;
requireEl.src =
"
$requireUrl
"
;
requireEl.src =
getTTScriptUrl("requireJs")
;
// This attribute tells require JS what to load as main (defined below).
// This attribute tells require JS what to load as main (defined below).
requireEl.setAttribute("data-main", "main_module.bootstrap");
requireEl.setAttribute("data-main", "main_module.bootstrap");
document.head.appendChild(requireEl);
document.head.appendChild(requireEl);
...
...
packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart
View file @
88346922
...
@@ -56,12 +56,53 @@ _flutter.loader = null;
...
@@ -56,12 +56,53 @@ _flutter.loader = null;
});
});
}
}
/**
* Handles the creation of a TrustedTypes `policy` that validates URLs based
* on an (optional) incoming array of RegExes.
*/
class FlutterTrustedTypesPolicy {
/**
* Constructs the policy.
* @param {[RegExp]} validPatterns the patterns to test URLs
* @param {String} policyName the policy name (optional)
*/
constructor(validPatterns, policyName = "flutter-js") {
const patterns = validPatterns || [
/
\
.dart
\
.js
$
/,
/^flutter_service_worker.js
$
/
];
if (window.trustedTypes) {
this.policy = trustedTypes.createPolicy(policyName, {
createScriptURL: function(url) {
const parsed = new URL(url, window.location);
const file = parsed.pathname.split("/").pop();
const matches = patterns.some((pattern) => pattern.test(file));
if (matches) {
return parsed.toString();
}
console.error(
"URL rejected by TrustedTypes policy",
policyName, ":", url, "(download prevented)");
}
});
}
}
}
/**
/**
* Handles loading/reloading Flutter'
s
service
worker
,
if
configured
.
* Handles loading/reloading Flutter'
s
service
worker
,
if
configured
.
*
*
*
@see
:
https:
//developers.google.com/web/fundamentals/primers/service-workers
*
@see
:
https:
//developers.google.com/web/fundamentals/primers/service-workers
*/
*/
class
FlutterServiceWorkerLoader
{
class
FlutterServiceWorkerLoader
{
/**
* Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
* @param {TrustedTypesPolicy | undefined} policy
*/
setTrustedTypesPolicy
(
policy
)
{
this
.
_ttPolicy
=
policy
;
}
/**
/**
* Returns a Promise that resolves when the latest Flutter service worker,
* Returns a Promise that resolves when the latest Flutter service worker,
* configured by `settings` has been loaded and activated.
* configured by `settings` has been loaded and activated.
...
@@ -84,8 +125,14 @@ _flutter.loader = null;
...
@@ -84,8 +125,14 @@ _flutter.loader = null;
timeoutMillis
=
4000
,
timeoutMillis
=
4000
,
}
=
settings
;
}
=
settings
;
// Apply the TrustedTypes policy, if present.
let
url
=
serviceWorkerUrl
;
if
(
this
.
_ttPolicy
!=
null
)
{
url
=
this
.
_ttPolicy
.
createScriptURL
(
url
);
}
const
serviceWorkerActivation
=
navigator
.
serviceWorker
const
serviceWorkerActivation
=
navigator
.
serviceWorker
.
register
(
serviceWorkerU
rl
)
.
register
(
u
rl
)
.
then
(
this
.
_getNewServiceWorker
)
.
then
(
this
.
_getNewServiceWorker
)
.
then
(
this
.
_waitForServiceWorkerActivation
);
.
then
(
this
.
_waitForServiceWorkerActivation
);
...
@@ -173,6 +220,14 @@ _flutter.loader = null;
...
@@ -173,6 +220,14 @@ _flutter.loader = null;
this
.
_scriptLoaded
=
false
;
this
.
_scriptLoaded
=
false
;
}
}
/**
* Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
* @param {TrustedTypesPolicy | undefined} policy
*/
setTrustedTypesPolicy
(
policy
)
{
this
.
_ttPolicy
=
policy
;
}
/**
/**
* Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
* Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
* user-specified `onEntrypointLoaded` callback with an EngineInitializer
* user-specified `onEntrypointLoaded` callback with an EngineInitializer
...
@@ -262,7 +317,12 @@ _flutter.loader = null;
...
@@ -262,7 +317,12 @@ _flutter.loader = null;
_createScriptTag
(
url
)
{
_createScriptTag
(
url
)
{
const
scriptTag
=
document
.
createElement
(
"script"
);
const
scriptTag
=
document
.
createElement
(
"script"
);
scriptTag
.
type
=
"application/javascript"
;
scriptTag
.
type
=
"application/javascript"
;
scriptTag
.
src
=
url
;
// Apply TrustedTypes validation, if available.
let
trustedUrl
=
url
;
if
(
this
.
_ttPolicy
!=
null
)
{
trustedUrl
=
this
.
_ttPolicy
.
createScriptURL
(
url
);
}
scriptTag
.
src
=
trustedUrl
;
return
scriptTag
;
return
scriptTag
;
}
}
}
}
...
@@ -285,9 +345,13 @@ _flutter.loader = null;
...
@@ -285,9 +345,13 @@ _flutter.loader = null;
async
loadEntrypoint
(
options
)
{
async
loadEntrypoint
(
options
)
{
const
{
serviceWorker
,
...
entrypoint
}
=
options
||
{};
const
{
serviceWorker
,
...
entrypoint
}
=
options
||
{};
// A Trusted Types policy that is going to be used by the loader.
const
flutterTT
=
new
FlutterTrustedTypesPolicy
();
// The FlutterServiceWorkerLoader instance could be injected as a dependency
// The FlutterServiceWorkerLoader instance could be injected as a dependency
// (and dynamically imported from a module if not present).
// (and dynamically imported from a module if not present).
const
serviceWorkerLoader
=
new
FlutterServiceWorkerLoader
();
const
serviceWorkerLoader
=
new
FlutterServiceWorkerLoader
();
serviceWorkerLoader
.
setTrustedTypesPolicy
(
flutterTT
.
policy
);
await
serviceWorkerLoader
.
loadServiceWorker
(
serviceWorker
).
catch
(
e
=>
{
await
serviceWorkerLoader
.
loadServiceWorker
(
serviceWorker
).
catch
(
e
=>
{
// Regardless of what happens with the injection of the SW, the show must go on
// Regardless of what happens with the injection of the SW, the show must go on
console
.
warn
(
"Exception while loading service worker:"
,
e
);
console
.
warn
(
"Exception while loading service worker:"
,
e
);
...
@@ -296,6 +360,7 @@ _flutter.loader = null;
...
@@ -296,6 +360,7 @@ _flutter.loader = null;
// The FlutterEntrypointLoader instance could be injected as a dependency
// The FlutterEntrypointLoader instance could be injected as a dependency
// (and dynamically imported from a module if not present).
// (and dynamically imported from a module if not present).
const
entrypointLoader
=
new
FlutterEntrypointLoader
();
const
entrypointLoader
=
new
FlutterEntrypointLoader
();
entrypointLoader
.
setTrustedTypesPolicy
(
flutterTT
.
policy
);
// Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
// Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
this
.
didCreateEngineInitializer
=
this
.
didCreateEngineInitializer
=
entrypointLoader
.
didCreateEngineInitializer
.
bind
(
entrypointLoader
);
entrypointLoader
.
didCreateEngineInitializer
.
bind
(
entrypointLoader
);
...
...
packages/flutter_tools/test/general.shard/web/bootstrap_test.dart
View file @
88346922
...
@@ -14,9 +14,11 @@ void main() {
...
@@ -14,9 +14,11 @@ void main() {
mapperUrl:
'mapper.js'
,
mapperUrl:
'mapper.js'
,
);
);
// require js source is interpolated correctly.
// require js source is interpolated correctly.
expect
(
result
,
contains
(
'requireEl.src = "require.js";'
));
expect
(
result
,
contains
(
'"requireJs": "require.js"'
));
expect
(
result
,
contains
(
'requireEl.src = getTTScriptUrl("requireJs");'
));
// stack trace mapper source is interpolated correctly.
// stack trace mapper source is interpolated correctly.
expect
(
result
,
contains
(
'mapperEl.src = "mapper.js";'
));
expect
(
result
,
contains
(
'"mapper": "mapper.js"'
));
expect
(
result
,
contains
(
'mapperEl.src = getTTScriptUrl("mapper");'
));
// data-main is set to correct bootstrap module.
// data-main is set to correct bootstrap module.
expect
(
result
,
contains
(
'requireEl.setAttribute("data-main", "main_module.bootstrap");'
));
expect
(
result
,
contains
(
'requireEl.setAttribute("data-main", "main_module.bootstrap");'
));
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment