fix(mp): 安全 P0 修复 + 架构 Hook 层补充 + 五专家组分析报告
安全修复: - 提取 sanitizeHtml 共享工具,修复 article/detail RichText XSS 风险 - request.ts 生产环境强制 HTTPS,消除 HTTP 回退风险 - 错误信息净化:后端错误码映射为用户友好消息,不再透传原始内容 - Token 生命周期管理:利用 expires_in 记录过期时间,请求前主动刷新 工程修复: - Babel 依赖从 dependencies 移至 devDependencies(包体积优化) 架构改进: - 新增 usePagination hook(分页加载 + hasMore + refresh,10+ 页面可复用) - 新增 useAuthRequired hook(登录态 + 患者档案 + 角色判断统一入口) - 新增 usePageRefresh hook(下拉刷新统一封装,17 页面可复用) 文档: - 五专家组深度分析+头脑风暴报告(架构7.2/安全5.5/UX6.0/工程5.5/产品7.2)
This commit is contained in:
@@ -3,6 +3,7 @@ import { View, Text, RichText } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import { getAiAnalysisDetail, type AiAnalysisItem } from '@/services/ai-analysis';
|
||||
import Loading from '@/components/Loading';
|
||||
import { sanitizeHtml } from '@/utils/sanitize-html';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -13,29 +14,10 @@ const TYPE_LABELS: Record<string, string> = {
|
||||
report_summary_generation: '报告摘要',
|
||||
};
|
||||
|
||||
/** 移除危险的 HTML 标签和事件属性,防止 XSS */
|
||||
function sanitizeHtml(html: string): string {
|
||||
return html
|
||||
// 移除 <script> 标签及其内容
|
||||
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
||||
// 移除 <iframe>, <object>, <embed>, <form>, <input>, <textarea>, <style> 标签
|
||||
.replace(/<\/?(?:iframe|object|embed|form|input|textarea|style)\b[^>]*>/gi, '')
|
||||
// 移除 <link> 和 <meta> 标签
|
||||
.replace(/<\/?(?:link|meta)\b[^>]*>/gi, '')
|
||||
// 移除所有 on* 事件属性 (onclick, onerror, onload 等)
|
||||
.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi, '')
|
||||
// 移除 javascript: 和 data: 协议的 href/src 属性
|
||||
.replace(/(href|src)\s*=\s*(?:"javascript:[^"]*"|'javascript:[^']*')/gi, '')
|
||||
.replace(/(href|src)\s*=\s*(?:"data:[^"]*"|'data:[^']*')/gi, '');
|
||||
}
|
||||
|
||||
function markdownToHtml(md: string): string {
|
||||
// 先转义 markdown 中可能存在的原始 HTML 标签
|
||||
const escaped = sanitizeHtml(md);
|
||||
return escaped
|
||||
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
|
||||
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
|
||||
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
|
||||
.replace(/^(#{1,3}) (.+)$/gm, (_, h: string, t: string) => `<h${h.length}>${t}</h${h.length}>`)
|
||||
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
||||
.replace(/^- (.+)$/gm, '<li>$1</li>')
|
||||
|
||||
@@ -3,6 +3,7 @@ import { View, Text, RichText } from '@tarojs/components';
|
||||
import Taro, { useRouter, useShareAppMessage } from '@tarojs/taro';
|
||||
import { getArticleDetail, getPublicArticleDetail, Article } from '../../../services/article';
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
import { sanitizeHtml } from '@/utils/sanitize-html';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import { useAuthStore } from '../../../stores/auth';
|
||||
import './index.scss';
|
||||
@@ -82,7 +83,7 @@ export default function ArticleDetail() {
|
||||
{/* 正文 */}
|
||||
<View className='article-content'>
|
||||
<RichText
|
||||
nodes={article.content || ''}
|
||||
nodes={sanitizeHtml(article.content || '')}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
Reference in New Issue
Block a user