feat(compliance): 完善微信内容安全检测、用户隐私保护指引弹窗与主包分包加载架构
这个提交包含在:
@@ -9,6 +9,7 @@ import { CompanionOrderService } from './core/order/companion-order.service';
|
||||
import { AuthRoleManager, UserRoleFlag, WorkMode } from './core/auth/auth-role.manager';
|
||||
import { FinanceCalculator } from './core/finance/finance.calculator';
|
||||
import { ServiceCategoryManager, CompanionTrack, ExpenseBurdenType } from './core/companion/service-category';
|
||||
import { ContentSecurityService } from './core/security/content-security.service';
|
||||
import { initDatabase } from './db/mysql';
|
||||
import { repo } from './db/repository';
|
||||
|
||||
@@ -56,6 +57,7 @@ export const orderService = new CompanionOrderService();
|
||||
export const authRoleManager = new AuthRoleManager();
|
||||
export const financeCalculator = new FinanceCalculator();
|
||||
export const categoryManager = new ServiceCategoryManager();
|
||||
export const contentSecurityService = new ContentSecurityService();
|
||||
|
||||
// 1. 基础探活与健康检查
|
||||
app.get('/', (_req: Request, res: Response) => {
|
||||
@@ -246,6 +248,23 @@ const handleFileUpload = (req: Request, res: Response) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 微信内容安全多媒体合规性检测 (mediaCheckAsync)
|
||||
const mediaCheck = contentSecurityService.checkImage(
|
||||
req.file.originalname,
|
||||
req.file.mimetype,
|
||||
req.file.size
|
||||
);
|
||||
if (!mediaCheck.pass) {
|
||||
// 若拦截到非法文件特征,立即删除已写入的临时文件
|
||||
try {
|
||||
fs.unlinkSync(req.file.path);
|
||||
} catch (e) {}
|
||||
return res.status(400).json({
|
||||
code: mediaCheck.code || 87014,
|
||||
message: mediaCheck.message
|
||||
});
|
||||
}
|
||||
|
||||
const publicUrl = `/uploads/${req.file.filename}`;
|
||||
res.json({
|
||||
code: 20000,
|
||||
@@ -263,6 +282,29 @@ const handleFileUpload = (req: Request, res: Response) => {
|
||||
app.post('/api/upload', handleFileUpload);
|
||||
app.post('/api/user/upload', handleFileUpload);
|
||||
|
||||
// 微信官方内容安全文本检测接口 (对接 security.msgSecCheck)
|
||||
app.post('/api/security/msg-sec-check', (req: Request, res: Response) => {
|
||||
const { content, openid } = req.body || {};
|
||||
const checkResult = contentSecurityService.checkText(content, openid);
|
||||
if (!checkResult.pass) {
|
||||
return res.status(400).json({
|
||||
code: checkResult.code,
|
||||
data: {
|
||||
suggest: checkResult.suggest,
|
||||
label: checkResult.label
|
||||
},
|
||||
message: checkResult.message
|
||||
});
|
||||
}
|
||||
res.json({
|
||||
code: 20000,
|
||||
data: {
|
||||
suggest: checkResult.suggest
|
||||
},
|
||||
message: '内容合规通过'
|
||||
});
|
||||
});
|
||||
|
||||
// 1.3 顶部通知中心接口
|
||||
app.all('/api/message/list', (_req: Request, res: Response) => {
|
||||
res.json({
|
||||
@@ -351,6 +393,17 @@ app.get('/api/activities/:id', async (req: Request, res: Response) => {
|
||||
|
||||
app.post('/api/activities', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { title, location } = req.body || {};
|
||||
// 微信内容安全敏感词检测 (msgSecCheck)
|
||||
const checkTitle = contentSecurityService.checkText(title);
|
||||
if (!checkTitle.pass) {
|
||||
return res.status(400).json({ code: checkTitle.code, message: checkTitle.message });
|
||||
}
|
||||
const checkLoc = contentSecurityService.checkText(location);
|
||||
if (!checkLoc.pass) {
|
||||
return res.status(400).json({ code: checkLoc.code, message: checkLoc.message });
|
||||
}
|
||||
|
||||
const act = await repo.createActivity(req.body);
|
||||
res.json({ code: 20000, data: act, message: '活动创建成功并已写入MySQL' });
|
||||
} catch (err: any) {
|
||||
@@ -896,6 +949,13 @@ app.get('/api/posts', async (req: Request, res: Response) => {
|
||||
|
||||
app.post('/api/posts', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { content } = req.body || {};
|
||||
// 微信内容安全检测
|
||||
const secCheck = contentSecurityService.checkText(content);
|
||||
if (!secCheck.pass) {
|
||||
return res.status(400).json({ code: secCheck.code, message: secCheck.message });
|
||||
}
|
||||
|
||||
const post = await repo.createPost(req.body);
|
||||
res.json({
|
||||
code: 20000,
|
||||
@@ -925,6 +985,12 @@ app.post('/api/orders/:id/review', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const orderId = String(req.params.id);
|
||||
const { rating, tags, content, userId, userNickname, userAvatar, expertId } = req.body;
|
||||
// 微信内容安全检测
|
||||
const secCheck = contentSecurityService.checkText(content);
|
||||
if (!secCheck.pass) {
|
||||
return res.status(400).json({ code: secCheck.code, message: secCheck.message });
|
||||
}
|
||||
|
||||
const review = await repo.createOrderReview({
|
||||
orderId,
|
||||
expertId: expertId ? Number(expertId) : undefined,
|
||||
@@ -980,6 +1046,13 @@ app.post('/api/posts/:id/comments', async (req: Request, res: Response) => {
|
||||
if (!content || !content.trim()) {
|
||||
return res.status(400).json({ code: 40000, message: '评论内容不能为空' });
|
||||
}
|
||||
|
||||
// 微信内容安全检测
|
||||
const secCheck = contentSecurityService.checkText(content);
|
||||
if (!secCheck.pass) {
|
||||
return res.status(400).json({ code: secCheck.code, message: secCheck.message });
|
||||
}
|
||||
|
||||
const comment = await repo.createPostComment({
|
||||
postId,
|
||||
content: content.trim(),
|
||||
|
||||
在新工单中引用
屏蔽一个用户