安全加固 + 结构清理:修注入/串写/竞态,DOMPurify 上线,后端补事务与 handler 测试

后端:
- ORDER BY 白名单(sanitizeOrder)堵住 ?order= SQL 注入,补回归测试
- 登录限速(每 IP 10 次失败/10 分钟 429)、TLS/反代下 Secure cookie、NewAPI 构造器
- Delete/setTags/MergeTags/DeleteTag 包事务;Archive 去 500 篇上限
- 列表接口裁剪:不传 content_md,长文 content_html 截 600,新增 content_len;health 探 DB

前端:
- EditorView 路由复用串写修复(RouterView :key + sync watch 回写原文章)
- v-html 出口统一过 DOMPurify(sanitizeHtml),stripTags 改 DOMParser
- 列表竞态防护(Home/Tag/Posts 请求序号)、TagView 分页修复
- 侧栏接口 30s 缓存去重;one:unauthorized 监听器泄漏修复
- 删 styles.css 498 行重复块;移除 tailwind/marked/vue-tsc 死依赖;CommandPalette a11y 语义
This commit is contained in:
Sakurasan
2026-09-21 23:59:09 +08:00
parent c762f06cd7
commit dd2994189a
25 changed files with 539 additions and 1411 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
<script setup>
import { computed } from 'vue'
import { site } from '../site'
import { relativeDate, stripTags, minutesLabel } from '../utils'
import { relativeDate, stripTags, minutesLabel, sanitizeHtml } from '../utils'
const props = defineProps({
post: { type: Object, required: true }
@@ -12,7 +12,7 @@ const isShort = computed(() => props.post.kind === 'short')
// 时间线里短文不铺全文,超过 5 行折叠;长文只显示摘要
const body = computed(() => {
if (!isShort.value) return props.post.summary || stripTags(props.post.content_html || '')
return props.post.content_html || ''
return sanitizeHtml(props.post.content_html)
})
// 长文没写摘要时,从正文里截一段纯文本
+1 -4
View File
@@ -9,10 +9,7 @@ const tags = ref([])
onMounted(async () => {
try {
const [posts, tagData] = await Promise.all([
publicApi.posts({ size: 5 }),
publicApi.tags()
])
const [posts, tagData] = await Promise.all([publicApi.latest(), publicApi.tags()])
latest.value = posts.items || []
tags.value = (tagData.tags || []).slice(0, 12)
} catch (e) {