383 lines
14 KiB
TypeScript
383 lines
14 KiB
TypeScript
|
|
import { COUNTER, DEFAULT_LV, ADULT_AGE, GUEST_MAX_TIME, TASK_TYPE } from '@consts';
|
|
import { RoleModel } from '@db/Role';
|
|
import { UserModel, UserType } from '@db/User';
|
|
import { STATUS, GET_SMS_TYPE, ADDICTION_PREVENTION_CODE } from '@consts';
|
|
import { smsModel } from '@db/Sms';
|
|
import { Service } from 'egg';
|
|
import Counter from '@db/Counter';
|
|
import { getExpByLv } from '../pubUtils/data';
|
|
import { isString } from 'underscore';
|
|
import { getAge } from '../pubUtils/timeUtil';
|
|
import { resResult } from '../pubUtils/util';
|
|
import { checkTeeanAgerTime } from '../pubUtils/authenticateUtil';
|
|
import { authenticate } from '../pubUtils/httpUtil';
|
|
import { checkTask, getCreateUserFuncs } from 'app/pubUtils/taskUtil';
|
|
|
|
/**
|
|
* Test Service
|
|
*/
|
|
export default class Auth extends Service {
|
|
|
|
/**
|
|
* 设备免密登录
|
|
* @param telNo - 用户手机号
|
|
*/
|
|
|
|
public async deviceLogin(isGuest: boolean, token: string, deviceId: string, platform: string, pkgName: string, serverType: string, getuiCID: string) {
|
|
const ctx = this.ctx;
|
|
const ip = ctx.request.ip;
|
|
|
|
let user = await UserModel.findUserByToken(token);
|
|
|
|
if (!user) {
|
|
if (isGuest) {
|
|
const tel = ctx.service.utils.genCode(10);
|
|
const token = ctx.service.utils.generateStr(256);
|
|
let lastGuest = await UserModel.getLastDeviceGuest(deviceId, token);
|
|
if (lastGuest) {
|
|
let param = this.getReturnParam(lastGuest);
|
|
return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
|
|
canLogin: true, // 未设置密码等于未创建账号
|
|
...param
|
|
});
|
|
} else {
|
|
|
|
user = await UserModel.createUser(isGuest, tel, token, platform, pkgName, serverType, deviceId, 0, ip);
|
|
if (getuiCID) {//更新个推cid
|
|
await UserModel.updateGetuiCID(tel, getuiCID);
|
|
}
|
|
let param = this.getReturnParam(user);
|
|
|
|
return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
|
|
canLogin: true,
|
|
...param
|
|
});
|
|
}
|
|
|
|
} else {
|
|
|
|
return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
|
|
canLogin: false
|
|
});
|
|
}
|
|
} else {
|
|
const token = ctx.service.utils.generateStr(256);
|
|
user = await UserModel.updateToken(user.tel, token, deviceId, ip);
|
|
if (getuiCID) {//更新个推cid
|
|
await UserModel.updateGetuiCID(user.tel, getuiCID);
|
|
}
|
|
let param = this.getReturnParam(user);
|
|
|
|
let canLogin = true;
|
|
if (!user.isGuest && !user.hasSetPw) canLogin = false;
|
|
return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
|
|
canLogin, // 未设置密码等于未创建账号
|
|
...param
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
private getReturnParam(user: UserType) {
|
|
let age = getAge(user.birthday);
|
|
let isAdult = age >= ADULT_AGE;
|
|
let todayPlayTime = user.todayPlayTime;
|
|
let type = checkTeeanAgerTime(isAdult, todayPlayTime);
|
|
if ((user.isGuest || !user.hasAuthenticated) && user.guestTime > GUEST_MAX_TIME) {
|
|
type = ADDICTION_PREVENTION_CODE.GUEST;
|
|
}
|
|
|
|
return {
|
|
tel: user.tel,
|
|
isGuest: !!user.isGuest,
|
|
guestTime: user.guestTime, // 游客已体验时间
|
|
hasAuthenticated: !!user.hasAuthenticated, // 是否进行过实名认证
|
|
isAdult, // 是否已成年
|
|
todayPlayTime, // 今天已游戏时长
|
|
type, // 防沉迷类型
|
|
hasSetPw: user.hasSetPw, // 是否设置了密码
|
|
token: user.token, // 用户token
|
|
userCode: user.userCode // 用户标识
|
|
}
|
|
}
|
|
|
|
public checkTelNo(telNo) {
|
|
if (!isString(telNo)) {
|
|
return { status: 1, resResult: resResult(STATUS.WRONG_PARMS) };
|
|
}
|
|
if (telNo.length !== 11) {
|
|
return { status: 1, resResult: resResult(STATUS.TEL_LEN_ERR) };
|
|
}
|
|
return { status: 0 };
|
|
}
|
|
|
|
async sendSmsCodeByGuodu(tel, code) {
|
|
const ctx = this.ctx;
|
|
const url = `http://221.179.172.68:8000/QxtSms/QxtFirewall?OperID=bantu3&OperPass=c8XcTffG&DesMobile=${tel}&Content=${encodeURIComponent(`【同人游戏】验证码${code},您正在登录赵云传,若非本人操作,请勿泄露`)}&Content_Code=1`;
|
|
const result = await ctx.curl(url, {
|
|
method: 'GET',
|
|
});
|
|
return result.data;
|
|
}
|
|
|
|
testLimit(sms, interval) {
|
|
if (sms.updateTime.getTime() > Date.now() - interval) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 用户获取手机验证码
|
|
* @param telNo - 用户手机号
|
|
*/
|
|
|
|
public async getSms(type: number, tel: string) {
|
|
const ctx = this.ctx;
|
|
|
|
const telVerify = this.checkTelNo(tel);
|
|
if (telVerify.status !== 0) {
|
|
return telVerify.resResult;
|
|
}
|
|
|
|
if (type == GET_SMS_TYPE.BIND) {
|
|
let telUser = await UserModel.findUserByTel(tel);
|
|
if (telUser && telUser.uid != ctx.uid) {
|
|
return ctx.service.utils.resResult(STATUS.TEL_HAS_USED);
|
|
}
|
|
}
|
|
|
|
const sms = await smsModel.findByTel(tel, false);
|
|
if (sms) {
|
|
if (await sms.timeLimit(10000)) {
|
|
return this.ctx.service.utils.resResult(STATUS.SMS_IN_60S);
|
|
}
|
|
if (await sms.cntLimit(8)) {
|
|
return this.ctx.service.utils.resResult(STATUS.SMS_CNT_LIMIT);
|
|
}
|
|
}
|
|
|
|
let code = '';
|
|
if (sms && (!sms.used || sms.isFixed)) {
|
|
code = sms.code;
|
|
} else {
|
|
code = this.ctx.service.utils.generateNum(6);
|
|
}
|
|
|
|
const smsResult = await this.sendSmsCodeByGuodu(tel, code);
|
|
console.log(smsResult);
|
|
await smsModel.updateByTel(tel, code, false, new Date(), sms?.hasSendToday() ? sms.countToday + 1 : 1);
|
|
|
|
let user = await UserModel.findUserByTel(tel);
|
|
return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
|
|
hasAccount: !!user && !!user.hasSetPw
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 用户获取到手机验证码之后发送验证登录请求
|
|
* @param tel 登录手机号
|
|
* @param code 登录验证码
|
|
* @param platform 平台
|
|
* @param pkgName 包名
|
|
* @param serverType 服务器类型
|
|
*/
|
|
public async smsLogin(tel: string, deviceId: string, code: string, platform: string, pkgName: string, serverType: string, getuiCID: string) {
|
|
const ctx = this.ctx;
|
|
const ip = ctx.request.ip;
|
|
// 参数检查
|
|
const telVerify = this.checkTelNo(tel);
|
|
if (telVerify.status !== 0) {
|
|
return telVerify.resResult;
|
|
}
|
|
|
|
// ! 测试阶段允许客户端不传验证码,此时不做验证码验证,直接注册或登录账号
|
|
// TODO 上线前改掉或仅保留在测试服
|
|
if (code !== '') {
|
|
if (!isString(code) || code.length !== 6) {
|
|
return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
|
|
}
|
|
|
|
// 手机验证码核验
|
|
const smsValid: boolean = await smsModel.validateSms(tel, code);
|
|
if (!smsValid) {
|
|
const sms = await smsModel.findByTel(tel);
|
|
if (sms && sms.isFixed) { // 固定手机号登录
|
|
if (sms.code !== code) {
|
|
return ctx.service.utils.resResult(STATUS.SMS_INVALID);
|
|
}
|
|
} else {
|
|
return ctx.service.utils.resResult(STATUS.SMS_INVALID);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 用户注册登录
|
|
const token = ctx.service.utils.generateStr(256);
|
|
const user = await UserModel.createOrUpdate(false, tel, token, platform, pkgName, serverType, deviceId, ip);
|
|
if (getuiCID) {//更新个推cid
|
|
await UserModel.updateGetuiCID(tel, getuiCID);
|
|
}
|
|
let param = this.getReturnParam(user);
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, param);
|
|
}
|
|
|
|
|
|
/**
|
|
* 给策划用于直接获得手机号验证码
|
|
* @param tel 登录手机号
|
|
*/
|
|
public async getSmsCode(tel: string) {
|
|
const ctx = this.ctx;
|
|
|
|
const sms = await smsModel.findByTel(tel);
|
|
if (sms) {
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, { code: sms?.code });
|
|
} else {
|
|
return ctx.service.utils.resResult(STATUS.SMS_INVALID);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置密码
|
|
* @param password 密码
|
|
*/
|
|
public async setPassword(password: string) {
|
|
const { ctx } = this;
|
|
const { uid } = ctx;
|
|
if (!password) return ctx.service.utils.resResult(STATUS.PASSWORD_ILLEGEL);
|
|
|
|
let user = await UserModel.setPass(uid, password);
|
|
if (user) {
|
|
let param = this.getReturnParam(user);
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, param);
|
|
} else {
|
|
return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 密码登录
|
|
* @param tel 登录手机号
|
|
* @param code 登录验证码
|
|
* @param platform 平台
|
|
* @param pkgName 包名
|
|
* @param serverType 服务器类型
|
|
*/
|
|
public async pwLogin(tel: string, deviceId: string, pw: string, getuiCID: string) {
|
|
const ctx = this.ctx;
|
|
// 参数检查
|
|
const telVerify = this.checkTelNo(tel);
|
|
if (telVerify.status !== 0) {
|
|
return telVerify.resResult;
|
|
}
|
|
|
|
|
|
// 用户注册登录
|
|
const token = ctx.service.utils.generateStr(256);
|
|
const user = await UserModel.checkPass(tel, pw, token, deviceId);
|
|
if (!user) return ctx.service.utils.resResult(STATUS.PASSWORD_ERR);
|
|
if (getuiCID) {//更新个推cid
|
|
await UserModel.updateGetuiCID(tel, getuiCID);
|
|
}
|
|
let param = this.getReturnParam(user);
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, { ...param });
|
|
}
|
|
|
|
public async checkRole(serverId: number) {
|
|
const ctx = this.ctx;
|
|
const { uid } = ctx;
|
|
const role = await RoleModel.findByUid(uid, serverId);
|
|
if (role) {
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId });
|
|
}
|
|
return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND);
|
|
}
|
|
|
|
public async createRole(serverId: number) {
|
|
console.log('enter Auth createRole');
|
|
const ctx = this.ctx;
|
|
const { uid } = ctx;
|
|
const roleId = ctx.service.utils.genCode(10);
|
|
const code = ctx.service.utils.genCode(6);
|
|
const seqId = await Counter.getNewCounter(COUNTER.ROLE) || -1;
|
|
|
|
const role = await RoleModel.createRole(uid, serverId, { roleId, code, roleName: roleId, seqId, lv: DEFAULT_LV, exp: (getExpByLv(DEFAULT_LV - 1) || { sum: 0 }).sum || 0 });
|
|
if (role) {
|
|
let funcs = await getCreateUserFuncs(role.funcs, role.lv);
|
|
|
|
// 任务
|
|
await checkTask(roleId, TASK_TYPE.ROLE_LV, role.lv, false, {}, funcs);
|
|
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId });
|
|
}
|
|
return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND);
|
|
}
|
|
|
|
/**
|
|
* 绑定账号
|
|
* @param tel 手机号
|
|
* @param code 验证码
|
|
*/
|
|
public async bind(tel: string, code: string) {
|
|
const ctx = this.ctx;
|
|
// 参数检查
|
|
const telVerify = this.checkTelNo(tel);
|
|
if (telVerify.status !== 0) {
|
|
return telVerify.resResult;
|
|
}
|
|
|
|
if (!isString(code) || code.length !== 6) {
|
|
return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
|
|
}
|
|
|
|
// 手机验证码核验
|
|
const smsValid: boolean = await smsModel.validateSms(tel, code);
|
|
if (!smsValid) {
|
|
const sms = await smsModel.findByTel(tel);
|
|
if (sms && sms.isFixed) { // 固定手机号登录
|
|
if (sms.code !== code) {
|
|
return ctx.service.utils.resResult(STATUS.SMS_INVALID);
|
|
}
|
|
} else {
|
|
return ctx.service.utils.resResult(STATUS.SMS_INVALID);
|
|
}
|
|
}
|
|
|
|
let telUser = await UserModel.findUserByTel(tel);
|
|
if (telUser && telUser.uid != ctx.uid) {
|
|
return ctx.service.utils.resResult(STATUS.TEL_HAS_USED);
|
|
}
|
|
|
|
let user = await UserModel.bindTel(ctx.uid, tel);
|
|
if (!user) return ctx.service.utils.resResult(STATUS.ACCOUNT_NOT_GUEST);
|
|
let param = this.getReturnParam(user);
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, param);
|
|
}
|
|
|
|
/**
|
|
* 实名认证
|
|
* @param password 密码
|
|
*/
|
|
public async authentication(name: string, idNum: string) {
|
|
const ctx = this.ctx;
|
|
// TODO 接SDK
|
|
console.log(name, idNum);
|
|
let result = await authenticate(name, idNum, ctx.userCode, ctx.pkgName);
|
|
if (!result) return ctx.service.utils.resResult(STATUS.AUTHEN_FAIL);
|
|
|
|
let birthday = this.getBirthdayByIdCard(idNum);
|
|
let user = await UserModel.authentication(ctx.uid, birthday, '');
|
|
let param = this.getReturnParam(user);
|
|
return ctx.service.utils.resResult(STATUS.SUCCESS, param);
|
|
}
|
|
|
|
private getBirthdayByIdCard(idNum: string) {
|
|
let year = idNum.slice(6, 10);
|
|
let month = idNum.slice(10, 12);
|
|
let date = idNum.slice(12, 14);
|
|
return `${year}-${month}-${date}`;
|
|
}
|
|
}
|