Commit e12b963e authored by dpapad's avatar dpapad Committed by Commit Bot

WebUI: Migrate certificate viewer to JS modules.

Also change parse_html_subset.js to initialize the
parse-html-subset TrustedTypes policy lazily, only when it is
actually used, to avoid having to allow that policy in the CSP
configuration on the C++ side for cases where parse_html_subset.js
is just a transitive dependency and not actually used (which is
the case for chrome;//view-cert).

Bug: 1149868
Change-Id: I1a8f32f3289f6068c0eafbb80cdc046451fc028e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2544067
Commit-Queue: dpapad <dpapad@chromium.org>
Reviewed-by: default avatarRebekah Potter <rbpotter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830138}
parent 716bf8c0
......@@ -6,14 +6,16 @@ import("//chrome/common/features.gni")
import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
uses_js_modules = true
deps = [ ":certificate_viewer" ]
}
js_library("certificate_viewer") {
deps = [
"//ui/webui/resources/js:util",
"//ui/webui/resources/js/cr:ui",
"//ui/webui/resources/js/cr/ui:tabs",
"//ui/webui/resources/js/cr/ui:tree",
"//ui/webui/resources/js:cr.m",
"//ui/webui/resources/js:util.m",
"//ui/webui/resources/js/cr:ui.m",
"//ui/webui/resources/js/cr/ui:tabs.m",
"//ui/webui/resources/js/cr/ui:tree.m",
]
}
......@@ -7,17 +7,7 @@
<link rel="stylesheet" href="chrome://resources/css/tabs.css">
<link rel="stylesheet" href="chrome://resources/css/tree.css">
<link rel="stylesheet" href="certificate_viewer.css">
<script src="chrome://resources/js/load_time_data.js"></script>
<script src="strings.js"></script>
<script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/cr/ui.js"></script>
<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
<script src="chrome://resources/js/cr/ui/tabs.js"></script>
<script src="chrome://resources/js/cr/ui/tree.js"></script>
<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="certificate_viewer.js"></script>
<script type="module" src="certificate_viewer.js"></script>
</head>
<body>
<tabbox id="tabbox">
......
......@@ -2,8 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
'use strict';
import './strings.m.js';
import {assert} from 'chrome://resources/js/assert.m.js';
import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
import {decorate} from 'chrome://resources/js/cr/ui.m.js';
import {TabBox} from 'chrome://resources/js/cr/ui/tabs.m.js';
import {Tree, TreeItem} from 'chrome://resources/js/cr/ui/tree.m.js';
import {$} from 'chrome://resources/js/util.m.js';
/**
* @typedef {{
......@@ -18,7 +24,7 @@
* substituting in translated strings and requesting certificate details.
*/
function initialize() {
cr.ui.decorate('tabbox', cr.ui.TabBox);
decorate('tabbox', TabBox);
const args = JSON.parse(chrome.getVariableValue('dialogArguments'));
getCertificateInfo(/** @type {!CertificateInfo} */ (args));
......@@ -69,13 +75,13 @@
}
/**
* Initialize a cr.ui.Tree object from a given element using the specified
* Initialize a Tree object from a given element using the specified
* change handler.
* @param {!HTMLElement} tree The HTMLElement to style as a tree.
* @param {function()} handler Function to call when a node is selected.
*/
function initializeTree(tree, handler) {
cr.ui.decorate(tree, cr.ui.Tree);
decorate(tree, Tree);
tree['detail'] = {payload: {}, children: {}};
tree.addEventListener('change', handler);
}
......@@ -97,7 +103,7 @@
/**
* Expand all nodes of the given tree object.
* @param {!cr.ui.Tree} tree The tree object to expand all nodes on.
* @param {!Tree} tree The tree object to expand all nodes on.
*/
function revealTree(tree) {
tree.expanded = true;
......@@ -122,7 +128,7 @@
* @param {Object} hierarchy A dictionary containing the hierarchy.
*/
function createCertificateHierarchy(hierarchy) {
const treeItem = /** @type {!cr.ui.Tree} */ ($('hierarchy'));
const treeItem = /** @type {!Tree} */ ($('hierarchy'));
const root = constructTree(hierarchy[0]);
treeItem['detail'].children['root'] = root;
treeItem.add(root);
......@@ -138,12 +144,12 @@
}
/**
* Constructs a cr.ui.TreeItem corresponding to the passed in tree
* Constructs a TreeItem corresponding to the passed in tree
* @param {Object} tree Dictionary describing the tree structure.
* @return {!cr.ui.TreeItem} Tree node corresponding to the input dictionary.
* @return {!TreeItem} Tree node corresponding to the input dictionary.
*/
function constructTree(tree) {
const treeItem = new cr.ui.TreeItem({
const treeItem = new TreeItem({
label: tree.label,
detail: {payload: tree.payload ? tree.payload : {}, children: {}}
});
......@@ -160,7 +166,7 @@
* Clear any previous certificate fields in the tree.
*/
function clearCertificateFields() {
const treeItem = /** @type {!cr.ui.Tree} */ ($('cert-fields'));
const treeItem = /** @type {!Tree} */ ($('cert-fields'));
for (const key in treeItem['detail'].children) {
treeItem.remove(treeItem['detail'].children[key]);
delete treeItem['detail'].children[key];
......@@ -174,7 +180,7 @@
clearCertificateFields();
const item = $('hierarchy').selectedItem;
if (item && item.detail.payload.index !== undefined) {
cr.sendWithPromise('requestCertificateFields', item.detail.payload.index)
sendWithPromise('requestCertificateFields', item.detail.payload.index)
.then(onCertificateFields);
}
}
......@@ -186,7 +192,7 @@
*/
function onCertificateFields(certFields) {
clearCertificateFields();
const treeItem = /** @type {!cr.ui.Tree} */ ($('cert-fields'));
const treeItem = /** @type {!Tree} */ ($('cert-fields'));
treeItem.add(
treeItem['detail'].children['root'] = constructTree(certFields[0]));
revealTree(treeItem);
......@@ -219,4 +225,3 @@
}
document.addEventListener('DOMContentLoaded', initialize);
})();
......@@ -50,7 +50,10 @@ content::WebUIDataSource* GetWebUIDataSource(const std::string& host) {
html_source->OverrideContentSecurityPolicy(
network::mojom::CSPDirectiveName::TrustedTypes,
"trusted-types cr-ui-tree-js-static;");
"trusted-types cr-ui-tree-js-static certificate-test-script;");
html_source->OverrideContentSecurityPolicy(
network::mojom::CSPDirectiveName::ScriptSrc,
"script-src chrome://resources chrome://test 'self';");
html_source->UseStringsJs();
......
......@@ -18,8 +18,6 @@ CertificateViewerUITest.prototype = {
extraLibraries: [
'//third_party/mocha/mocha.js',
'//chrome/test/data/webui/mocha_adapter.js',
'test_util.js',
'certificate_viewer_dialog_test.js',
],
/**
......@@ -37,6 +35,23 @@ CertificateViewerUITest.prototype = {
},
};
// Helper for loading the Mocha test file as a JS module. Not using
// test_loader.html, as the test code needs to be loaded in the context of the
// dialog triggered with the ShowCertificateViewer() C++ call above.
function loadTestModule() {
const scriptPolicy =
window.trustedTypes.createPolicy('certificate-test-script', {
createScriptURL: () =>
'chrome://test/certificate_viewer_dialog_test.js',
});
const s = document.createElement('script');
s.type = 'module';
s.src = scriptPolicy.createScriptURL('');
document.body.appendChild(s);
return new Promise(function(resolve, reject) {
s.addEventListener('load', () => resolve());
});
}
// Include the bulk of c++ code.
// Certificate viewer UI tests are disabled on platforms with native certificate
......@@ -49,13 +64,19 @@ GEN('CertificateViewerUITest::CertificateViewerUITest() {}');
GEN('CertificateViewerUITest::~CertificateViewerUITest() {}');
TEST_F('CertificateViewerUITest', 'DialogURL', function() {
mocha.grep('DialogURL').run();
loadTestModule().then(() => {
mocha.grep('DialogURL').run();
});
});
TEST_F('CertificateViewerUITest', 'CommonName', function() {
mocha.grep('CommonName').run();
loadTestModule().then(() => {
mocha.grep('CommonName').run();
});
});
TEST_F('CertificateViewerUITest', 'Details', function() {
mocha.grep('Details').run();
loadTestModule().then(() => {
mocha.grep('Details').run();
});
});
......@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
GEN('#include "content/public/test/browser_test.h"');
import {$} from 'chrome://resources/js/util.m.js';
import {eventToPromise} from 'chrome://test/test_util.m.js';
/**
* Find the first tree item (in the certificate fields tree) with a value.
......@@ -34,7 +35,6 @@ suite('CertificateViewer', function() {
assertEquals('www.google.com', $('issued-cn').textContent);
});
test('Details', async function() {
var certHierarchy = $('hierarchy');
var certFields = $('cert-fields');
......@@ -49,7 +49,7 @@ suite('CertificateViewer', function() {
// Wait for the '-for-testing' event to fire only if |certFields| is not
// populated yet, otherwise don't wait, the event has already fired.
const whenLoaded = certFields.childNodes.length === 0 ?
test_util.eventToPromise(
eventToPromise(
'certificate-fields-updated-for-testing', document.body) :
Promise.resolve();
......
......@@ -84,14 +84,10 @@
* This policy maps a given string to a `TrustedHTML` object
* without performing any validation. Callsites must ensure
* that the resulting object will only be used in inert
* documents.
* documents. Initialized lazily.
* @type {!TrustedTypePolicy}
*/
let unsanitizedPolicy;
if (window.trustedTypes) {
unsanitizedPolicy = trustedTypes.createPolicy(
'parse-html-subset', {createHTML: untrustedHTML => untrustedHTML});
}
/**
* @param {!Array<string>} optTags an Array to merge.
......@@ -154,6 +150,10 @@
r.selectNode(doc.body);
if (window.trustedTypes) {
if (!unsanitizedPolicy) {
unsanitizedPolicy = trustedTypes.createPolicy(
'parse-html-subset', {createHTML: untrustedHTML => untrustedHTML});
}
s = unsanitizedPolicy.createHTML(s);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment