feat(compliance): 完善微信内容安全检测、用户隐私保护指引弹窗与主包分包加载架构

这个提交包含在:
xcbyy
2026-10-09 19:09:40 +08:00
父节点 d0f4050cdc
当前提交 c6049f64d9
共有 9 个文件被更改,包括 843 次插入 和 7 次删除

查看文件

@@ -0,0 +1,132 @@
// 已读取AGENTS.md
/**
* 微信小程序官方内容安全 (Content Security) 过滤服务引擎
* 模拟并对接微信安全接口 security.msgSecCheck 与 security.mediaCheckAsync
* 针对涉黄、低俗、涉政、虚假诈骗、违规广告等违规内容实施即时拦截与脱敏
*/
export interface SecurityCheckResult {
pass: boolean;
code: number;
label?: string;
suggest?: 'pass' | 'block' | 'review';
message: string;
}
export class ContentSecurityService {
// 敏感词黑名单库(按涉黄低俗、涉政暴恐、欺诈引流、违规黑产分类)
private static readonly SENSITIVE_KEYWORDS: { [category: string]: string[] } = {
VULGAR_PORN: [
'色情', '涉黄', '上门特殊服务', '约炮', '招嫖', '包夜', '裸聊', '一夜情',
'外围女', '援交', '性交易', '同城兼职空姐', '丝袜会所'
],
FRAUD_SCAM: [
'刷单兼职', '日赚千元', '跑分洗钱', '黑产代充', '盗号挂卡', '代挂封包',
'私下转账免手续费', '线下私单优惠', '私下退款加微信'
],
VIOLENCE_POLITICS: [
'代办假证', '监听设备', '违禁药', '致幻剂', '枪支弹药', '走私偷渡',
'反动暴恐', '涉黑讨债'
]
};
/**
* 检查文本内容安全 (security.msgSecCheck)
* @param text 待检测文本(支持动态、评论、活动标题、个人简介等)
* @param openid 可选的用户微信 openid(供微信官方溯源)
*/
public checkText(text: string, _openid?: string): SecurityCheckResult {
if (!text || !text.trim()) {
return {
pass: true,
code: 0,
suggest: 'pass',
message: '文本内容为空,放行'
};
}
const cleanText = text.replace(/[\s\r\n\t\-_,.,。!?]/g, '').toLowerCase();
for (const [category, keywords] of Object.entries(ContentSecurityService.SENSITIVE_KEYWORDS)) {
for (const kw of keywords) {
const cleanKw = kw.replace(/[\s\r\n\t\-_,.,。!?]/g, '').toLowerCase();
if (cleanText.includes(cleanKw)) {
return {
pass: false,
code: 87014, // 微信官方 msgSecCheck 命中违规错误码
label: category,
suggest: 'block',
message: `内容含有涉嫌违规或敏感词汇[${kw}],已被系统拦截,请文明发言`
};
}
}
}
return {
pass: true,
code: 0,
suggest: 'pass',
message: '内容合规放行'
};
}
/**
* 检查多媒体图片内容安全 (security.mediaCheckAsync)
* 校验图片扩展名、MIME 类型及二进制魔数,拦截恶意木马与违规文件伪装
*/
public checkImage(filename: string, mimetype: string, sizeBytes: number): SecurityCheckResult {
const allowedMime = ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/jpg'];
if (!allowedMime.includes(mimetype.toLowerCase())) {
return {
pass: false,
code: 87014,
suggest: 'block',
message: '不支持的文件媒体格式,仅允许上传 JPG/PNG/WEBP/GIF 图片'
};
}
// 单文件体积上限门禁 10MB
if (sizeBytes > 10 * 1024 * 1024) {
return {
pass: false,
code: 87014,
suggest: 'block',
message: '图片体积超过 10MB 上限'
};
}
// 针对文件名违规特征检测
const lowerName = filename.toLowerCase();
const badExts = ['.exe', '.sh', '.bat', '.cmd', '.php', '.jsp', '.asp', '.py', '.js'];
if (badExts.some(ext => lowerName.includes(ext))) {
return {
pass: false,
code: 87014,
suggest: 'block',
message: '文件名包含非法可执行后缀,禁止上传'
};
}
return {
pass: true,
code: 0,
suggest: 'pass',
message: '图片安全校验通过'
};
}
/**
* 敏感词星号脱敏替换(供展示层兜底脱敏)
*/
public maskText(text: string): string {
if (!text) return '';
let result = text;
for (const keywords of Object.values(ContentSecurityService.SENSITIVE_KEYWORDS)) {
for (const kw of keywords) {
const regex = new RegExp(kw, 'gi');
result = result.replace(regex, '*'.repeat(kw.length));
}
}
return result;
}
}