增加重要日志的记录

This commit is contained in:
zhl 2023-04-18 22:23:37 +08:00
parent 403f37ac12
commit 3034702f3f
5 changed files with 118 additions and 18 deletions

View File

@ -1,4 +1,4 @@
import { permission, role, router } from 'decorators/router'
import { role, router } from 'decorators/router'
import BaseController, { ROLE_ANON } from 'common/base.controller'
import { ZError } from 'common/ZError'
import { NonceRecord } from 'models/NonceRecord'
@ -9,7 +9,7 @@ import { User } from 'models/User'
const LOGIN_TIP = 'This signature is just to verify your identity'
export default class AccountController extends BaseController {
@role(ROLE_ANON)
@router('get /api/wallet/wallet_nonce')
@router('get /api/user/login')
async walletNonce(req, res) {
let record = new NonceRecord()
await record.save()
@ -17,49 +17,65 @@ export default class AccountController extends BaseController {
}
// wallet login
@role(ROLE_ANON)
@router('post /api/wallet/wallet_login')
@router('post /api/user/login')
async loginWallet(req, res) {
const { nonce, signature, account } = req.params
logger.info(`wallet login::account:${account} nonce:${nonce} signature:${signature}`)
if (!nonce || !signature || !account) {
const { nonce, signature, address } = req.params
logger.db('login', req)
logger.info(`wallet login::address:${address} nonce:${nonce} signature:${signature}`)
if (!nonce || !signature || !address) {
throw new ZError(10, 'params mismatch')
}
let record = await NonceRecord.findById(nonce)
if (!record || record.status !== 0) {
throw new ZError(11, 'nonce invalid')
}
if (record.expired < Date.now()) {
throw new ZError(12, 'nonce expired')
}
record.status = 1
await record.save()
const signObj = buildLoginSignMsg(nonce, LOGIN_TIP)
const recover = recoverTypedSignatureV4(signObj, signature)
if (recover !== account) {
if (recover !== address) {
throw new ZError(20, 'address mismatch')
}
let accountData = await User.findByAddress(account)
let accountData = await User.insertOrUpdate({ address }, {})
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()
const token = await res.jwtSign({ id: accountData.id })
setImmediate(() => {
NonceRecord.removeExpired()
})
return { token }
}
@router('post /api/wallet/logout')
async logout(req, res) {
return {}
}
@router('get /api/user/:uid/info')
@router('get /api/user/status')
async info(req) {
let uid = req.params.uid
const account = await User.findById(uid)
return { account: account, user: req.user }
let user = req.user
return {}
}
@router('post /api/user/claim')
async claim(req, res) {
return {}
let user = req.user
logger.db('claim', req)
const {} = req.params
const taskId = ''
return { taskId }
}
@router('get /api/user/claim/:taskId')
async claimStatus(req, res) {
const { taskId } = req.params
const txHashList = []
let status = 0
return { status, txHashList }
}
}

View File

@ -1,3 +1,9 @@
import { LoggerQueue } from 'queue/logger.queue'
const level = process.env.NODE_ENV === 'production' ? 'info' : 'log'
const logger = require('tracer').colorConsole({ dateformat: 'yyyy-mm-dd HH:MM:ss.L', level })
logger.db = function (name: string, req: any, logObj?: any) {
logObj = logObj || {}
new LoggerQueue().addLog(name, req, logObj)
}
export default logger

View File

@ -2,11 +2,19 @@ import { getModelForClass, index, modelOptions, pre, prop } from '@typegoose/typ
import { dbconn } from 'decorators/dbconn'
import { BaseModule } from './Base'
const DEFAULT_EXPIRED = 1000 * 60 * 5
@dbconn()
@modelOptions({ schemaOptions: { collection: 'nonce_record', timestamps: true } })
class NonceRecordClass extends BaseModule {
@prop({ required: true, default: 0 })
public status: number
@prop({ default: Date.now() + DEFAULT_EXPIRED })
public expired: number
public static async removeExpired() {
await NonceRecord.deleteMany({ expired: { $lt: Date.now() } })
}
}
export const NonceRecord = getModelForClass(NonceRecordClass, { existingConnection: NonceRecordClass['db'] })

31
src/models/UserLog.ts Normal file
View File

@ -0,0 +1,31 @@
import { dbconn } from 'decorators/dbconn'
import { getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
import { BaseModule } from './Base'
/**
*
*/
@dbconn()
@index({ user: 1 }, { unique: false })
@index({ name: 1 }, { unique: false })
@modelOptions({ schemaOptions: { collection: 'user_log', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
class UserLogClass extends BaseModule {
@prop()
public user: string
@prop()
public name: string
@prop()
public method: string
@prop()
public path: string
@prop()
public referer: string
@prop()
public user_agent: string
@prop()
public ip: string
@prop({ type: mongoose.Schema.Types.Mixed })
public params: any
}
export const UserLog = getModelForClass(UserLogClass, { existingConnection: UserLogClass['db'] })

39
src/queue/logger.queue.ts Normal file
View File

@ -0,0 +1,39 @@
import { AsyncQueue, createAsyncQueue } from 'common/AsyncQueue'
import { singleton } from 'decorators/singleton'
import logger from 'logger/logger'
import { UserLog } from 'models/UserLog'
@singleton
export class LoggerQueue {
private queue: AsyncQueue
constructor() {
this.queue = createAsyncQueue()
}
public addLog(name, req, logObj) {
this.queue.push(async () => {
const user = req.user
const ip = req.headers['x-forwarded-for'] || req.ip
const path = req.url
const params = req.method === 'GET' ? req.query : req.body
const dataObj = JSON.stringify(logObj) === '{}' ? params : logObj
try {
const history = new UserLog({
user: user ? user.id : '',
path: path,
method: req.method,
params: dataObj,
referer: req.headers['referer'],
user_agent: req.headers['user-agent'],
ip,
name,
})
await history.save()
} catch (err) {
logger.error('error add user log: ')
logger.error(err)
}
})
}
}