wechat.js 2.94 KB
'use strict';

/*
 * 生成微信分享所需的签名
 * bikai <kai.bi@yoho.cn>
 * 2016.6.15
 */
const request = require('request-promise');
const Promise = require('bluebird');
const crypto = require('crypto');
const logger = global.yoho.logger;
const cache = global.yoho.cache;

// 此处请勿使用有货公众号的 appId, 此处使用的是 女生志 的appId
const appId = 'wxb52ec6a352f0b090';
const secret = '9fe6bedb0b7f30986a168c7fc44f34c0';

const sha1 = (str) => {
    const generator = crypto.createHash('sha1');

    generator.update(str);
    return generator.digest('hex');
};

const accessTokenCacheKey = 'wechatShare:accessToken';
const ticketCacheKey = 'wechatShare:ticket';

// 微信 JS 接口签名校验工具 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

let _getAccessToken = Promise.coroutine(function* () {
    let accessToken = yield cache.get(accessTokenCacheKey);

    if (accessToken) {
        return accessToken;
    }

    logger.info('get accessToken from wechat API');
    return request({
        url: 'https://api.weixin.qq.com/cgi-bin/token',
        qs: {
            grant_type: 'client_credential',
            appid: appId,
            secret: secret
        },
        json: true
    }).then((res) => {

        // accessToken 有效期 7200s,缓存 7100s
        cache.set(accessTokenCacheKey, res.access_token, 7100).catch((err) => {
            logger.error('set wechat accessToken cache error', JSON.stringify(err));
        });
        return res.access_token;
    }).catch((err) => {
        logger.error('get accessToken from wechat API error', JSON.stringify(err));
    });
});

let _getTicket = Promise.coroutine(function* () {
    let ticket = yield cache.get(ticketCacheKey);

    if (ticket) {
        return ticket;
    }

    logger.info('get ticket from wechat API');
    return request({
        url: 'https://api.weixin.qq.com/cgi-bin/ticket/getticket',
        qs: {
            access_token: yield _getAccessToken(),
            type: 'jsapi'
        },
        json: true
    }).then(res => {

            // ticket 有效期 7200s,缓存 7100s
        cache.set(ticketCacheKey, res.ticket, 7100).catch((err) => {
            logger.error('set wechat Token cache error', JSON.stringify(err));
        });
        return res.ticket;
    }).catch((err) => {
        logger.error('get ticket from wechat API error', JSON.stringify(err));
    });
});

let calcSignature = Promise.coroutine(function* (data) {
    data = Object.assign({
        nonceStr: Math.random().toString(36).substr(2, 15),
        timestamp: Math.floor(Date.now() / 1000) + '',
        ticket: yield _getTicket(),
        appId: appId
    }, data);

    const str = `jsapi_ticket=${data.ticket}&noncestr=${data.nonceStr}&timestamp=${data.timestamp}&url=${data.url}`;

    data.signature = sha1(str);
    return data;
});

// 测试
// calcSignature({
//     url: 'http://www.yohobuy.com/'
// }).then(console.log);

module.exports = {
    calcSignature
};