加密:接口加密解密
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Application, BackendSession, HandlerService, pinus, } from 'pinus';
|
||||
import { aesEncrypt, aesEncryptcfb, resResult } from '../../../pubUtils/util';
|
||||
import { resResult } from '../../../pubUtils/util';
|
||||
import { ENCRYPT_IV, ENCRYPT_KEY, STATUS, TASK_TYPE } from '../../../consts';
|
||||
import { ActivityGroupModel } from '../../../db/ActivityGroup';
|
||||
import { ServerlistModel } from '../../../db/Serverlist';
|
||||
|
||||
@@ -2,112 +2,204 @@ import {Application, RouteRecord, FrontendOrBackendSession, HandlerCallback, pin
|
||||
// import { checkEvent } from '../../../services/eventSercive';
|
||||
import { refresh } from '../../../services/refreshService';
|
||||
import { checkPrivateChat, checkGuildChat, checkOtherChat, checkRoleName, checkGuildName } from "../../../services/sdkService";
|
||||
import { resResult, checkWhiteList, genCode } from "../../../pubUtils/util";
|
||||
import { resResult, genCode } from "../../../pubUtils/util";
|
||||
import { checkWhiteList, MsgEncrypt } from "../../../pubUtils/sysUtil";
|
||||
import { BLOCK_TYPE, CHANNEL_PREFIX, MSG_TYPE, PUSH_ROUTE, STATUS } from "../../../consts";
|
||||
import { nowSeconds } from "../../../pubUtils/timeUtil";
|
||||
import { getServerMainten } from "../../../services/gmService";
|
||||
import { errlogger } from "../../../util/logger";
|
||||
import { errlogger, infologger } from "../../../util/logger";
|
||||
import { gameData } from "../../../pubUtils/data";
|
||||
import { sendMessageToUser } from "../../../services/pushService";
|
||||
import { isCheckWord } from "../../../pubUtils/sdkUtil";
|
||||
import { isDevelopEnv } from "../../../services/utilService";
|
||||
import { isNumber } from "underscore";
|
||||
import { redisClient } from "../../../services/redisService";
|
||||
export function globalFilter(app: Application) {
|
||||
return new Filter(app);
|
||||
}
|
||||
|
||||
var Filter = function(this: any, app: Application) {
|
||||
this.app = app;
|
||||
this.accessTime = new Map<string, number>();
|
||||
};
|
||||
class Filter {
|
||||
private app: Application;
|
||||
private accessTime = new Map<string, number>();
|
||||
|
||||
Filter.prototype.checkFrequency = function(route: string, msg: any, roleId: string) {
|
||||
let protect = gameData.serverConst.PROTECT_API.find(cur => {
|
||||
if(cur.route == route) {
|
||||
let paramOK = true;
|
||||
for(let key in cur.param) {
|
||||
if(msg[key] != cur.param[key]) {
|
||||
paramOK = false; break;
|
||||
constructor(app: Application) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public async before (routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, next: HandlerCallback) {
|
||||
const serverId: number = session.get('serverId');
|
||||
const sid: string = session.get('sid');
|
||||
const roleId: string = session.get('roleId');
|
||||
const uid: number = session.get('userid');
|
||||
const ip: string = session.get('ip');
|
||||
// console.log('*********** global before ip', ip)
|
||||
let guildCode = session.get('guildCode');
|
||||
let blockType = session.get('blockType');
|
||||
|
||||
if(!this.checkPassEncrypt(routeRecord.route)) {
|
||||
msg = this.decryptMsg(msg, session);
|
||||
if(!msg) return next(new Error('globalFilter'), resResult(STATUS.WRONG_PARMS));
|
||||
|
||||
if(!this.checkTimeStamp(msg)) return next(new Error('globalFilter'), resResult(STATUS.TIMESTAMP_ERR));
|
||||
if(!this.checkDuplicateAccess(msg)) return next(new Error('globalFilter'), resResult(STATUS.DUPLICATE_ACCESS))
|
||||
}
|
||||
|
||||
// 访问频率控制
|
||||
if(!this.checkFrequency(routeRecord.route, msg, roleId)) {
|
||||
return next(new Error('globalFilter'), resResult(STATUS.ACCESS_BUSY));
|
||||
}
|
||||
if(!this.checkFunction(routeRecord.route)) {
|
||||
return next(new Error('globalFilter'), resResult(STATUS.FUNCTION_CLOSE));
|
||||
}
|
||||
|
||||
// 玩家屏蔽
|
||||
if(blockType == BLOCK_TYPE.BLOCK) return next(new Error('globalFilter'), resResult(STATUS.BLOCKED));
|
||||
if(blockType == BLOCK_TYPE.BAN && this.checkBanRoute(routeRecord.route)) {
|
||||
return next(new Error('globalFilter'), resResult(STATUS.BANNED));
|
||||
}
|
||||
|
||||
session.push('teamCode', () => {});
|
||||
|
||||
|
||||
let hasNoBlockWords = isCheckWord(isDevelopEnv()) && this.checkHasBlockWord(routeRecord.route, msg, roleId, serverId, guildCode);
|
||||
if(!hasNoBlockWords) return next(new Error('globalFilter'), resResult(STATUS.BLOCK_WORDS));
|
||||
|
||||
if(routeRecord.route == 'guild.guildHandler.createGuild') {
|
||||
let guildCode = genCode(6);
|
||||
msg.guildCode = guildCode;
|
||||
}
|
||||
|
||||
if(await this.checkMainten(serverId, sid, ip, uid)) {
|
||||
sendMessageToUser(roleId, PUSH_ROUTE.SERVER_MAINTENANCE, resResult(STATUS.SERVER_MAINTENANCE), sid);
|
||||
return next(new Error('globalFilter'), resResult(STATUS.SERVER_MAINTENANCE));
|
||||
}
|
||||
|
||||
next(null);
|
||||
};
|
||||
|
||||
public async after (err: Error, routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, resp: any, next: HandlerCallback) {
|
||||
//刷新
|
||||
await refresh(session);
|
||||
|
||||
infologger.debug('global after ', routeRecord.route, msg && JSON.stringify(msg), resp && JSON.stringify(resp), session && session.get('roleId'));
|
||||
if(!this.checkPassEncrypt(routeRecord.route)) {
|
||||
let data = this.encryptMsg(resp, session);
|
||||
if(!data) return next(new Error('response data err'));
|
||||
resp = this.setResp(resp, data);
|
||||
}
|
||||
|
||||
next(null);
|
||||
};
|
||||
|
||||
// 检查调用频率
|
||||
private checkFrequency (route: string, msg: any, roleId: string) {
|
||||
let protect = gameData.serverConst.PROTECT_API.find(cur => {
|
||||
if(cur.route == route) {
|
||||
let paramOK = true;
|
||||
for(let key in cur.param) {
|
||||
if(msg[key] != cur.param[key]) {
|
||||
paramOK = false; break;
|
||||
}
|
||||
}
|
||||
if(paramOK) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if(!protect) {
|
||||
return true;
|
||||
}
|
||||
let keyOfRouteWithUser = `${protect.id}_${roleId}`;
|
||||
if(this.accessTime && this.accessTime.has(keyOfRouteWithUser)) {
|
||||
console.log(this.accessTime.get(keyOfRouteWithUser) - Date.now());
|
||||
if(Date.now() - this.accessTime.get(keyOfRouteWithUser) < protect.interval) {
|
||||
errlogger.info(`${keyOfRouteWithUser} 间隔时间小于${protect.interval}ms,为 ${Date.now() - this.accessTime.get(keyOfRouteWithUser)}`);
|
||||
return false;
|
||||
}
|
||||
if(paramOK) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if(!protect) {
|
||||
}
|
||||
if(!this.accessTime) this.accessTime = new Map<string, number>();
|
||||
this.accessTime.set(keyOfRouteWithUser, Date.now());
|
||||
return true;
|
||||
}
|
||||
let keyOfRouteWithUser = `${protect.id}_${roleId}`;
|
||||
if(this.accessTime && this.accessTime.has(keyOfRouteWithUser)) {
|
||||
console.log(this.accessTime.get(keyOfRouteWithUser) - Date.now());
|
||||
if(Date.now() - this.accessTime.get(keyOfRouteWithUser) < protect.interval) {
|
||||
errlogger.info(`${keyOfRouteWithUser} 间隔时间小于${protect.interval}ms,为 ${Date.now() - this.accessTime.get(keyOfRouteWithUser)}`);
|
||||
return false;
|
||||
|
||||
// 检查该接口是否关闭
|
||||
private checkFunction (route: string) {
|
||||
if(gameData.serverConst.API_IS_CLOSE == 1) {
|
||||
if(gameData.serverConst.CLOSE_APIS.indexOf(route) != -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!this.accessTime) this.accessTime = new Map<string, number>();
|
||||
this.accessTime.set(keyOfRouteWithUser, Date.now());
|
||||
return true;
|
||||
}
|
||||
|
||||
Filter.prototype.checkFunction = function(route: string) {
|
||||
if(gameData.serverConst.API_IS_CLOSE == 1) {
|
||||
if(gameData.serverConst.CLOSE_APIS.indexOf(route) != -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Filter.prototype.before = async function (routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, next: HandlerCallback) {
|
||||
const serverId: number = session.get('serverId');
|
||||
const sid: string = session.get('sid');
|
||||
const roleId: string = session.get('roleId');
|
||||
const uid: number = session.get('userid');
|
||||
const ip: string = session.get('ip');
|
||||
// console.log('*********** global before ip', ip)
|
||||
let guildCode = session.get('guildCode');
|
||||
let blockType = session.get('blockType');
|
||||
// 访问频率控制
|
||||
if(!this.checkFrequency(routeRecord.route, msg, roleId)) {
|
||||
return next(new Error('globalFilter'), resResult(STATUS.ACCESS_BUSY));
|
||||
}
|
||||
if(!this.checkFunction(routeRecord.route)) {
|
||||
return next(new Error('globalFilter'), resResult(STATUS.FUNCTION_CLOSE));
|
||||
return true;
|
||||
}
|
||||
|
||||
// 玩家屏蔽
|
||||
if(blockType == BLOCK_TYPE.BLOCK) return next(new Error('globalFilter'), resResult(STATUS.BLOCKED));
|
||||
if(blockType == BLOCK_TYPE.BAN) {
|
||||
if([
|
||||
// 这个接口是否需要加密解密
|
||||
private checkPassEncrypt (route: string) {
|
||||
return route.startsWith('gm.');
|
||||
}
|
||||
|
||||
// 解密接口
|
||||
private decryptMsg (msg: any, session: FrontendOrBackendSession) {
|
||||
let msgEncrypt = new MsgEncrypt({ encodeK: msg?.k, encodeV: msg?.v });
|
||||
let { aesKey, aesIV } = msgEncrypt.getKv();
|
||||
msg = this.setMsg(msg, msgEncrypt.decryptMsg(msg?.data));
|
||||
if(!msg) return false;
|
||||
|
||||
session.set('k', aesKey);
|
||||
session.set('v', aesIV);
|
||||
session.push('k', () => {});
|
||||
session.push('v', () => {});
|
||||
return msg
|
||||
}
|
||||
|
||||
// 解密接口
|
||||
private encryptMsg (resp: any, session: FrontendOrBackendSession) {
|
||||
let msgEncrypt = new MsgEncrypt({ k: session.get('k'), v: session.get('v')});
|
||||
let data = msgEncrypt.encryptMsg(resp);
|
||||
return data;
|
||||
}
|
||||
|
||||
// 传入的msg的修改
|
||||
private setMsg (msg:any, targetObj: any) {
|
||||
if(!msg || !targetObj || typeof targetObj != 'object') {
|
||||
return msg;
|
||||
}
|
||||
delete msg.k;
|
||||
delete msg.v;
|
||||
delete msg.data;
|
||||
for(let key in targetObj) {
|
||||
if(targetObj.hasOwnProperty(key)) {
|
||||
msg[key] = targetObj[key];
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
// 传出的resp的修改
|
||||
private setResp(resp: any, data: string) {
|
||||
for(let key in resp) {
|
||||
if(resp.hasOwnProperty(key)) {
|
||||
delete resp[key];
|
||||
}
|
||||
}
|
||||
resp.data = data;
|
||||
return resp;
|
||||
}
|
||||
|
||||
// 禁言的接口
|
||||
private checkBanRoute (route: string) {
|
||||
return [
|
||||
'chat.chatHandler.sendPrivateMessage',
|
||||
'chat.chatHandler.sendGroupMessage',
|
||||
'battle.comBattleHandler.sendTeamMsg',
|
||||
'battle.barrageHandler.sendBarrage',
|
||||
'guild.guildHandler.sendMail',
|
||||
'guild.guildHandler.setGuildInfo',
|
||||
].indexOf(routeRecord.route) != -1) {
|
||||
return next(new Error('globalFilter'), resResult(STATUS.BANNED));
|
||||
}
|
||||
].indexOf(route) != -1
|
||||
}
|
||||
|
||||
session.push('teamCode', () => {});
|
||||
|
||||
if(sid) {
|
||||
const mainten = getServerMainten(serverId);
|
||||
if(mainten) { // 该服务器维护
|
||||
if(mainten.startTime > nowSeconds() || mainten.endTime < nowSeconds()) return next(null)
|
||||
|
||||
let isWhiteList = await checkWhiteList(this.app.get('env'), ip, uid, serverId);
|
||||
if(isWhiteList) return next(null);
|
||||
|
||||
sendMessageToUser(roleId, PUSH_ROUTE.SERVER_MAINTENANCE, resResult(STATUS.SERVER_MAINTENANCE), sid);
|
||||
return next(new Error('globalFilter'), resResult(STATUS.SERVER_MAINTENANCE));
|
||||
}
|
||||
}
|
||||
|
||||
let hasBlockWords = false;
|
||||
if(isCheckWord(isDevelopEnv())) {
|
||||
switch(routeRecord.route) {
|
||||
// 检查聊天屏蔽词
|
||||
private async checkHasBlockWord (route: string, msg: any, roleId: string, serverId: number, guildCode: string) {
|
||||
let hasBlockWords = false;
|
||||
switch(route) {
|
||||
case 'chat.chatHandler.sendPrivateMessage':
|
||||
{
|
||||
if(msg.type == MSG_TYPE.IMG) break;
|
||||
@@ -161,26 +253,39 @@ Filter.prototype.before = async function (routeRecord: RouteRecord, msg: any, se
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hasBlockWords;
|
||||
}
|
||||
|
||||
if(routeRecord.route == 'guild.guildHandler.createGuild') {
|
||||
let guildCode = genCode(6);
|
||||
msg.guildCode = guildCode;
|
||||
// 检查是否维护中
|
||||
private async checkMainten(serverId: number, sid: string, ip: string, uid: number) {
|
||||
if(!sid) return false;
|
||||
|
||||
const mainten = getServerMainten(serverId);
|
||||
if(!mainten) return false // 该服务器维护
|
||||
if(mainten.startTime > nowSeconds() || mainten.endTime < nowSeconds()) return false;
|
||||
|
||||
let isWhiteList = await checkWhiteList(this.app.get('env'), ip, uid, serverId);
|
||||
if(isWhiteList) return false;
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if(hasBlockWords) return next(new Error('globalFilter'), resResult(STATUS.BLOCK_WORDS));
|
||||
private checkTimeStamp(msg: { ts: number }) {
|
||||
let ts = msg.ts;
|
||||
delete msg.ts;
|
||||
return isNumber(ts) && Date.now() - ts < gameData.serverConst.TIME_STAMP_OVER && Date.now() > ts;
|
||||
}
|
||||
|
||||
next(null);
|
||||
};
|
||||
private async checkDuplicateAccess(msg: { cs: string }) {
|
||||
let cs = msg.cs;
|
||||
delete msg.cs;
|
||||
let redis = redisClient();
|
||||
if(await redis.existsAsync(`cs: ${cs}`)) {
|
||||
return false
|
||||
}
|
||||
|
||||
Filter.prototype.after = async function (err: Error, routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, resp: any, next: HandlerCallback) {
|
||||
//刷新
|
||||
await refresh(session);
|
||||
// return checkEvent(session).then(()=>{
|
||||
// next(err);
|
||||
// }).catch(e => {
|
||||
// console.error(e);
|
||||
// next(err);
|
||||
// }); // 奇遇本检查
|
||||
next(null);
|
||||
};
|
||||
await redis.setAsync(`cs: ${cs}`, '');
|
||||
await redis.expireAsync(`cs: ${cs}`, gameData.serverConst.ACCESS_CODE_EXPIRE_TIME/1000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import { SurveyRecModel } from "../db/SurveyRec";
|
||||
import { getPopUpShopData } from "./activity/popUpShopService";
|
||||
import { TaskPassData } from "../domain/activityField/taskPassField";
|
||||
import { ActivityGroupModel } from "../db/ActivityGroup";
|
||||
import { ActivityInRemote } from "../domain/activityField/activityField";
|
||||
import { redisClient } from "./redisService";
|
||||
|
||||
// —————————————— 跑马灯 —————————————— //
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Channel, pinus } from "pinus";
|
||||
import { CHANNEL_PREFIX, PUSH_BATCH, PUSH_INTERVAL, PUSH_ROUTE, STATUS } from "../consts";
|
||||
import { resResult } from "../pubUtils/util";
|
||||
import { genCode, resResult } from "../pubUtils/util";
|
||||
import { getCityChannelSid, getGuildChannelSid, getWorldChannelSid, groupRoomId } from "./chatService";
|
||||
import { getAllOnlineRoles, getRoleOnlineInfo } from "./redisService";
|
||||
import { errlogger, infologger } from '../util/logger';
|
||||
import { MsgEncrypt } from "../pubUtils/sysUtil";
|
||||
|
||||
export async function sendMessageToAllWithSuc(route: string, data: any, filterCb?: ({ lv, topLineupCe }) => boolean) {
|
||||
await sendMessageToAll(route, resResult(STATUS.SUCCESS, data), filterCb);
|
||||
@@ -84,14 +85,14 @@ export async function sendMessageToUsersWithSuc(route: string, data: any, uids:
|
||||
// 推送给个人的方法收束于这个函数
|
||||
export async function sendMessageToUsers(route: string, data: any, uids: { uid: string, sid: string }[]) {
|
||||
if(uids.length > 0) {
|
||||
pinus.app.get('channelService').pushMessageByUids(route, data, uids);
|
||||
pinus.app.get('channelService').pushMessageByUids(route, encryptMsg(data), uids);
|
||||
infologger.debug(`pushMessage route: ${route} data: ${JSON.stringify(data)} members: ${uids.map(obj => obj.uid).join()}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendMessageToTeam(teamCode: string, route: string, data: any) {
|
||||
const channel = pinus.app.get('channelService').getChannel(teamCode);
|
||||
sendMessageToChannel(channel, route, resResult(STATUS.SUCCESS, data));
|
||||
sendMessageToChannel(channel, route, resResult(STATUS.SUCCESS, encryptMsg(data)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,4 +154,27 @@ export function removeFromTeamChannel(teamCode: string, roleId: string) {
|
||||
if (users.indexOf(roleId) !== -1) {
|
||||
channel.removeMember(roleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getKvFromMemory() {
|
||||
let k = pinus.app.get('aeaKey');
|
||||
let v = pinus.app.get('aesIV');
|
||||
let kvRefTime = pinus.app.get('kvRefTime');
|
||||
let now = new Date().setMinutes(0, 0, 0);
|
||||
if(!kvRefTime || now - kvRefTime >= 60 * 60 * 1000) {
|
||||
k = genCode(24);
|
||||
v = genCode(16);
|
||||
pinus.app.set('aeaKey', k);
|
||||
pinus.app.set('aesIV', v);
|
||||
pinus.app.set('kvRefTime', now);
|
||||
}
|
||||
return { k, v }
|
||||
}
|
||||
|
||||
function encryptMsg(json: any) {
|
||||
let kv = getKvFromMemory();
|
||||
let msgEncrypt = new MsgEncrypt(kv);
|
||||
let { aesKey, aesIV } = msgEncrypt.getEncodeKv();
|
||||
let data = msgEncrypt.encryptMsg(json);
|
||||
return { data, k: aesKey, v: aesIV }
|
||||
}
|
||||
|
||||
@@ -337,6 +337,7 @@ export async function roleLeave(roleId: string) {
|
||||
await redisClient().hdelAsync(REDIS_KEY.ONLINE_CNT, roleId);
|
||||
await redisClient().hdelAsync(REDIS_KEY.ONLINE_USERS, roleId);
|
||||
await redisClient().hdelAsync(REDIS_KEY.USER_CODE, role.userCode);
|
||||
await redisClient().hdelAsync(REDIS_KEY.ONLINE_CNT, roleId);
|
||||
}
|
||||
return role;
|
||||
}
|
||||
@@ -365,6 +366,7 @@ export async function getRoleOnlineInfo(roleId: string) {
|
||||
try {
|
||||
let result = str.split('|');
|
||||
let [userCode, sid, createTime, serverId, lv, topLineupCe] = result;
|
||||
|
||||
return {
|
||||
isOnline: true, userCode, sid,
|
||||
createtime: parseInt(createTime),
|
||||
|
||||
Reference in New Issue
Block a user