diff --git a/frontend/package.json b/frontend/package.json index 78951c4b..e09558c7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "ace-builds": "^1.37.5", "core-js": "^3.40.0", "dayjs": "^1.11.10", + "dompurify": "^3.2.6", "epubjs": "^0.3.93", "filesize": "^10.1.1", "js-base64": "^3.7.7", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index d9d19749..66142514 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: dayjs: specifier: ^1.11.10 version: 1.11.13 + dompurify: + specifier: ^3.2.6 + version: 3.2.6 epubjs: specifier: ^0.3.93 version: 0.3.93 @@ -946,8 +949,8 @@ packages: resolution: {integrity: sha512-dF2iMMy8P9uKVHV/20LA1ulFLL+MKSbfMiixSmn6fpwqzvix38OIc7ebgnFbBqElvghZCW9ACtzKTGKsTGTWGA==} engines: {node: '>= 16'} - '@intlify/shared@11.1.3': - resolution: {integrity: sha512-pTFBgqa/99JRA2H1qfyqv97MKWJrYngXBA/I0elZcYxvJgcCw3mApAoPW3mJ7vx3j+Ti0FyKUFZ4hWxdjKaxvA==} + '@intlify/shared@11.1.7': + resolution: {integrity: sha512-4yZeMt2Aa/7n5Ehy4KalUlvt3iRLcg1tq9IBVfOgkyWFArN4oygn6WxgGIFibP3svpaH8DarbNaottq+p0gUZQ==} engines: {node: '>= 16'} '@intlify/shared@12.0.0-alpha.2': @@ -1174,6 +1177,9 @@ packages: '@types/node@22.10.10': resolution: {integrity: sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} @@ -1602,6 +1608,9 @@ packages: dom-walk@0.1.2: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} + dompurify@3.2.6: + resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + electron-to-chromium@1.5.67: resolution: {integrity: sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==} @@ -3628,7 +3637,7 @@ snapshots: '@intlify/shared@11.1.2': {} - '@intlify/shared@11.1.3': {} + '@intlify/shared@11.1.7': {} '@intlify/shared@12.0.0-alpha.2': {} @@ -3636,8 +3645,8 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0) '@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.2(vue@3.5.13(typescript@5.6.3))) - '@intlify/shared': 11.1.3 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.3)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.2(vue@3.5.13(typescript@5.6.3)))(vue@3.5.13(typescript@5.6.3)) + '@intlify/shared': 11.1.7 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.2(vue@3.5.13(typescript@5.6.3)))(vue@3.5.13(typescript@5.6.3)) '@rollup/pluginutils': 5.1.4(rollup@4.40.1) '@typescript-eslint/scope-manager': 8.21.0 '@typescript-eslint/typescript-estree': 8.21.0(typescript@5.6.3) @@ -3659,11 +3668,11 @@ snapshots: - supports-color - typescript - '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.3)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.2(vue@3.5.13(typescript@5.6.3)))(vue@3.5.13(typescript@5.6.3))': + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.2(vue@3.5.13(typescript@5.6.3)))(vue@3.5.13(typescript@5.6.3))': dependencies: '@babel/parser': 7.26.7 optionalDependencies: - '@intlify/shared': 11.1.3 + '@intlify/shared': 11.1.7 '@vue/compiler-dom': 3.5.13 vue: 3.5.13(typescript@5.6.3) vue-i18n: 11.1.2(vue@3.5.13(typescript@5.6.3)) @@ -3812,6 +3821,9 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/trusted-types@2.0.7': + optional: true + '@types/web-bluetooth@0.0.20': {} '@typescript-eslint/eslint-plugin@8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0)(typescript@5.6.3))(eslint@9.19.0)(typescript@5.6.3)': @@ -4282,6 +4294,10 @@ snapshots: dom-walk@0.1.2: {} + dompurify@3.2.6: + optionalDependencies: + '@types/trusted-types': 2.0.7 + electron-to-chromium@1.5.67: {} emoji-regex@8.0.0: {} diff --git a/frontend/src/views/files/Editor.vue b/frontend/src/views/files/Editor.vue index 9e9b6b68..d78e6afe 100644 --- a/frontend/src/views/files/Editor.vue +++ b/frontend/src/views/files/Editor.vue @@ -41,6 +41,7 @@ import url from "@/utils/url"; import ace, { Ace, version as ace_version } from "ace-builds"; import modelist from "ace-builds/src-noconflict/ext-modelist"; import "ace-builds/src-noconflict/ext-language_tools"; +import DOMPurify from "dompurify"; import HeaderBar from "@/components/header/HeaderBar.vue"; import Action from "@/components/header/Action.vue"; @@ -83,7 +84,7 @@ onMounted(() => { if (isMarkdownFile && isPreview.value) { const new_value = editor.value?.getValue() || ""; try { - previewContent.value = await marked(new_value); + previewContent.value = DOMPurify.sanitize(await marked(new_value)); } catch (error) { console.error("Failed to convert content to HTML:", error); previewContent.value = "";