🐞 fix(WebUI): 解决XSS注入的问题

This commit is contained in:
IGCrystal
2025-07-04 22:39:32 +08:00
committed by Soulter
parent 7512bfc710
commit 14a8bb57df
5 changed files with 49 additions and 33 deletions
+1
View File
@@ -26,6 +26,7 @@
"js-md5": "^0.8.3",
"lodash": "4.17.21",
"marked": "^15.0.7",
"markdown-it": "^14.1.0",
"pinia": "2.1.6",
"remixicon": "3.5.0",
"vee-validate": "4.11.3",
@@ -1,7 +1,7 @@
<script setup>
import { ref, watch, onMounted, computed } from 'vue';
import axios from 'axios';
import { marked } from 'marked';
import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import { useI18n } from '@/i18n/composables';
@@ -74,29 +74,28 @@ function openRepoInNewTab() {
}
}
// 配置markdown-it,启用代码高亮
const md = new MarkdownIt({
html: true, // 启用HTML标签
breaks: true, // 换行转<br>
linkify: true, // 自动转链接
typographer: false, // 禁用智能引号
highlight: function(code, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(code, { language: lang }).value;
} catch (e) {
console.error(e);
}
}
return hljs.highlightAuto(code).value;
}
});
// 渲染Markdown内容
function renderMarkdown(content) {
if (!content) return '';
// 配置marked使用highlight.js进行语法高亮
marked.setOptions({
highlight: function(code, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(code, { language: lang }).value;
} catch (e) {
console.error(e);
}
}
return hljs.highlightAuto(code).value;
},
gfm: true, // GitHub Flavored Markdown
breaks: true, // Convert \n to <br>
headerIds: true, // Add id attributes to headers
mangle: false // Don't mangle email addresses
});
return marked(content);
return md.render(content);
}
// 刷新README内容
@@ -7,9 +7,17 @@ import LanguageSwitcher from '@/components/shared/LanguageSwitcher.vue';
import {md5} from 'js-md5';
import {useAuthStore} from '@/stores/auth';
import {useCommonStore} from '@/stores/common';
import {marked} from 'marked';
import MarkdownIt from 'markdown-it';
import { useI18n } from '@/i18n/composables';
// 配置markdown-it,默认安全设置
const md = new MarkdownIt({
html: false, // 启用HTML标签
breaks: true, // 换行转<br>
linkify: true, // 自动转链接
typographer: false // 禁用智能引号
});
const customizer = useCustomizerStore();
const { t } = useI18n();
let dialog = ref(false);
@@ -323,7 +331,7 @@ commonStore.getStartTime();
<div v-if="releaseMessage"
style="background-color: #646cff24; padding: 16px; border-radius: 10px; font-size: 14px; max-height: 400px; overflow-y: auto;"
v-html="marked(releaseMessage)" class="markdown-content">
v-html="md.render(releaseMessage)" class="markdown-content">
</div>
<div class="mb-4 mt-4">
+8 -5
View File
@@ -177,7 +177,7 @@
</v-avatar>
<div class="bot-message-content">
<div class="message-bubble bot-bubble">
<div v-html="marked(msg.message)" class="markdown-content"></div>
<div v-html="md.render(msg.message)" class="markdown-content"></div>
</div>
<div class="message-actions">
<v-btn :icon="getCopyIcon(index)" size="small" variant="text"
@@ -261,7 +261,7 @@
<script>
import { router } from '@/router';
import axios from 'axios';
import { marked } from 'marked';
import MarkdownIt from 'markdown-it';
import { ref } from 'vue';
import { useCustomizerStore } from '@/stores/customizer';
import { useI18n, useModuleI18n } from '@/i18n/composables';
@@ -270,8 +270,11 @@ import ProviderModelSelector from '@/components/chat/ProviderModelSelector.vue';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
marked.setOptions({
breaks: true,
// 配置markdown-it,启用代码高亮
const md = new MarkdownIt({
html: false, // 禁用HTML标签,防XSS
breaks: true, // 换行转<br>
linkify: true, // 自动转链接
highlight: function (code, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
@@ -303,7 +306,7 @@ export default {
t,
tm,
router,
marked,
md,
ref
};
},
+10 -5
View File
@@ -318,12 +318,16 @@
<script>
import axios from 'axios';
import { VueMonacoEditor } from '@guolao/vue-monaco-editor';
import { marked } from 'marked';
import MarkdownIt from 'markdown-it';
import { useCommonStore } from '@/stores/common';
import { useI18n, useModuleI18n } from '@/i18n/composables';
marked.setOptions({
breaks: true
// 配置markdown-it,默认安全设置
const md = new MarkdownIt({
html: false, // 禁用HTML标签(关键!)
breaks: true, // 换行转<br>
linkify: true, // 自动转链接
typographer: false // 禁用智能引号(避免干扰)
});
export default {
@@ -879,8 +883,9 @@ export default {
// 处理字符串内容
final_content = content;
} else if (!final_content) return this.tm('status.emptyContent');
// 使用marked处理Markdown格式
return marked(final_content);
// 使用markdown-it处理,默认安全(html: false会禁用HTML标签)
return md.render(final_content);
},
// 显示成功消息