sdk: 登录
This commit is contained in:
@@ -14,8 +14,6 @@ import { pushComposeOrangeHero, pushHeroQualityUpMsg, pushHeroStarMax, pushHeroW
|
||||
import { calculatetopLineup, calEquipSeids } from '../../../pubUtils/playerCe';
|
||||
import { PvpDefenseModel } from '../../../db/PvpDefense';
|
||||
import { checkTaskWithHero, checkTask, checkActivityTask } from '../../../services/taskService';
|
||||
import { addSkin } from '../../../pubUtils/itemUtils';
|
||||
import Skin from '../../../db/Skin';
|
||||
import { EquipModel, EquipType } from '../../../db/Equip';
|
||||
import { checkEquipCanPut } from '../../../services/equipService';
|
||||
import { pick } from 'underscore';
|
||||
|
||||
@@ -11,3 +11,16 @@ export enum BANTU_VID_ADDR {
|
||||
REPORT_ONLINE = '/addiction_prevention/report_online'
|
||||
}
|
||||
export const BANTU_VID_APP_KEY = '05c1c495369769e3c5d98426e9c8c2c0';
|
||||
|
||||
export enum SDK_37_ADDR {
|
||||
LOGIN = 'https://apimyh5.37.com/index.php?c=sdk-unified&a=validate'
|
||||
}
|
||||
export enum SDK_37_CONST {
|
||||
GAME_ID = 165, // 研发使用的GAME_ID
|
||||
PID = '37h5', // 37渠道标识
|
||||
FX_C_GAME_ID = 21228, // 子游戏id
|
||||
GAME_KEY = 'sgzzyz',
|
||||
LOGIN_KEY = '3PerD)H!JdTC_pEUnZl8vXKgasj5;7Q~', // 登录KEY
|
||||
PAY_KEY = '0;_Zy.qodXCF8NGQmrOYltk%HgfAz*39', // 重置KEY
|
||||
CHAT_KEY = '3PerD)H!JdTC_pEUnZl8vXKgasj5;7Q~', // 聊天KEY
|
||||
}
|
||||
@@ -30,6 +30,8 @@ export const STATUS = {
|
||||
NAME_HAS_USED: { code: 10015, simStr: '该名字已使用' },
|
||||
ROLE_HAS_INIT: { code: 10016, simStr: '该角色已初始过' },
|
||||
ROLE_EXIST: { code: 10017, simStr: '账号已存在' },
|
||||
CHANNEL_ERR: { code: 10018, simStr: '无此渠道' },
|
||||
VALIDATE_ERR: { code: 10019, simStr: '渠道校验错误' },
|
||||
// 战斗相关状态 20000 - 29999
|
||||
// 战斗通用 20000 - 20099
|
||||
BATTLE_MISS_INFO: { code: 20001, simStr: '缺少关卡信息' },
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CounterModel } from './Counter';
|
||||
import BaseModel from './BaseModel';
|
||||
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
|
||||
import { genCode, aesEncryptcfb, aesDecryptcfb } from '../pubUtils/util';
|
||||
import { LoginValidateData37, ChannelInfo } from '../domain/sdk';
|
||||
const bcrypt = require('bcrypt');
|
||||
const SALT_WORK_FACTOR = 5
|
||||
|
||||
@@ -18,6 +19,7 @@ class PlatForm {
|
||||
*/
|
||||
@index({ tel: 1 })
|
||||
@index({ uid: 1 })
|
||||
@index({ channelId: 1 })
|
||||
export default class User extends BaseModel {
|
||||
|
||||
@prop({ required: true })
|
||||
@@ -32,6 +34,15 @@ export default class User extends BaseModel {
|
||||
@prop({ required: true })
|
||||
token: string;
|
||||
|
||||
@prop({ required: true })
|
||||
channelType: string; // 渠道类型
|
||||
|
||||
@prop({ required: true })
|
||||
channelId: string; // 渠道类型
|
||||
|
||||
@prop({ required: true, _id: false })
|
||||
channelInfo: LoginValidateData37|{}; // 渠道数据
|
||||
|
||||
@prop({ required: true, set: (val: string) => aesEncryptcfb(val, ENCRYPT_KEY, ENCRYPT_IV), get: (val: string) => aesDecryptcfb(val, ENCRYPT_KEY, ENCRYPT_IV) })
|
||||
tel: string; // 账号
|
||||
|
||||
@@ -44,9 +55,6 @@ export default class User extends BaseModel {
|
||||
@prop({ required: true })
|
||||
salt: string;
|
||||
|
||||
@prop({ required: true, default: '' })
|
||||
channelId: string;
|
||||
|
||||
// 游客相关
|
||||
@prop({ required: false, default: false })
|
||||
isGuest: boolean; // 是否是游客
|
||||
@@ -123,6 +131,20 @@ export default class User extends BaseModel {
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async createUserWithChannel(channelId: string, channelType: string, channelInfO: ChannelInfo, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, ip: string = '') {
|
||||
const curTime: Date = new Date();
|
||||
|
||||
const uid = await CounterModel.getNewCounter(COUNTER.UID);
|
||||
const userCode = genCode(8);
|
||||
const doc = new UserModel();
|
||||
let update = {};
|
||||
update = Object.assign(update, doc.toJSON(), { platform, pkgName, serverType, createTime: curTime, uid, userCode, username: `用户${uid}`, token, lastLoginTime: curTime, ip, channelInfO, channelType });
|
||||
delete update["device"];
|
||||
|
||||
const user: UserType = await UserModel.findOneAndUpdate({ channelId }, { $set: update, $addToSet: { device: deviceId } }, { upsert: true, new: true }).lean({ getters: true });
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async getLastDeviceGuest(deviceId: string, token: string) {
|
||||
const user: UserType = await UserModel.findOneAndUpdate({ device: { $elemMatch: { $eq: deviceId } }, isGuest: true }, { token }, { new: true }).sort({ createTime: -1 }).lean({ getters: true });
|
||||
return user;
|
||||
@@ -136,11 +158,23 @@ export default class User extends BaseModel {
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async updateTokenByChannel(channelId: string, token: string, deviceId: string, ip: string, channelInfo: ChannelInfo) {
|
||||
|
||||
const curTime: Date = new Date();
|
||||
|
||||
let user = await UserModel.findOneAndUpdate({ channelId }, { $set: { token, lastLoginTime: curTime, ip, channelInfo }, $addToSet: { device: deviceId } }, { new: true }).lean({ getters: true });
|
||||
return user;
|
||||
}
|
||||
public static async updateGetuiCID(tel: string, cid: string) {
|
||||
let user = await UserModel.findOneAndUpdate({ tel }, { $set: { getuiCID: cid } }, { new: true }).lean({ getters: true });
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async updateGetuiCIDByChannel(channel: string, cid: string) {
|
||||
let user = await UserModel.findOneAndUpdate({ channel }, { $set: { getuiCID: cid } }, { new: true }).lean({ getters: true });
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async createOrUpdate(isGuest: boolean, tel: string, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, ip: string) {
|
||||
// console.log(tel);
|
||||
|
||||
@@ -153,6 +187,18 @@ export default class User extends BaseModel {
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async createOrUpdateChannelUser(channelId: string, channelType: string, channelInfo: ChannelInfo, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, ip: string) {
|
||||
// console.log(tel);
|
||||
|
||||
let user: UserType = await UserModel.findUserByChannel(channelId);
|
||||
if (!user) {
|
||||
user = await UserModel.createUserWithChannel(channelId, channelType, channelInfo, token, platform, pkgName, serverType, deviceId, ip);
|
||||
} else {
|
||||
user = await UserModel.updateTokenByChannel(channelId, token, deviceId, ip, channelInfo);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private static async encryptPass(password: string, salt?: string) {
|
||||
if (!salt) {
|
||||
salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
|
||||
@@ -191,6 +237,11 @@ export default class User extends BaseModel {
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async findUserByChannel(channelId: string) {
|
||||
const user: UserType = await UserModel.findOne({ channelId }).select('uid token serverType auth tel userCode pkgName ip').lean({ getters: true });
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async findTokenByTel(tel: string) {
|
||||
const user: UserType = await UserModel.findOne({ tel }).lean();
|
||||
return user ? user.token : null;
|
||||
|
||||
42
shared/domain/sdk.ts
Normal file
42
shared/domain/sdk.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { prop } from "@typegoose/typegoose";
|
||||
|
||||
// 37的登录验证返回参数
|
||||
export class LoginValidateData37 {
|
||||
@prop({ required: true })
|
||||
uid: number; // 用户uid
|
||||
|
||||
@prop({ required: true })
|
||||
is_phone_bind: number; // 是否绑定手机
|
||||
|
||||
@prop({ required: true })
|
||||
is_idcard_bind: number; // 是否绑定身份证
|
||||
|
||||
@prop({ required: true })
|
||||
is_adult: number; // 是否成年
|
||||
|
||||
@prop({ required: true })
|
||||
vip_level: number; // vip等级
|
||||
|
||||
@prop({ required: true })
|
||||
is_youke: number; // 是否为第三方来源
|
||||
|
||||
@prop({ required: true })
|
||||
is_bind_alias: number; // 是否绑定平台个性账号
|
||||
|
||||
@prop({ required: true })
|
||||
birth: number; // 用户生日
|
||||
|
||||
@prop({ required: true })
|
||||
age: number; // 用户年龄
|
||||
|
||||
@prop({ required: true })
|
||||
unique_realname_id: string; // 用户身份证唯一标识
|
||||
}
|
||||
|
||||
export interface LoginValidataReturn37 {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: LoginValidateData37;
|
||||
}
|
||||
|
||||
export type ChannelInfo = LoginValidataReturn37|{};
|
||||
@@ -1,9 +1,65 @@
|
||||
import * as request from "request-promise";
|
||||
import * as crypto from 'crypto'
|
||||
import { BANTU_VID_ADDR, BANTU_VID_APP_KEY } from '../consts';
|
||||
import { BANTU_VID_ADDR, BANTU_VID_APP_KEY, HTTP_METHOD } from '../consts';
|
||||
|
||||
// 通用,请求http
|
||||
export async function httpRequest(url: string, method: string, headers: any, body: any) {
|
||||
console.log(`httpRequest*********: ${url}, ${method}, ${JSON.stringify(headers)}, ${JSON.stringify(body)}`)
|
||||
|
||||
let options = {
|
||||
url,
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
json: true
|
||||
}
|
||||
|
||||
try {
|
||||
let res = await request(options);
|
||||
console.log('*****request result*****');
|
||||
console.log(JSON.stringify(res));
|
||||
return res;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function md5(str: string, treatStr?: (str: string) => string) {
|
||||
if(treatStr) str = treatStr(str);
|
||||
console.log('*****str', str)
|
||||
return crypto.createHash('md5').update(str, 'utf8').digest("hex");
|
||||
};
|
||||
|
||||
export function getMd5ObjSign(obj: any, joinMark: string, treatStr?: (str: string) => string) {
|
||||
const str = [];
|
||||
Object.keys(obj).sort().forEach((key) => {
|
||||
if (key == 'sign') {
|
||||
|
||||
} else {
|
||||
str.push(key + '=' + obj[key]);
|
||||
}
|
||||
});
|
||||
if (str.length == 0) {
|
||||
console.error('check obj', obj);
|
||||
}
|
||||
var strs = str.join(joinMark);
|
||||
return md5(strs, treatStr);
|
||||
}
|
||||
|
||||
export async function checkMd5Sign(obj: any, treatStr?: (str: string) => string) {
|
||||
if (getMd5ObjSign(obj, '', treatStr) === obj.sign) {
|
||||
return true;
|
||||
}
|
||||
console.warn('correct sign:', getMd5ObjSign(obj, '', treatStr), obj.sign);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/************** 厚土防沉迷接口 **************/
|
||||
/**
|
||||
* 在线报告
|
||||
* 在线报告 暂时不使用
|
||||
* @param userCode 账号
|
||||
* @param packageName 包名
|
||||
*/
|
||||
@@ -24,7 +80,7 @@ export async function reportOnline(userCode: string, packageName: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 实名认证
|
||||
* 实名认证 暂时不使用
|
||||
* @param name 真实姓名
|
||||
* @param idNum 身份证号
|
||||
* @param userCode 账号
|
||||
@@ -50,7 +106,7 @@ export async function authenticate(name: string, idNum: string, userCode: string
|
||||
}
|
||||
|
||||
export async function vidHttpRequest(addr: string, body: any) {
|
||||
body['sign'] = getObjSign(body);
|
||||
body['sign'] = getVidObjSign(body);
|
||||
console.log('body: ', JSON.stringify(body))
|
||||
|
||||
let options = {
|
||||
@@ -62,7 +118,7 @@ export async function vidHttpRequest(addr: string, body: any) {
|
||||
|
||||
try {
|
||||
let res = await request(options);
|
||||
let check = checkSign(res);
|
||||
let check = checkVidObjSign(res);
|
||||
if (!check) return false;
|
||||
// console.log('*****request result*****');
|
||||
// console.log(JSON.stringify(res));
|
||||
@@ -73,54 +129,38 @@ export async function vidHttpRequest(addr: string, body: any) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function httpRequest(url: string, method: string, headers: any, body: any) {
|
||||
console.log(`httpRequest*********: ${url}, ${method}, ${JSON.stringify(headers)}, ${JSON.stringify(body)}`)
|
||||
|
||||
let options = {
|
||||
url,
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
json: true
|
||||
}
|
||||
|
||||
try {
|
||||
let res = await request(options);
|
||||
console.log('*****request result*****');
|
||||
console.log(JSON.stringify(res));
|
||||
return res;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false
|
||||
}
|
||||
function getVidObjSign(body: any) {
|
||||
return getMd5ObjSign(body, '', treatVid);
|
||||
}
|
||||
|
||||
export function md5Vid(str: string) {
|
||||
str = 'vId' + str;
|
||||
return crypto.createHash('md5').update(str, 'utf8').digest("hex");
|
||||
};
|
||||
|
||||
export function getObjSign(obj: any) {
|
||||
const str = [];
|
||||
Object.keys(obj).sort().forEach((key) => {
|
||||
if (key == 'sign') {
|
||||
|
||||
} else {
|
||||
str.push(key + '=' + obj[key]);
|
||||
}
|
||||
});
|
||||
if (str.length == 0) {
|
||||
console.error('check obj', obj);
|
||||
}
|
||||
var strs = str.join('');
|
||||
return md5Vid(strs);
|
||||
function checkVidObjSign(obj: any) {
|
||||
return checkMd5Sign(obj, treatVid);
|
||||
}
|
||||
|
||||
export async function checkSign(obj: any) {
|
||||
if (getObjSign(obj) === obj.sign) {
|
||||
return true;
|
||||
}
|
||||
console.warn('correct sign:', getObjSign(obj), obj.sign);
|
||||
return false;
|
||||
function treatVid(str) {
|
||||
return 'vId' + str;
|
||||
}
|
||||
|
||||
// 37sdk请求
|
||||
|
||||
function get37ObjSign(body: any, key: string) {
|
||||
return getMd5ObjSign(body, '&', (str) => `${str}&${key}`);
|
||||
}
|
||||
|
||||
export async function request37(url: string, body: any, key: string) {
|
||||
// body = {
|
||||
// clientid: 'abscddsssssss',
|
||||
// pid: '37h5',
|
||||
// game_id: 30,
|
||||
// pst: 'MWNmY2pweWZ6dFRhZmdnZ1k4aHhINVUyZnFra1',
|
||||
// time: 1583821808,
|
||||
// c_game_id: 'com.a.test'
|
||||
// }
|
||||
|
||||
// key = 'FkM619)t,P7E3yK#44q85)!Sm5cv8j'
|
||||
body['sign'] = get37ObjSign(body, key);
|
||||
|
||||
let result = await httpRequest(url, HTTP_METHOD.POST, {}, body);
|
||||
console.log('******result', result)
|
||||
return result;
|
||||
}
|
||||
34
shared/pubUtils/sdkUtil.ts
Normal file
34
shared/pubUtils/sdkUtil.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { SDK_37_ADDR, SDK_37_CONST } from '../consts';
|
||||
import { request37 } from './httpUtil';
|
||||
import { nowSeconds } from './timeUtil';
|
||||
import { LoginValidataReturn37 } from '../domain/sdk';
|
||||
|
||||
/************** 37sdk **************/
|
||||
|
||||
export async function loginValidate37(clientId: string, pst: string) {
|
||||
let result: LoginValidataReturn37 = await request37(SDK_37_ADDR.LOGIN, {
|
||||
clientid: clientId,
|
||||
pid: SDK_37_CONST.PID,
|
||||
game_id: SDK_37_CONST.GAME_ID,
|
||||
pst,
|
||||
time: nowSeconds(),
|
||||
c_game_id: SDK_37_CONST.FX_C_GAME_ID
|
||||
}, SDK_37_CONST.LOGIN_KEY);
|
||||
if (result && result.code !== 1) {
|
||||
console.error(result.msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function loginValidata(channelType: string, clientId: string, pst: string) {
|
||||
if(channelType == '37') {
|
||||
return await loginValidate37(clientId, pst);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getChannelId(channelType: string, uid: number|string) {
|
||||
return `${channelType}: ${uid}`;
|
||||
}
|
||||
@@ -412,7 +412,7 @@ export function readFileAndParseJson(path: string) {
|
||||
let readResult = readFile(path);
|
||||
return JSON.parse(readResult);
|
||||
} catch(e) {
|
||||
throw new Error(`connectors.json 格式错误:${e.message}`);
|
||||
throw new Error(`connectors.json 格式错误:${(<Error>e).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ export function readFileAndParse(fileName: string) {
|
||||
let readResult = readJsonFile(fileName);
|
||||
return JSON.parse(readResult);
|
||||
} catch(e) {
|
||||
throw new Error(`${fileName}格式错误:${e.message}`);
|
||||
throw new Error(`${fileName}格式错误:${(<Error>e).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ export function readWarJsonFileAndParse() {
|
||||
let json = JSON.parse(str);
|
||||
result.push(json);
|
||||
} catch(e) {
|
||||
throw new Error(`${name}格式错误:${e.message}`);
|
||||
throw new Error(`${name}格式错误:${(<Error>e).message}`);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -61,4 +61,10 @@ export default class AccountController extends Controller {
|
||||
const { name, idNum } = ctx.request.body;
|
||||
ctx.body = await ctx.service.auth.authentication(name, idNum);
|
||||
}
|
||||
|
||||
public async channelLogin() {
|
||||
const { ctx } = this;
|
||||
const { channelType, pst, clientId, deviceId, platform, pkgName, serverType, getuiCID } = ctx.request.body;
|
||||
ctx.body = await ctx.service.auth.channelLogin(channelType, clientId, pst, deviceId, platform, pkgName, serverType, getuiCID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export default class GameController extends Controller {
|
||||
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true });
|
||||
return;
|
||||
} catch (e) {
|
||||
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack });
|
||||
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: (<Error>e).stack });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export default (app: Application) => {
|
||||
router.get('/dev', controller.home.dev);
|
||||
router.get('/dev/smscode', controller.account.getSmsCode);
|
||||
router.get('/', controller.home.index);
|
||||
router.post('/user/channellogin', controller.account.channelLogin);
|
||||
router.post('/user/devicelogin', controller.account.deviceLogin);
|
||||
router.post('/user/getsms', controller.account.getSms);
|
||||
router.post('/user/smslogin', controller.account.smsLogin);
|
||||
|
||||
@@ -13,6 +13,8 @@ import { resResult } from '../pubUtils/util';
|
||||
import { checkTeeanAgerTime } from '../pubUtils/authenticateUtil';
|
||||
import { authenticate } from '../pubUtils/httpUtil';
|
||||
import { checkTask } from 'app/pubUtils/taskUtil';
|
||||
import { getChannelId, loginValidata } from '../pubUtils/sdkUtil';
|
||||
import { LoginValidateData37 } from 'app/domain/sdk';
|
||||
|
||||
/**
|
||||
* Test Service
|
||||
@@ -381,4 +383,46 @@ export default class Auth extends Service {
|
||||
let date = idNum.slice(12, 14);
|
||||
return `${year}-${month}-${date}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 渠道服登录
|
||||
* @param channelType 渠道类型 37: '37'
|
||||
* @param clientId
|
||||
* @param pst
|
||||
* @param deviceId
|
||||
* @param platform
|
||||
* @param pkgName
|
||||
* @param serverType
|
||||
* @param getuiCID
|
||||
* @returns
|
||||
*/
|
||||
public async channelLogin(channelType: string, clientId: string, pst: string, deviceId: string, platform: string, pkgName: string, serverType: string, getuiCID: string) {
|
||||
const ctx = this.ctx;
|
||||
const ip = ctx.request.ip;
|
||||
|
||||
let requestResult = await loginValidata(channelType, clientId, pst)
|
||||
if(!requestResult) return this.ctx.service.utils.resResult(STATUS.CHANNEL_ERR);
|
||||
if(requestResult.code != 1) {
|
||||
return this.ctx.service.utils.resResult(STATUS.VALIDATE_ERR, requestResult);
|
||||
}
|
||||
|
||||
let channelId = getChannelId(channelType, requestResult.data.uid);
|
||||
const token = ctx.service.utils.generateStr(256);
|
||||
let user = await UserModel.createOrUpdateChannelUser(channelId, channelType, requestResult.data, token, platform, pkgName, serverType, deviceId, ip);
|
||||
if (getuiCID) {//更新个推cid
|
||||
await UserModel.updateGetuiCIDByChannel(channelId, getuiCID);
|
||||
}
|
||||
let channelInfo: any = {};
|
||||
if(channelType == '37') {
|
||||
channelInfo.uid = (<LoginValidateData37>user.channelInfo).uid;
|
||||
}
|
||||
return ctx.service.utils.resResult(STATUS.SUCCESS, {
|
||||
canLogin: true,
|
||||
channelId,
|
||||
token: user.token,
|
||||
userCode: user.userCode,
|
||||
channelInfo
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user