Skip to content

Commit

Permalink
fix: unescaped scripts in report tpl (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyutaotao authored Dec 24, 2024
1 parent 1e76905 commit 5c582a8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 34 deletions.
29 changes: 22 additions & 7 deletions packages/midscene/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export function getLogDirByType(type: 'dump' | 'cache' | 'report' | 'tmp') {
let reportTpl: string | null = null;
function getReportTpl() {
if (ifInBrowser) {
if (!reportTpl && (window as any).midscene_report_tpl) {
reportTpl = (window as any).midscene_report_tpl;
if (!reportTpl && (window as any).get_midscene_report_tpl) {
reportTpl = (window as any).get_midscene_report_tpl();
}
assert(
reportTpl,
Expand All @@ -57,6 +57,15 @@ function getReportTpl() {
return reportTpl;
}

export function replaceStringWithFirstAppearance(
str: string,
target: string,
replacement: string,
) {
const index = str.indexOf(target);
return str.slice(0, index) + replacement + str.slice(index + target.length);
}

export function reportHTMLContent(
dumpData: string | ReportDumpWithAttributes[],
): string {
Expand All @@ -66,13 +75,15 @@ export function reportHTMLContent(
(Array.isArray(dumpData) && dumpData.length === 0) ||
typeof dumpData === 'undefined'
) {
reportContent = tpl.replace(
/\s+{{dump}}\s+/,
reportContent = replaceStringWithFirstAppearance(
tpl,
'{{dump}}',
`<script type="midscene_web_dump" type="application/json"></script>`,
);
} else if (typeof dumpData === 'string') {
reportContent = tpl.replace(
/\s+{{dump}}\s+/,
reportContent = replaceStringWithFirstAppearance(
tpl,
'{{dump}}',
`<script type="midscene_web_dump" type="application/json">${dumpData}</script>`,
);
} else {
Expand All @@ -84,7 +95,11 @@ export function reportHTMLContent(
' ',
)}\n>${dumpString}\n</script>`;
});
reportContent = tpl.replace(/\s+{{dump}}\s+/, dumps.join('\n'));
reportContent = replaceStringWithFirstAppearance(
tpl,
'{{dump}}',
dumps.join('\n'),
);
}
return reportContent;
}
Expand Down
4 changes: 1 addition & 3 deletions packages/visualizer/html/extension-sidepanel.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<html>
<title>Midscene.js Playground</title>

</html>

<head>
<title>Midscene.js Playground</title>
<link rel="stylesheet" href="/lib/popup.css">
</head>

Expand Down
6 changes: 4 additions & 2 deletions packages/visualizer/html/report.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

<title>Midscene Visualizer</title>
{{css}}
<!-- -->
{{js}}

</head>

Expand All @@ -19,6 +17,10 @@
{{dump}}

<div id="app" style="width: 100vw; height: 100vh;"></div>

<!-- -->
{{js}}

<script>
console.log(midsceneVisualizer);
midsceneVisualizer.default.mount('app');
Expand Down
67 changes: 45 additions & 22 deletions packages/visualizer/scripts/build-html.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { strict as assert } from 'node:assert';
import { rmSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { join } from 'node:path';
import { execa } from 'execa';
import {
ensureDirectoryExistence,
Expand Down Expand Up @@ -36,33 +36,52 @@ const outputExtensionPlayground = join(
);
const outputExtensionSidepanel = join(outputExtensionPageDir, 'sidepanel.html');

const replaceStringWithFirstAppearance = (
str: string,
target: string,
replacement: string,
) => {
const index = str.indexOf(target);
return str.slice(0, index) + replacement + str.slice(index + target.length);
};

/* report utils */
function emptyDumpReportHTML() {
return tplReplacer(reportTpl, {
css: `<style>\n${reportCSS}\n</style>\n`,
js: `<script>\n${reportJS}\n</script>`,
dump: '',
});
}

function scriptsOfSettingReportTpl() {
const leftAngleMark = '__left_angle_mark_';
return `window.midscene_report_tpl = ${JSON.stringify(
emptyDumpReportHTML(),
).replace(/</g, leftAngleMark)}.replace(/${leftAngleMark}/g, '<') ;`;
let html = replaceStringWithFirstAppearance(
reportTpl,
'{{css}}',
`<style>\n${reportCSS}\n</style>\n`,
);
html = replaceStringWithFirstAppearance(
html,
'{{js}}',
`<script>\n${reportJS}\n</script>`,
);
return html;
}

const tplRetrieverFn = `window.get_midscene_report_tpl = () => {
const tpl = document.getElementById('midscene_report_tpl').innerText;
const tplDecoded = decodeURIComponent(tpl);
return tplDecoded;
};`;
function putReportTplIntoHTML(html: string, outsourceMode = false) {
assert(html.indexOf('</body>') !== -1, 'HTML must contain </body>');

const tplWrapper = `<noscript id="midscene_report_tpl">\n${encodeURIComponent(
emptyDumpReportHTML(),
)}\n</noscript>`;

if (outsourceMode) {
// in Chrome extension
return html.replace(
'</body>',
`<script src="/lib/set-report-tpl.js"></script>\n</body>`,
`${tplWrapper}<script src="/lib/set-report-tpl.js"></script>\n</body>`,
);
}
return html.replace(
'</body>',
`<script>\n${scriptsOfSettingReportTpl()}\n</script>\n</body>`,
`${tplWrapper}<script>${tplRetrieverFn}</script>\n</body>`,
);
}

Expand All @@ -76,9 +95,11 @@ function reportHTMLWithDump(
dumpContent = `<script type="midscene_web_dump">\n${dumpJsonString}\n</script>`;
}

const reportHTML = tplReplacer(emptyDumpReportHTML(), {
dump: dumpContent,
});
const reportHTML = replaceStringWithFirstAppearance(
emptyDumpReportHTML(),
'{{dump}}',
dumpContent || '{{dump}}',
);

const html = putReportTplIntoHTML(reportHTML);
if (filePath) {
Expand All @@ -97,7 +118,7 @@ function buildExtension() {
// write the set-report-tpl.js into the extension
writeFileSync(
join(__dirname, '../unpacked-extension/lib/set-report-tpl.js'),
scriptsOfSettingReportTpl(),
tplRetrieverFn,
);

// playground.html
Expand All @@ -115,7 +136,7 @@ function buildExtension() {
// sidepanel.html
writeFileSync(
outputExtensionSidepanel,
putReportTplIntoHTML(extensionSidepanelTpl, true), // TODO: remove the inline script
putReportTplIntoHTML(extensionSidepanelTpl, true),
);
console.log(`HTML file generated successfully: ${outputExtensionSidepanel}`);

Expand Down Expand Up @@ -151,7 +172,9 @@ function buildReport() {
assert(reportHTMLContent.length >= 1000);
ensureDirectoryExistence(outputReportHTML);
writeFileSync(outputReportHTML, reportHTMLContent);
console.log(`HTML file generated successfully: ${outputReportHTML}`);
console.log(
`HTML file generated successfully: ${outputReportHTML}, size: ${reportHTMLContent.length}`,
);

// demo pages
for (const demo of demoData) {
Expand Down Expand Up @@ -179,6 +202,6 @@ function buildReport() {
);
}

buildExtension();
buildReport();
buildExtension();
packExtension();

0 comments on commit 5c582a8

Please sign in to comment.