import BaseController, {ROLE_ANON} from 'common/base.controller' import {ZError} from 'common/ZError' import { role, router } from 'decorators/router' import logger from 'logger/logger' import { ActivityUser } from 'models/ActivityUser' import {DEFAULT_EXPIRED, NonceRecord} from 'models/NonceRecord' import { LoginRecordQueue } from 'queue/loginrecord.queue' import { RedisClient } from 'redis/RedisClient' import { rankKey } from 'services/rank.svr' import {SiweMessage} from 'siwe' import { yesterday } from 'utils/date.util' import { checkParamsNeeded } from 'utils/net.util' import { aesDecrypt, base58ToHex } from 'utils/security.util' const LOGIN_TIP = 'This signature is just to verify your identity' class SignController extends BaseController { @role(ROLE_ANON) @router('get /api/wallet/nonce') async walletNonce(req, res) { const { address } = req.params let record = new NonceRecord({ expired: Date.now() + DEFAULT_EXPIRED, address }) await record.save() return { nonce: record.id, tips: LOGIN_TIP } } //TODO:: 增加okx的奖励 @role(ROLE_ANON) @router('post /api/wallet/login') async walletVerify(req, res) { const { signature, message, activity } = req.params checkParamsNeeded(signature, message) if (!message.nonce) { throw new ZError(11, 'Invalid nonce'); } let nonce = message.nonce let source = 'unknow' if (nonce.length > 24) { nonce = base58ToHex(nonce); let nonceStr = aesDecrypt(nonce, activity); if (nonceStr.indexOf('|') >=0 ) { const split = nonceStr.split('|') nonce = split[0]; source = split[1]; } else { nonce = nonceStr; } } let record = await NonceRecord.findById(nonce) if (!record || record.status !== 0) { throw new ZError(12, 'nonce invalid') } if (record.expired < Date.now()) { throw new ZError(13, 'nonce expired') } if (record.address.toLowerCase() !== message.address.toLowerCase()) { throw new ZError(14, 'address not match') } record.status = 1 await record.save() const msgSign = new SiweMessage(message); try { await msgSign.verify({ signature, nonce: message.nonce }); } catch (e) { throw new ZError(15, 'signature invalid') } let accountData = await ActivityUser.insertOrUpdate({ address: message.address, activity }, {}) if (!accountData) { throw new ZError(11, 'user not found') } if (accountData.locked) { throw new ZError(12, 'user locked') } accountData.lastLogin = Date.now() await accountData.save() new LoginRecordQueue().addLog(req, accountData.id, activity, source) const token = await res.jwtSign({ id: accountData.id, address: accountData.address, activity: accountData.activity }) return { token } } @router('get /api/user/state') async userInfo(req){ const user = req.user; const todayKey = rankKey(user.activity, new Date()); const todayScore = await new RedisClient().zscore(todayKey, user.id) const totalKey = rankKey(user.activity); const totalScore = await new RedisClient().zscore(totalKey, user.id) const totalRank = await new RedisClient().zrevrank(totalKey, user.id) let invite = '' if (user.inviteUser) { const inviteUser = await ActivityUser.findById(user.inviteUser) if (inviteUser) { invite = inviteUser.address } } let result = { address: user.address, boost: user.boost || 1, boostExpire: user.boostExpire, twitterId: user.twitterId, twitterName: user.twitterName, discordId: user.discordId, discordName: user.discordName, scoreToday: todayScore ? parseInt(todayScore+'') : 0, scoreTotal: totalScore ? parseInt(totalScore+'') : 0, rankTotal: totalRank ? totalRank : '-', invite, code: user.inviteCode, } return result; } /** * regist user by token from wallet-svr * TODO:: * @param req * @param res * @returns */ @role(ROLE_ANON) @router('post /api/wallet/verify_token') async verifyToken(req, res) { const { wallet_token } = req.params return {} } }