helper_20220215085858.js 3.17 KB
'use strict';
const moment = require('moment');

module.exports = {

  /**
   * 对象拼接为字符串
   * @param {object} object 待拼接的hash对象
   */
  concatHash(object) {
    const keys = Object.keys(object).sort();
    let paramsStr = '';
    for (let index = 0; index < keys.length; index++) {
      const key = keys[index];
      let value = object[key];
      // object参数类型转换为string
      if (typeof (value) === 'object') {
        value = JSON.stringify(value);
      }
      paramsStr = paramsStr + `${key}${value}`;
    }
    return paramsStr;
  },
  err({ ctx, code, err, status }) {
    ctx.body = {
      success: false,
      code: code || 1,
      err,
    };
    ctx.status = status || 200;
  },

  // 优化错误信息可读性
  errorReadable(e) {
    switch (e.code) {
      case 'invalid_param': { // 参数错误
        const errorHash = {
          missing_field: '缺失',
        };
        let msg = '';
        for (let i = 0; i < e.errors.length; i++) {
          msg += '参数' + e.errors[i].field + ' ' + (errorHash[e.errors[i].code] || e.errors[i].message) + ';';
        }
        return msg;
      }
      default:
        console.log('未优化类型错误!');
        return JSON.stringify(e);
    }
  },

  success({ ctx, data, status }) {
    ctx.body = {
      success: true,
      code: 0,
      data,
    };
    ctx.status = status || 200;
  },

  async verifySign(ctx) {
    const authorization = ctx.request.headers.authorization;
    const timestamp = ctx.request.headers.timestamp;
    const publicKey = ctx.request.headers.publickey;
    if (!timestamp) {
      this.err({
        ctx,
        err: 'hearder: timestamp不能为空',
      });
      return false;
    }
    if (!authorization) {
      this.err({
        ctx,
        err: 'hearder: authorization不能为空',
      });
      return false;
    }
    if (!publicKey) {
      this.err({
        ctx,
        err: 'hearder: publicKey不能为空',
      });
      return false;
    }
    // 验证时间不大于5秒
    const time = moment().valueOf();
    if (Math.abs(Number(timestamp) - time) > (ctx.app.config.timeEquation || 5000)) {
      ctx.body = {
        code: 1,
        err: '签名超时',
      };
      return false;
    }

    // 验证签名
    // 1. 获取请求者公钥
    const platformKey = await ctx.model.PlatformKey.findOne({ where: { publicKey } });
    if (!platformKey) {
      ctx.body = {
        code: 1,
        err: 'publicKey不存在',
      };
      return false;
    }
    if (!platformKey.usable) {
      ctx.body = {
        code: 1,
        err: '密钥对不可用',
      };
      return;
    }

    // 2. 对签名进行验证

    // 2.1 合并参数并排序组合拼接
    const allParams = { ...ctx.params, ...ctx.request.query, ...ctx.request.body, timestamp };
    const paramsStr = this.concatHash(allParams);

    const verify = this.service.sdk.gm.sm2VerifySign(paramsStr, authorization, publicKey);
    // 3. 比对时间戳
    if (!verify) {
      ctx.body = {
        code: 1,
        err: '签名无效',
      };
      return false;
    }
    // 记录当前媒体平台
    ctx.platformId = platformKey.platformId;
    return true;
  },

};