{"size": 1719, "ext": "js", "max_stars_repo_path": "app/middleware/application_authenticate.js", "max_stars_repo_name": "AidenChen/im-server", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "app/middleware/application_authenticate.js", "max_issues_repo_name": "AidenChen/im-server", "max_issues_repo_issues_event_min_datetime": "2021-03-01T20:49:54.000Z", "max_issues_repo_issues_event_max_datetime": "2022-03-08T21:35:45.000Z", "max_forks_repo_path": "app/middleware/application_authenticate.js", "max_forks_repo_name": "AidenChen/im-server", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": 6, "max_forks_count": null, "avg_line_length": 30.6964285714, "max_line_length": 91, "alphanum_fraction": 0.6544502618}
const Kamora = require('kamora')
const jwt = require('jsonwebtoken')
const error = require('../../config/error')
const jwtConfig = require('../../config/jwt')

const Application = Kamora.Database.model('application')

const getApplicationFromToken = async (token) => {
  const application = await Application
    .findById(token.uid)
    .catch(() => {
      throw new Kamora.Error(error.name.INTERNAL_SERVER_ERROR)
    })
  if (!application) {
    throw new Kamora.Error(error.name.NOT_EXIST)
  }
  return application
}

module.exports = async (ctx, next) => {
  const token = ctx.get('Authorization')
  if (!token) {
    throw new Kamora.Error(error.name.LOGIN_REQUIRED, '令牌认证失败')
  }

  try {
    const decoded = await jwt.verify(token, jwtConfig.secret)

    ctx.filter = ctx.filter || {}
    ctx.filter.application = await getApplicationFromToken(decoded)
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      // ignoreExpiration为true时即使过期也能解析成功
      const decoded = await jwt.verify(token, jwtConfig.secret, { ignoreExpiration: true })

      // 只要令牌在刷新期限内，就给发放新的令牌，不论旧令牌是否已经生成过新令牌，也不作废旧令牌
      if (Math.floor(Date.now() / 1000) - decoded.exp <= jwtConfig.refresh_ttl * 60) {
        ctx.filter = ctx.filter || {}
        ctx.filter.application = await getApplicationFromToken(decoded)

        const newToken = jwt.sign({
          uid: decoded.uid,
          exp: Math.floor(Date.now() / 1000) + jwtConfig.ttl * 60
        }, jwtConfig.secret)
        ctx.set('Authorization', newToken)
      } else {
        throw new Kamora.Error(error.name.LOGIN_REQUIRED, '令牌已过期，请重新登录')
      }
    } else {
      throw new Kamora.Error(error.name.LOGIN_REQUIRED, '令牌不合法，请重新登录')
    }
  }

  await next()
}
