176 lines
5.6 KiB
TypeScript
176 lines
5.6 KiB
TypeScript
import logger from 'logger/logger'
|
|
import { ActivityUser } from 'models/ActivityUser'
|
|
import {
|
|
CodeRecord,
|
|
CodeStatus,
|
|
CodeType,
|
|
DEFAULT_CODE,
|
|
DEFAULT_EXPIRE_TIME,
|
|
isEmail,
|
|
isValiedCode,
|
|
} from 'models/CodeRecord'
|
|
import { DEFAULT_LOGIN_MAIL_HTML, DEFAULT_LOGIN_MAIL_SUBJECT, EmailSvr } from 'services/email.svr'
|
|
import { BaseController, router, ZError } from 'zutils'
|
|
import { sha1 } from 'zutils/utils/security.util'
|
|
import { SyncLocker } from 'common/SyncLocker'
|
|
import { ShareCodeRecord, ShareCodeStatus, ShareCodeType } from 'models/wallet/ShareCodeRecord'
|
|
|
|
export const isValiedShareCode = (code: string) => {
|
|
return /^[23456789abcdefghjkmnpqrstuvwxy]{8}$/.test(code)
|
|
}
|
|
class MailController extends BaseController {
|
|
/**
|
|
* 通过邮件验证码形式的登录
|
|
*/
|
|
// @router('post /api/user/verify_email')
|
|
async loginWithEmail(req, res) {
|
|
await new SyncLocker().checkLock(req)
|
|
logger.db('verify_email', req)
|
|
let user = req.user
|
|
const { email, code } = req.params
|
|
if (!email || !code) {
|
|
throw new ZError(10, 'params mismatch')
|
|
}
|
|
if (!isEmail(email)) {
|
|
throw new ZError(11, 'Invalid email')
|
|
}
|
|
if (!isValiedCode(code)) {
|
|
throw new ZError(11, 'code error')
|
|
}
|
|
if (user.gameAccountBinded()) {
|
|
throw new ZError(12, 'already bind game account')
|
|
}
|
|
let openId = sha1(email)
|
|
let userCheck = await ActivityUser.findOne({ emailId: openId })
|
|
if (userCheck && userCheck.id !== user.id) {
|
|
throw new ZError(13, 'Email already binded to another account')
|
|
}
|
|
let recordCode = await CodeRecord.findByEmail(user.id, email, CodeType.LOGIN)
|
|
if (!recordCode) {
|
|
throw new ZError(14, 'code expired')
|
|
}
|
|
if (recordCode.code !== code) {
|
|
throw new ZError(16, 'code error')
|
|
}
|
|
user.emailId = openId
|
|
user.email = email
|
|
recordCode.status = CodeStatus.SUCCESS
|
|
await recordCode.save()
|
|
await user.save()
|
|
return {}
|
|
}
|
|
|
|
@router('post /api/user/verify_client')
|
|
async loginWithGameClient(req, res) {
|
|
await new SyncLocker().checkLock(req)
|
|
logger.db('verify_client', req)
|
|
let user = req.user
|
|
const { code } = req.params
|
|
if (!code) {
|
|
throw new ZError(10, 'params mismatch')
|
|
}
|
|
if (!isValiedShareCode(code)) {
|
|
throw new ZError(11, 'code error')
|
|
}
|
|
if (user.gameAccountBinded()) {
|
|
throw new ZError(12, 'already bind game account')
|
|
}
|
|
|
|
let recordCode = await ShareCodeRecord.findByCode(code, ShareCodeType.BIND_UAW)
|
|
if (!recordCode) {
|
|
throw new ZError(14, 'code expired')
|
|
}
|
|
const openId = recordCode.openId
|
|
let userCheck = await ActivityUser.findOne({ clientId: openId, clientPlat: recordCode.plat })
|
|
let userCheck2 = await ActivityUser.findOne({ googleId: openId })
|
|
let userCheck3 = await ActivityUser.findOne({ emailId: openId })
|
|
if (
|
|
(userCheck && userCheck.id !== user.id) ||
|
|
(userCheck2 && userCheck2.id !== user.id) ||
|
|
(userCheck3 && userCheck3.id !== user.id)
|
|
) {
|
|
throw new ZError(13, 'Email already binded to another account')
|
|
}
|
|
user.clientId = openId
|
|
user.clientMail = recordCode.email
|
|
user.clientPlat = recordCode.plat
|
|
recordCode.status = ShareCodeStatus.SUCCESS
|
|
await ShareCodeRecord.updateOne(
|
|
{ code, type: ShareCodeType.BIND_UAW, status: ShareCodeStatus.PENDING },
|
|
{ status: ShareCodeStatus.SUCCESS },
|
|
)
|
|
await user.save()
|
|
return {}
|
|
}
|
|
|
|
/**
|
|
* 发送验证码
|
|
*/
|
|
// @router('post /api/email/send_code')
|
|
async sendVerifyCode(req, res) {
|
|
await new SyncLocker().checkLock(req)
|
|
logger.db('send_mail_code', req)
|
|
let user = req.user
|
|
let { email, type } = req.params
|
|
type = type || CodeType.LOGIN
|
|
if (!email) {
|
|
throw new ZError(10, 'params mismatch')
|
|
}
|
|
if (!isEmail(email)) {
|
|
throw new ZError(11, 'Invalid email')
|
|
}
|
|
if (user.gameAccountBinded()) {
|
|
throw new ZError(12, 'already bind game account')
|
|
}
|
|
let openId = sha1(email)
|
|
let userCheck = await ActivityUser.findOne({ emailId: openId })
|
|
if (userCheck && userCheck.id !== user.id) {
|
|
throw new ZError(13, 'Email already binded to another account')
|
|
}
|
|
type = parseInt(type)
|
|
let record = await CodeRecord.findByEmail(user.id, email, type)
|
|
if (!record || record.user !== user.id) {
|
|
record = new CodeRecord({ email, type, code: DEFAULT_CODE, user: user.id })
|
|
await record.save()
|
|
}
|
|
let html, subject
|
|
switch (type) {
|
|
case CodeType.LOGIN:
|
|
html = DEFAULT_LOGIN_MAIL_HTML
|
|
subject = DEFAULT_LOGIN_MAIL_SUBJECT
|
|
}
|
|
if (!html || !subject) {
|
|
throw new ZError(15, 'type error')
|
|
}
|
|
|
|
subject = record.code + ' ' + subject
|
|
html = html.replace('{{ocde}}', record.code)
|
|
html = html.replace('{{time}}', new Date().format('yyyy-MM-dd hh:mm:ss'))
|
|
let msgData = {
|
|
to: email,
|
|
html,
|
|
subject,
|
|
}
|
|
setImmediate(async () => {
|
|
try {
|
|
let { errcode, errmsg, data } = await new EmailSvr().sendMail(msgData)
|
|
if (errcode) {
|
|
logger.info(`error send mail:: email: ${email}, type: ${type}, errcode: ${errcode}, errmsg: ${errmsg}`)
|
|
record.status = CodeStatus.FAIL
|
|
} else {
|
|
logger.info(`success send mail:: email: ${email}, type: ${type}, messageId: ${data.messageId}`)
|
|
record.mailSend = true
|
|
record.emailId = data.messageId
|
|
record.expiredAt = Date.now() + DEFAULT_EXPIRE_TIME
|
|
}
|
|
await record.save()
|
|
} catch (err) {
|
|
logger.info(`error send mail:: email: ${email}, type: ${type}, errmsg: ${err.message || err}`)
|
|
record.status = CodeStatus.FAIL
|
|
await record.save()
|
|
}
|
|
})
|
|
return {}
|
|
}
|
|
}
|