blob: 61c92a87b66fd84d206025ae954782d9d33ec03a [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. 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:js_interop';
import 'package:web/web.dart';
// According to the CSP3 spec a nonce must be a valid base64 string.
final _noncePattern = RegExp('^[\\w+/_-]+[=]{0,2}\$');
/// Returns CSP nonce, if set for any script tag.
String? _findNonce() {
final elements = window.document.querySelectorAll('script');
for (var i = 0; i < elements.length; i++) {
final element = elements.item(i);
final nonceValue = (element as HTMLElement).nonce;
if (_noncePattern.hasMatch(nonceValue)) {
return nonceValue;
}
}
return null;
}
/// Creates a script that will run properly when strict CSP is enforced.
///
/// More specifically, the script has the correct `nonce` value set.
final HTMLElement Function() _createScript =
(() {
final nonce = _findNonce();
if (nonce == null) {
return () => document.createElement('script') as HTMLElement;
}
return () {
final scriptElement = document.createElement('script') as HTMLElement;
return scriptElement..setAttribute('nonce', nonce);
};
})();
/// Runs `window.$dartRunMain()` by injecting a script tag.
///
/// We do this so that we don't see user exceptions bubble up in our own error
/// handling zone.
void runMain() {
final scriptElement =
_createScript()..innerHTML = r'window.$dartRunMain();'.toJS;
document.body!.append(scriptElement.jsify()!);
// External tear-offs are not allowed.
// ignore: unnecessary_lambdas
Future.microtask(() => scriptElement.remove());
}