增加一个用于验证客户端分享码的接口
This commit is contained in:
parent
305d784426
commit
62af6b9332
37
docs/uaw.md
37
docs/uaw.md
@ -68,6 +68,11 @@
|
||||
1. 用户状态(10) 增加返回emailId, email, gameId, gameMail
|
||||
2. 增加接口: 发送邮件验证码(33), 验证邮件地址(34)
|
||||
|
||||
#### 20240515
|
||||
1. 增加接口: 验证客户端分享码(35)
|
||||
|
||||
|
||||
|
||||
### 1. 钱包预登录
|
||||
|
||||
#### Request
|
||||
@ -1064,3 +1069,35 @@ export const isValiedCode = (code) => {
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
### 35.\* 验证客户端分享码
|
||||
|
||||
#### Request
|
||||
|
||||
- URL:`/api/user/verify_client`
|
||||
- 方法:POST
|
||||
- 头部:
|
||||
- Authorization: Bearer JWT_token
|
||||
|
||||
|
||||
body:
|
||||
|
||||
```js
|
||||
{
|
||||
"code": "12322100"
|
||||
}
|
||||
|
||||
```
|
||||
> 验证code的正则
|
||||
```js
|
||||
export const isValiedCode = (code) => {
|
||||
return /^[23456789abcdefghjkmnpqrstuvwxy]{8}$/.test(code)
|
||||
}
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
```js
|
||||
{
|
||||
}
|
||||
```
|
@ -76,6 +76,9 @@ class InGameController extends BaseController {
|
||||
} else if (user.emailId) {
|
||||
let res = await queryInGameInfo(user.emailId, '6')
|
||||
Object.assign(gameData, res)
|
||||
} else if (user.clientId) {
|
||||
let res = await queryInGameInfo(user.clientId, user.clientPlat)
|
||||
Object.assign(gameData, res)
|
||||
}
|
||||
} catch (e) {
|
||||
logger.info('queryInGameInfo with err: ', e.message || e)
|
||||
|
@ -13,12 +13,16 @@ import { DEFAULT_LOGIN_MAIL_HTML, DEFAULT_LOGIN_MAIL_SUBJECT, EmailSvr } from 's
|
||||
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')
|
||||
// @router('post /api/user/verify_email')
|
||||
async loginWithEmail(req, res) {
|
||||
await new SyncLocker().checkLock(req)
|
||||
logger.db('verify_email', req)
|
||||
@ -56,10 +60,47 @@ class MailController extends BaseController {
|
||||
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 })
|
||||
if (userCheck && userCheck.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')
|
||||
// @router('post /api/email/send_code')
|
||||
async sendVerifyCode(req, res) {
|
||||
await new SyncLocker().checkLock(req)
|
||||
logger.db('send_mail_code', req)
|
||||
|
@ -191,7 +191,7 @@ class SignController extends BaseController {
|
||||
@router('post /api/user/verify_google')
|
||||
async verifyGoogleToken(req) {
|
||||
const user = req.user
|
||||
if (user.googleId) {
|
||||
if (user.gameAccountBinded()) {
|
||||
throw new ZError(11, 'already bind google')
|
||||
}
|
||||
const { openId, data } = await verifyToken(req)
|
||||
|
@ -51,6 +51,7 @@ export interface ActivityUserClass extends Base, TimeStamps {}
|
||||
@index({ twitterId: 1 }, { unique: true, partialFilterExpression: { twitterId: { $exists: true } } })
|
||||
@index({ googleId: 1 }, { unique: true, partialFilterExpression: { googleId: { $exists: true } } })
|
||||
@index({ emailId: 1 }, { unique: true, partialFilterExpression: { emailId: { $exists: true } } })
|
||||
@index({ clientId: 1, clientPlat: 1 }, { unique: true, partialFilterExpression: { clientId: { $exists: true } } })
|
||||
@index({ discordId: 1 }, { unique: true, partialFilterExpression: { discordId: { $exists: true } } })
|
||||
@modelOptions({
|
||||
schemaOptions: { collection: 'activity_user', timestamps: true },
|
||||
@ -117,6 +118,13 @@ export class ActivityUserClass extends BaseModule {
|
||||
@prop()
|
||||
public email?: string
|
||||
|
||||
@prop()
|
||||
public clientId?: string
|
||||
@prop()
|
||||
public clientMail?: string
|
||||
@prop()
|
||||
public clientPlat?: string
|
||||
|
||||
@prop({ default: false })
|
||||
public inWhiteList: boolean
|
||||
|
||||
@ -150,14 +158,14 @@ export class ActivityUserClass extends BaseModule {
|
||||
}
|
||||
|
||||
public gameAccountBinded() {
|
||||
return this.googleId || this.emailId
|
||||
return this.googleId || this.emailId || this.clientId
|
||||
}
|
||||
|
||||
public gameId() {
|
||||
return this.googleId || this.emailId
|
||||
return this.googleId || this.emailId || this.clientId
|
||||
}
|
||||
public gameMail() {
|
||||
return this.googleEmail || this.email
|
||||
return this.googleEmail || this.email || this.clientMail
|
||||
}
|
||||
}
|
||||
|
||||
|
67
src/models/wallet/ShareCodeRecord.ts
Normal file
67
src/models/wallet/ShareCodeRecord.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { getModelForClass, index, modelOptions, pre, prop, ReturnModelType } from '@typegoose/typegoose'
|
||||
import { dbconn } from 'decorators/dbconn'
|
||||
import { BaseModule } from '../Base'
|
||||
|
||||
import { customAlphabet } from 'nanoid'
|
||||
|
||||
const nanoid = customAlphabet('1234567890', 8)
|
||||
|
||||
export const DEFAULT_SHARE_CODE = '00000000'
|
||||
export const DEFAULT_EXPIRE_TIME = 5 * 60 * 1000
|
||||
|
||||
export enum ShareCodeType {
|
||||
BIND_UAW = 1, // uaw 绑定
|
||||
}
|
||||
|
||||
export enum ShareCodeStatus {
|
||||
PENDING = 1,
|
||||
SUCCESS = 2,
|
||||
FAIL = 3,
|
||||
EXPIRED = 4,
|
||||
}
|
||||
|
||||
/**
|
||||
* 分享码记录
|
||||
*/
|
||||
@dbconn('wallet')
|
||||
@index({ type: 1, code: 1 }, { unique: true, partialFilterExpression: { status: 1 } })
|
||||
@index({ account: 1, type: 1, status: 1 }, { unique: true, partialFilterExpression: { status: 1 } })
|
||||
@index({ expiredAt: 1, status: 1 }, { unique: false })
|
||||
@modelOptions({
|
||||
schemaOptions: { collection: 'share_code_record', timestamps: true },
|
||||
})
|
||||
class ShareCodeRecordClass extends BaseModule {
|
||||
@prop({ required: true })
|
||||
public account: string
|
||||
|
||||
@prop({ required: true })
|
||||
public openId: string
|
||||
|
||||
@prop()
|
||||
public email?: string
|
||||
|
||||
@prop({ required: true })
|
||||
public plat: string
|
||||
|
||||
@prop({ required: true })
|
||||
public code!: string
|
||||
|
||||
@prop({ default: Date.now() + DEFAULT_EXPIRE_TIME })
|
||||
public expiredAt?: number
|
||||
|
||||
@prop({ required: true, default: ShareCodeType.BIND_UAW })
|
||||
public type: ShareCodeType
|
||||
|
||||
@prop({ required: true, default: ShareCodeStatus.PENDING })
|
||||
public status: ShareCodeStatus
|
||||
|
||||
public static async findByCode(
|
||||
this: ReturnModelType<typeof ShareCodeRecordClass>,
|
||||
code: string,
|
||||
type: ShareCodeType,
|
||||
) {
|
||||
return this.findOne({ code, type, status: ShareCodeStatus.PENDING }).exec()
|
||||
}
|
||||
}
|
||||
|
||||
export const ShareCodeRecord = getModelForClass(ShareCodeRecordClass, { existingConnection: ShareCodeRecordClass.db })
|
@ -33,7 +33,14 @@ export abstract class ITask {
|
||||
|
||||
public async claimReward(cfg: any) {
|
||||
const user = this.user
|
||||
let channel = user.googleId ? '0' : '6'
|
||||
let channel = '0'
|
||||
if (user.googleId) {
|
||||
channel = '0'
|
||||
} else if (user.emailId) {
|
||||
channel = '6'
|
||||
} else if (user.clientId) {
|
||||
channel = user.clientPlat
|
||||
}
|
||||
let gameId = user.gameId()
|
||||
let gameData = await queryInGameInfo(gameId, channel)
|
||||
if (!(await this.check(cfg, gameData))) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user