fix(mp): 五专家组全面审计修复 — 安全+功能+UX+性能+代码质量
安全修复: - 移除硬编码管理员凭据 admin/Admin@2026,改用环境变量注入 - 移除 forceSetAuth 全局 bridge 方法,减少攻击面 - sanitizeHtml 从黑名单正则升级为白名单方式 - secure-storage 实现 XOR+Base64 加密存储,不再明文 - 添加旧数据迁移逻辑 migrateLegacyStorage 功能修复: - 新增咨询创建页(consultation/create),修复"发起咨询"按钮导航失败 - 修复咨询详情页长轮询可能永远不启动(dataLoadedRef → useState) - 新增 createSession service API - 预约页面从主包移至分包,配置 commonChunks 优化主包体积 UX 修复: - 65 处硬编码字号 → var(--tk-font-*) token 替换 - AI 聊天页 13 处、咨询详情页 14 处、医生端核心页 38 处 - StatusTag 色值对齐设计系统色板 - Loading 文字从 --tk-font-h1(28px) 修正为 --tk-font-body-sm - EmptyState 文字从 --tk-font-num(30px)/--tk-font-h2(22px) 修正 - 医生端 5 处硬编码颜色 → SCSS 变量
This commit is contained in:
@@ -1,7 +1,52 @@
|
||||
const DANGEROUS_TAG_RE = /<(?:script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>|\/?(?:iframe|object|embed|form|input|textarea|style|link|meta)\b[^>]*)>/gi;
|
||||
const DANGEROUS_ATTR_RE = /(?:\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)|(?:href|src)\s*=\s*(?:"(?:javascript|data):[^"]*"|'(?:javascript|data):[^']*'))/gi;
|
||||
const ALLOWED_TAGS = new Set([
|
||||
'p', 'br', 'hr', 'div', 'span',
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
||||
'ul', 'ol', 'li',
|
||||
'table', 'thead', 'tbody', 'tr', 'th', 'td',
|
||||
'strong', 'em', 'b', 'i', 'u', 's', 'del', 'ins',
|
||||
'blockquote', 'pre', 'code',
|
||||
'a', 'img',
|
||||
'dl', 'dt', 'dd',
|
||||
'sup', 'sub',
|
||||
]);
|
||||
|
||||
const ALLOWED_ATTRS: Record<string, Set<string>> = {
|
||||
'*': new Set(['class']),
|
||||
a: new Set(['href', 'title']),
|
||||
img: new Set(['src', 'alt', 'width', 'height']),
|
||||
td: new Set(['colspan', 'rowspan']),
|
||||
th: new Set(['colspan', 'rowspan']),
|
||||
};
|
||||
|
||||
const URL_ATTRS = new Set(['href', 'src']);
|
||||
const SAFE_URL_RE = /^(?:https?|mailto|tel):|^$/i;
|
||||
|
||||
const TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9]*)\b[^>]*\/?>/g;
|
||||
const ATTR_RE = /([a-zA-Z][a-zA-Z0-9-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
||||
|
||||
export function sanitizeHtml(html: string): string {
|
||||
if (!html) return '';
|
||||
return html.replace(DANGEROUS_TAG_RE, '').replace(DANGEROUS_ATTR_RE, '');
|
||||
|
||||
return html.replace(TAG_RE, (fullMatch, tagName) => {
|
||||
const tag = tagName.toLowerCase();
|
||||
|
||||
if (!ALLOWED_TAGS.has(tag)) return '';
|
||||
|
||||
const allowedForTag = ALLOWED_ATTRS[tag] || new Set();
|
||||
const allowedGlobal = ALLOWED_ATTRS['*'];
|
||||
const combined = new Set([...allowedForTag, ...allowedGlobal]);
|
||||
|
||||
const cleaned = fullMatch.replace(ATTR_RE, (_, attrName, dqVal, sqVal) => {
|
||||
const attr = attrName.toLowerCase();
|
||||
const val = dqVal ?? sqVal ?? '';
|
||||
|
||||
if (!combined.has(attr)) return '';
|
||||
|
||||
if (URL_ATTRS.has(attr) && !SAFE_URL_RE.test(val)) return '';
|
||||
|
||||
return ` ${attr}="${val}"`;
|
||||
});
|
||||
|
||||
return cleaned;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user