|
|
@@ -36,6 +36,10 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
...baseConfig.paymentConfig,
|
|
|
signKey: DOUYIN_MINI_APP_PRIVATE_KEY,
|
|
|
gameId: DOUYIN_MINI_APP_GAME_ID,
|
|
|
+ },
|
|
|
+ loginConfig: {
|
|
|
+ ...baseConfig.loginConfig,
|
|
|
+ apiKey: DOUYIN_MINI_APP_PRIVATE_KEY, // 抖音使用privateKey作为apiKey
|
|
|
}
|
|
|
};
|
|
|
} else {
|
|
|
@@ -517,12 +521,12 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 执行内容安全审核(内部通用方法)
|
|
|
+ * 执行小程序内容安全审核
|
|
|
* @param params 审核参数
|
|
|
* @param config 渠道配置
|
|
|
* @returns 审核结果
|
|
|
*/
|
|
|
- private async performContentSecurityCheck(params: {
|
|
|
+ private async performMiniappContentSecurityCheck(params: {
|
|
|
uid: string;
|
|
|
content: string;
|
|
|
scene?: string;
|
|
|
@@ -541,8 +545,14 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
|
const nonce = Math.floor(Math.random() * 1000000);
|
|
|
|
|
|
+ // 使用小程序配置
|
|
|
+ let actualConfig = config;
|
|
|
+ if (config.channelId === 11) {
|
|
|
+ actualConfig = this.getChannel11Config('miniapp');
|
|
|
+ }
|
|
|
+
|
|
|
// 生成签名
|
|
|
- const signature = this.generateContentSecuritySignature({ timestamp, nonce }, config);
|
|
|
+ const signature = this.generateContentSecuritySignature({ timestamp, nonce }, actualConfig);
|
|
|
if (!signature) {
|
|
|
return {
|
|
|
success: false,
|
|
|
@@ -554,7 +564,7 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
// 构建请求参数
|
|
|
const requestData = {
|
|
|
uid: params.uid,
|
|
|
- gameid: config.paymentConfig.gameId,
|
|
|
+ gameid: actualConfig.paymentConfig.gameId,
|
|
|
signature: signature,
|
|
|
timestamp: timestamp,
|
|
|
nonce: nonce,
|
|
|
@@ -565,16 +575,19 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
usersign: params.usersign || ''
|
|
|
};
|
|
|
|
|
|
- // 调用内容安全API
|
|
|
- const apiUrl = `https://api.${config.paymentConfig.apiUrl}/mpcommon/?cmd=wxaMsgSecCheck`;
|
|
|
- logger.info("调用内容安全API:", { url: apiUrl, content: params.content.substring(0, 50) + '...' });
|
|
|
+ // 调用小程序内容安全API
|
|
|
+ const apiUrl = `https://api.${actualConfig.paymentConfig.apiUrl}/mpcommon/?cmd=wxaMsgSecCheck`;
|
|
|
+ logger.info("调用小程序内容安全API:", {
|
|
|
+ url: apiUrl,
|
|
|
+ content: params.content.substring(0, 50) + '...'
|
|
|
+ });
|
|
|
|
|
|
const response = await axios.post(apiUrl, requestData, {
|
|
|
httpsAgent: this.getHttpsAgent(),
|
|
|
headers: this.getCommonHeaders()
|
|
|
});
|
|
|
|
|
|
- logger.info("内容安全API响应:", response.data);
|
|
|
+ logger.info("小程序内容安全API响应:", response.data);
|
|
|
|
|
|
// 处理响应结果
|
|
|
if (response.data && response.data.error === 0) {
|
|
|
@@ -593,7 +606,102 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
};
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- logger.error("内容安全审核出错:", error);
|
|
|
+ logger.error("小程序内容安全审核出错:", error);
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ error: -1,
|
|
|
+ errmsg: "内容安全审核失败"
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行抖音内容安全审核
|
|
|
+ * @param params 审核参数
|
|
|
+ * @param config 渠道配置
|
|
|
+ * @returns 审核结果
|
|
|
+ */
|
|
|
+ private async performByteDanceContentSecurityCheck(params: {
|
|
|
+ uid: string;
|
|
|
+ content: string;
|
|
|
+ scene?: string;
|
|
|
+ nickname?: string;
|
|
|
+ title?: string;
|
|
|
+ usersign?: string;
|
|
|
+ }, config: ChannelConfig): Promise<{
|
|
|
+ success: boolean;
|
|
|
+ error?: number;
|
|
|
+ errmsg?: string;
|
|
|
+ result?: any;
|
|
|
+ trace_id?: string;
|
|
|
+ detail?: any;
|
|
|
+ }> {
|
|
|
+ try {
|
|
|
+ const timestamp = Math.floor(Date.now() / 1000);
|
|
|
+ const nonce = Math.floor(Math.random() * 1000000);
|
|
|
+
|
|
|
+ // 使用抖音小程序配置
|
|
|
+ let actualConfig = config;
|
|
|
+ if (config.channelId === 11) {
|
|
|
+ actualConfig = this.getChannel11Config('ttminiapp');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成签名
|
|
|
+ const signature = this.generateContentSecuritySignature({ timestamp, nonce }, actualConfig);
|
|
|
+ if (!signature) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ error: -1,
|
|
|
+ errmsg: "签名生成失败"
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建请求参数
|
|
|
+ const requestData = {
|
|
|
+ uid: params.uid,
|
|
|
+ gameid: actualConfig.paymentConfig.gameId,
|
|
|
+ signature: signature,
|
|
|
+ timestamp: timestamp,
|
|
|
+ nonce: nonce,
|
|
|
+ scene: params.scene || '1',
|
|
|
+ content: params.content,
|
|
|
+ nickname: params.nickname || '',
|
|
|
+ title: params.title || '',
|
|
|
+ usersign: params.usersign || ''
|
|
|
+ };
|
|
|
+
|
|
|
+ // 调用抖音内容安全API
|
|
|
+ const apiUrl = `https://api.${actualConfig.paymentConfig.apiUrl}/mpcommon/?cmd=byteDanceMsgSecCheck`;
|
|
|
+ logger.info("调用抖音内容安全API:", {
|
|
|
+ url: apiUrl,
|
|
|
+ content: params.content.substring(0, 50) + '...'
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await axios.post(apiUrl, requestData, {
|
|
|
+ httpsAgent: this.getHttpsAgent(),
|
|
|
+ headers: this.getCommonHeaders()
|
|
|
+ });
|
|
|
+
|
|
|
+ logger.info("抖音内容安全API响应:", response.data);
|
|
|
+
|
|
|
+ // 处理响应结果
|
|
|
+ if (response.data && response.data.error === 0) {
|
|
|
+ return {
|
|
|
+ success: true,
|
|
|
+ error: 0,
|
|
|
+ result: response.data.result,
|
|
|
+ trace_id: response.data.trace_id,
|
|
|
+ detail: response.data.detail
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ error: response.data?.error || -1,
|
|
|
+ errmsg: response.data?.errmsg || "内容安全检测失败"
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ logger.error("抖音内容安全审核出错:", error);
|
|
|
return {
|
|
|
success: false,
|
|
|
error: -1,
|
|
|
@@ -610,7 +718,9 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
async contentSecurityCheck(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
|
|
|
try {
|
|
|
const data = ctx.request.body as any;
|
|
|
- logger.info("内容安全审核请求参数:", data);
|
|
|
+ // 支持从GET query参数或POST body中获取platform参数
|
|
|
+ const platform = ctx.request.query.platform || data.platform || 'miniapp';
|
|
|
+ logger.info("内容安全审核请求参数:", { ...data, platform });
|
|
|
|
|
|
// 验证必要参数
|
|
|
const requiredParams = ['uid', 'scene', 'content'];
|
|
|
@@ -625,15 +735,24 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 调用通用内容安全审核方法
|
|
|
- const checkResult = await this.performContentSecurityCheck({
|
|
|
- uid: data.uid,
|
|
|
- content: data.content,
|
|
|
- scene: data.scene,
|
|
|
- nickname: data.nickname,
|
|
|
- title: data.title,
|
|
|
- usersign: data.usersign
|
|
|
- }, config);
|
|
|
+ // 根据platform调用对应的内容安全审核方法
|
|
|
+ const checkResult = platform === 'ttminiapp'
|
|
|
+ ? await this.performByteDanceContentSecurityCheck({
|
|
|
+ uid: data.uid,
|
|
|
+ content: data.content,
|
|
|
+ scene: data.scene,
|
|
|
+ nickname: data.nickname,
|
|
|
+ title: data.title,
|
|
|
+ usersign: data.usersign
|
|
|
+ }, config)
|
|
|
+ : await this.performMiniappContentSecurityCheck({
|
|
|
+ uid: data.uid,
|
|
|
+ content: data.content,
|
|
|
+ scene: data.scene,
|
|
|
+ nickname: data.nickname,
|
|
|
+ title: data.title,
|
|
|
+ usersign: data.usersign
|
|
|
+ }, config);
|
|
|
|
|
|
// 处理审核结果
|
|
|
if (checkResult.success && checkResult.result) {
|
|
|
@@ -670,21 +789,30 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
* @param uid 用户ID
|
|
|
* @param config 渠道配置
|
|
|
* @param scene 场景类型,默认为'1'(角色名称)
|
|
|
+ * @param platform 平台类型:miniapp(小程序)或 ttminiapp(抖音小程序),默认为 miniapp
|
|
|
* @returns 检查结果,suggest: pass/review/reject/risky
|
|
|
*/
|
|
|
private async checkContentSecurity(
|
|
|
content: string,
|
|
|
uid: string,
|
|
|
config: ChannelConfig,
|
|
|
- scene: string = '1'
|
|
|
+ scene: string = '1',
|
|
|
+ platform: string = 'miniapp'
|
|
|
): Promise<{ success: boolean; suggest?: string; message: string }> {
|
|
|
- // 调用通用内容安全审核方法
|
|
|
- const checkResult = await this.performContentSecurityCheck({
|
|
|
- uid: uid,
|
|
|
- content: content,
|
|
|
- scene: scene
|
|
|
- }, config);
|
|
|
+ // 根据platform调用对应的内容安全审核方法
|
|
|
+ const checkResult = platform === 'ttminiapp'
|
|
|
+ ? await this.performByteDanceContentSecurityCheck({
|
|
|
+ uid: uid,
|
|
|
+ content: content,
|
|
|
+ scene: scene
|
|
|
+ }, config)
|
|
|
+ : await this.performMiniappContentSecurityCheck({
|
|
|
+ uid: uid,
|
|
|
+ content: content,
|
|
|
+ scene: scene
|
|
|
+ }, config);
|
|
|
|
|
|
+ console.log("checkResult:", checkResult);
|
|
|
// 处理审核结果
|
|
|
if (checkResult.success && checkResult.result) {
|
|
|
const suggest = checkResult.result.suggest; // pass/review/reject/risky
|
|
|
@@ -741,8 +869,9 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
// API错误时,为了不影响用户体验,可以选择允许通过或拒绝
|
|
|
// 这里选择允许通过,但记录错误日志
|
|
|
return {
|
|
|
- success: true,
|
|
|
- message: "内容安全审核失败,已允许通过"
|
|
|
+ success: false,
|
|
|
+ suggest: "reject",
|
|
|
+ message: "内容安全审核失败,已拒绝"
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
@@ -755,7 +884,10 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
async editUserRoleInfo(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
|
|
|
try {
|
|
|
const data = ctx.request.body as any;
|
|
|
- logger.info("角色名称修改上报请求参数:", data);
|
|
|
+ // 支持从GET query参数或POST body中获取platform参数
|
|
|
+ const platform = ctx.request.query.platform || data.platform || 'miniapp';
|
|
|
+ logger.info("角色名称修改上报请求参数:", { ...data, platform });
|
|
|
+
|
|
|
// 验证必要参数
|
|
|
const requiredParams = ['openId', 'serverid', 'playerName'];
|
|
|
for (const param of requiredParams) {
|
|
|
@@ -798,7 +930,7 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
console.log("playerName for signature:", data.playerName);
|
|
|
|
|
|
// 内容安全审核:验证角色名称是否包含敏感内容
|
|
|
- const securityCheck = await this.checkContentSecurity(decodedPlayerName, data.openId, config);
|
|
|
+ const securityCheck = await this.checkContentSecurity(decodedPlayerName, data.openId, config, '1', platform as string);
|
|
|
if (!securityCheck.success) {
|
|
|
logger.warn("角色名称内容安全审核未通过:", {
|
|
|
playerName: decodedPlayerName,
|