-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core, web): add support for TrustedType (#10312)
* feat(core): support TrustedType * feat(core): support TrustedType * feat(core): support TrustedType * feat(core): add trusted types support * feat(core): add trusted types support * feat(core): add trusted types support * feat(core): add trusted types support * feat(core): add trusted types support * feat(core): add trusted types support * feat(core): add trusted types support * feat(core): add documentation
- Loading branch information
Showing
8 changed files
with
295 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 55 additions & 7 deletions
62
packages/firebase_core/firebase_core/example/web/index.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,61 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<!-- | ||
If you are serving your web app in a path other than the root, change the | ||
href value below to reflect the base path you are serving from. | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Firebase Core Example</title> | ||
</head> | ||
The path provided below has to start and end with a slash "/" in order for | ||
it to work correctly. | ||
<body> | ||
<script src="main.dart.js" type="application/javascript"></script> | ||
</body> | ||
For more details: | ||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base | ||
This is a placeholder for base href that will be replaced by the value of | ||
the `--base-href` argument provided to `flutter build`. | ||
--> | ||
<base href="$FLUTTER_BASE_HREF" /> | ||
|
||
<meta charset="UTF-8" /> | ||
<meta content="IE=Edge" http-equiv="X-UA-Compatible" /> | ||
|
||
<meta | ||
http-equiv="Content-Security-Policy" | ||
content="require-trusted-types-for 'script'" | ||
/> | ||
|
||
<title>Firebase Core Example</title> | ||
<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> | ||
document.addEventListener( | ||
'securitypolicyviolation', | ||
console.error.bind(console) | ||
); | ||
|
||
window.addEventListener('load', function (ev) { | ||
// Download main.dart.js | ||
_flutter.loader | ||
.loadEntrypoint({ | ||
serviceWorker: { | ||
serviceWorkerVersion: serviceWorkerVersion, | ||
}, | ||
}) | ||
.then(function (engineInitializer) { | ||
return engineInitializer.initializeEngine(); | ||
}) | ||
.then(function (appRunner) { | ||
return appRunner.runApp(); | ||
}); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
141 changes: 141 additions & 0 deletions
141
packages/firebase_core/firebase_core_web/lib/src/interop/js.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
// Copyright 2013 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. | ||
|
||
/* | ||
// DOM shim. This file contains everything we need from the DOM API written as | ||
// @staticInterop, so we don't need dart:html | ||
// https://developer.mozilla.org/en-US/docs/Web/API/ | ||
*/ | ||
|
||
import 'package:js/js.dart'; | ||
|
||
/// console interface | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
abstract class DomConsole {} | ||
|
||
/// The interface of window.console | ||
extension DomConsoleExtension on DomConsole { | ||
/// console.debug | ||
external DomConsoleDumpFn get debug; | ||
|
||
/// console.info | ||
external DomConsoleDumpFn get info; | ||
|
||
/// console.log | ||
external DomConsoleDumpFn get log; | ||
|
||
/// console.warn | ||
external DomConsoleDumpFn get warn; | ||
|
||
/// console.error | ||
external DomConsoleDumpFn get error; | ||
} | ||
|
||
/// Fakey variadic-type for console-dumping methods (like console.log or info). | ||
typedef DomConsoleDumpFn = void Function( | ||
Object? arg, [ | ||
Object? arg2, | ||
Object? arg3, | ||
Object? arg4, | ||
Object? arg5, | ||
Object? arg6, | ||
Object? arg7, | ||
Object? arg8, | ||
Object? arg9, | ||
Object? arg10, | ||
]); | ||
|
||
/// Error object | ||
@JS('Error') | ||
@staticInterop | ||
abstract class DomError {} | ||
|
||
/// Methods on the error object | ||
extension DomErrorExtension on DomError { | ||
/// Error message. | ||
external String? get message; | ||
|
||
/// Stack trace. | ||
external String? get stack; | ||
|
||
/// Error name. This is determined by the constructor function. | ||
external String get name; | ||
|
||
/// Error cause indicating the reason why the current error is thrown. | ||
/// | ||
/// This is usually another caught error, or the value provided as the `cause` | ||
/// property of the Error constructor's second argument. | ||
external Object? get cause; | ||
} | ||
|
||
/* | ||
// Trusted Types API (TrustedTypePolicy, TrustedScript, TrustedScriptURL) | ||
// https://developer.mozilla.org/en-US/docs/Web/API/TrustedTypesAPI | ||
*/ | ||
|
||
/// A factory to create `TrustedTypePolicy` objects. | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
abstract class DomTrustedTypePolicyFactory {} | ||
|
||
/// (Some) methods of the [DomTrustedTypePolicyFactory]: | ||
extension DomTrustedTypePolicyFactoryExtension on DomTrustedTypePolicyFactory { | ||
/// createPolicy | ||
external DomTrustedTypePolicy createPolicy( | ||
String policyName, | ||
DomTrustedTypePolicyOptions? policyOptions, | ||
); | ||
} | ||
|
||
/// Options to create a trusted type policy. | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
abstract class DomTrustedTypePolicyOptions { | ||
/// Constructs a TrustedPolicyOptions object in JavaScript. | ||
/// | ||
/// The following properties need to be manually wrapped in [allowInterop] | ||
/// before being passed to this constructor: [createScriptURL]. | ||
external factory DomTrustedTypePolicyOptions({ | ||
DomCreateScriptUrlOptionFn? createScriptURL, | ||
}); | ||
} | ||
|
||
/// Type of the function to configure createScriptURL | ||
typedef DomCreateScriptUrlOptionFn = String Function(String input); | ||
|
||
/// An instance of a TrustedTypePolicy | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
abstract class DomTrustedTypePolicy {} | ||
|
||
/// (Some) methods of the [DomTrustedTypePolicy] | ||
extension DomTrustedTypePolicyExtension on DomTrustedTypePolicy { | ||
/// Create a `TrustedScriptURL` for the given [input]. | ||
external DomTrustedScriptUrl createScriptURL(String input); | ||
} | ||
|
||
/// An instance of a DomTrustedScriptUrl | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
abstract class DomTrustedScriptUrl {} | ||
|
||
// Getters | ||
|
||
/// window.trustedTypes (may or may not be supported by the browser) | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
external DomTrustedTypePolicyFactory? get trustedTypes; | ||
|
||
/// window.console | ||
@JS() | ||
@staticInterop | ||
@anonymous | ||
external DomConsole get console; |
32 changes: 32 additions & 0 deletions
32
packages/firebase_core/firebase_core_web/test/firebase_core_tt_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright 2013 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. | ||
|
||
@TestOn('browser') | ||
import 'package:firebase_core_web/firebase_core_web.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
import 'tools.dart'; | ||
|
||
// NOTE: This file needs to be separated from the others because Content | ||
// Security Policies can never be *relaxed* once set. | ||
|
||
void main() { | ||
group('injectScript (TrustedTypes configured)', () { | ||
injectMetaTag(<String, String>{ | ||
'http-equiv': 'Content-Security-Policy', | ||
'content': "trusted-types flutterfire-firebase_core 'allow-duplicates';", | ||
}); | ||
|
||
test('Should inject Firebase Core script properly', () { | ||
final coreWeb = FirebaseCoreWeb(); | ||
final version = coreWeb.firebaseSDKVersion; | ||
final Future<void> done = coreWeb.injectSrcScript( | ||
'https://www.gstatic.com/firebasejs/$version/firebase-app.js', | ||
'firebase_core', | ||
); | ||
|
||
expect(done, isA<Future<void>>()); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright 2020 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:html'; | ||
|
||
import 'package:firebase_core_web/src/interop/js.dart' as dom; | ||
import 'package:js/js_util.dart' as js_util; | ||
|
||
/// Injects a `<meta>` tag with the provided [attributes] into the [dom.document]. | ||
void injectMetaTag(Map<String, String> attributes) { | ||
final Element meta = document.createElement('meta'); | ||
for (final MapEntry<String, String> attribute in attributes.entries) { | ||
js_util.callMethod( | ||
meta, | ||
'setAttribute', | ||
<String>[attribute.key, attribute.value], | ||
); | ||
} | ||
document.head?.append(meta); | ||
} |
Just a note here, the
script.text
assignment will still throw a Trusted Types violation as we're assigning a plain string value. We would need to create and assign aTrustedScript
toscript.text
to avoid the TT violation.