This is an automated email from the ASF dual-hosted git repository. wangzx pushed a commit to branch gh-pages in repository https://gitbox.apache.org/repos/asf/echarts-examples.git
The following commit(s) were added to refs/heads/gh-pages by this push: new 967dc5f4 enhance sandbox security and optimize share hint toast 967dc5f4 is described below commit 967dc5f4398de3531d2d1b78450c521cfa1ddb0c Author: plainheart <y...@all-my-life.cn> AuthorDate: Wed May 11 19:33:19 2022 +0800 enhance sandbox security and optimize share hint toast Signed-off-by: plainheart <y...@all-my-life.cn> --- src/editor/Editor.vue | 13 ------- src/editor/Preview.vue | 11 +++--- src/editor/View.vue | 18 --------- src/editor/downloadExample.js | 4 +- src/editor/sandbox/setup.js | 91 +++++++++++++++++++++++++++++++++---------- 5 files changed, 79 insertions(+), 58 deletions(-) diff --git a/src/editor/Editor.vue b/src/editor/Editor.vue index 6797a3f0..a14442e6 100644 --- a/src/editor/Editor.vue +++ b/src/editor/Editor.vue @@ -251,7 +251,6 @@ export default { loadExampleCode().then((code) => { // No editor available. Set to runCode directly. store.runCode = parseSourceCode(code); - this.showShareHint(); }); } else { loadExampleCode().then((code) => { @@ -260,7 +259,6 @@ export default { if (store.initialCode !== CODE_CHANGED_FLAG) { store.initialCode = this.initialCode; } - this.showShareHint(); }); window.addEventListener('mousemove', (e) => { @@ -278,17 +276,6 @@ export default { }, methods: { - showShareHint() { - if (store.isSharedCode) { - this.$message.closeAll(); - this.$message({ - type: 'warning', - message: this.$t('editor.share.hint'), - duration: 5000, - showClose: true - }); - } - }, toExternalEditor(vendor) { const previewRef = this.$refs.preview; if (!previewRef) { diff --git a/src/editor/Preview.vue b/src/editor/Preview.vue index 2dafe445..889933f1 100644 --- a/src/editor/Preview.vue +++ b/src/editor/Preview.vue @@ -329,9 +329,6 @@ export default { mounted() { this.run(); - if (store.isSharedCode) { - this.showShareHint(); - } this.fetchVersionList(); }, @@ -368,6 +365,8 @@ export default { if (!this.debouncedRun) { // First run this.run(); + // show share hint on first run if code is user-shared + store.isSharedCode && this.showShareHint(); } else { this.debouncedRun(); } @@ -406,7 +405,9 @@ export default { this.sandbox = null; } }, - download, + download() { + download(store.isSharedCode && this.$t('editor.share.hint')); + }, screenshot() { this.sandbox && this.sandbox.screenshot( @@ -421,7 +422,7 @@ export default { type: 'warning', message: this.$t('editor.share.hint'), customClass: 'toast-shared-url', - duration: 5000, + duration: 8000, showClose: true }); }, diff --git a/src/editor/View.vue b/src/editor/View.vue index 6b436641..e6e96ad1 100644 --- a/src/editor/View.vue +++ b/src/editor/View.vue @@ -15,24 +15,6 @@ export default { loadExampleCode().then((code) => { store.runCode = parseSourceCode(code); }); - - this.showShareHint(); - }, - - methods: { - showShareHint() { - if (store.isSharedCode) { - this.$message.closeAll(); - this.$message({ - type: 'warning', - message: this.$t('editor.share.hint'), - duration: 5000, - showClose: true - }); - } - } } }; </script> - -<style lang="scss"></style> diff --git a/src/editor/downloadExample.js b/src/editor/downloadExample.js index de3dc386..f33d12ec 100644 --- a/src/editor/downloadExample.js +++ b/src/editor/downloadExample.js @@ -2,7 +2,7 @@ import { store } from '../common/store'; import { URL_PARAMS, SCRIPT_URLS } from '../common/config'; import { downloadBlob } from '../common/helper'; -export function download() { +export function download(shareHint) { const hasRootPath = store.sourceCode.indexOf('ROOT_PATH') > -1; const rootPathCode = hasRootPath ? `var ROOT_PATH = '${store.cdnRoot}';` : ''; const lang = store.locale && store.locale.indexOf('zh') > -1 ? 'zh-CN' : 'en'; @@ -18,7 +18,7 @@ export function download() { ); const echarts4Dir = SCRIPT_URLS.echartsDir.replace('{{version}}', '4.9.0'); const code = `<!-- - THIS EXAMPLE WAS DOWNLOADED FROM ${window.location.href} + ${shareHint || `THIS EXAMPLE WAS DOWNLOADED FROM ${window.location.href}`} --> <!DOCTYPE html> <html lang="${lang}" style="height: 100%"> diff --git a/src/editor/sandbox/setup.js b/src/editor/sandbox/setup.js index 4ed795e5..ed889d56 100644 --- a/src/editor/sandbox/setup.js +++ b/src/editor/sandbox/setup.js @@ -84,8 +84,51 @@ function setup(isShared) { { location: Object.freeze(JSON.parse(JSON.stringify(location))), document: (() => { - const nativeCreateElement = document.createElement; - const nativeCreateElementNS = document.createElementNS; + const disallowedElements = [ + 'script', + 'video', + 'audio', + 'iframe', + 'frame', + 'frameset', + 'embed', + 'object', + // PENDING + 'foreignobject' + ]; + const disallowedElementsMatcher = new RegExp( + `<(${disallowedElements.join('|')}).*>` + ); + const nativeSetters = { + innerHTML: Object.getOwnPropertyDescriptor( + Element.prototype, + 'innerHTML' + ).set, + outerHTML: Object.getOwnPropertyDescriptor( + Element.prototype, + 'outerHTML' + ).set, + innerText: Object.getOwnPropertyDescriptor( + HTMLElement.prototype, + 'innerText' + ).set, + outerText: Object.getOwnPropertyDescriptor( + HTMLElement.prototype, + 'outerText' + ).set + }; + ['inner', 'outer'].forEach((prop) => { + const htmlProp = prop + 'HTML'; + Object.defineProperty(Element.prototype, htmlProp, { + set(value) { + return ( + disallowedElementsMatcher.test(value) + ? nativeSetters[prop + 'Text'] + : nativeSetters[htmlProp] + ).call(this, value); + } + }); + }); const fakeDoc = document.cloneNode(); // To enable the created elements to be inserted to body // Object.defineProperties(fakeDoc, { @@ -100,24 +143,32 @@ function setup(isShared) { // } // } // }); - fakeDoc.createElement = function () { - const tagName = arguments[0]; - if (tagName && tagName.toLowerCase() === 'script') { - return console.error( - `Disallowed attempting to create dynamic script!` - ); - } - return nativeCreateElement.apply(document, arguments); - }; - fakeDoc.nativeCreateElementNS = function () { - const tagName = arguments[0]; - if (tagName && tagName.toLowerCase() === 'script') { - return console.error( - `Disallowed attempting to create dynamic script!` - ); - } - return nativeCreateElementNS.apply(document, arguments); - }; + [ + ['write', document.write, 0, true], + ['writeln', document.writeln, 0, true], + ['createElement', document.createElement, 0], + ['createElementNS', document.createElementNS, 1] + ].forEach((api) => { + const nativeFn = api[1]; + const argIndx = api[2]; + const fullTextSearch = api[3]; + fakeDoc[api[0]] = function () { + let val = arguments[argIndx]; + val && (val = val.toLowerCase()); + if ( + val && + (fullTextSearch + ? ((val = val.match(disallowedElementsMatcher)), + (val = val && val[1])) + : disallowedElements.includes(val)) + ) { + return console.error( + `Disallowed attempting to create ${val} element!` + ); + } + return nativeFn.apply(document, arguments); + }; + }); return fakeDoc; })(), history: void 0, --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org