Source: Certificate.js

/**
 * Copyright (c) 2017 Baidu, Inc. All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


'use strict';

const crypto = require('crypto');
const fs = require('fs');
const request = require('request');

/**
 * 认证
 **/
class Certificate {
    /**
     * @param {Object} headers http请求的header
     * @param {string} requestBody 请求体
     * @param {string} privateKeyContent 私钥. 用于请求DuerOS参数签名
     **/
    constructor (headers, requestBody, privateKeyContent = '') {
        this.data = requestBody;  
        this.headers = headers;
        this.privateKey = privateKeyContent;
        this.verifyRequestSign = false;
    }

    /**
     * 开启验证请求参数签名,阻止非法请求
     *
     * @return {boolean}
     * @public
     */
    enableVerifyRequestSign() {
        this.verifyRequestSign = true; 
        return this;
    }
    /**
     * 关闭验证请求参数签名
     *
     * @return {boolean}
     * @public
     */
    disableVerifyRequestSign() {
        this.verifyRequestSign = false; 
        return this;
    }

    /**
     * @return promise
     * @private
     */
    _getRequestPublicKey() {
        var _this = this;
        return new Promise(function(resolve, reject){
            var url = _this.headers.signaturecerturl;
            if(!url) {
                reject(); 
            }

            var hash = crypto.createHash('md5');
            var cache = __dirname + '/' + hash.update(url).digest('hex');

            let content = '';
            fs.access(cache, (err) => {
                if(err) {
                    request({
                        url: url,
                        method: 'GET',
                    }, function(error, response, body){
                        let content = body;

                        if(!content) {
                            return reject(); 
                        }

                        fs.writeFile(cache, content, {encoding: "utf8"}, (err) => {
                            if (err) {
                                console.error(err); 
                            } 

                            // 缓存失败,但内容已经获取了
                            resolve(content);
                        });
                    });
                } else {
                    fs.readFile(cache, {encoding: "utf8"}, (err, data) => {
                        if(err) {
                            console.error(err); 
                            reject();
                        } else {
                            resolve(data); 
                        }
                    });
                }
            });
        });
    }


    /**
     * @desc 验证请求者是否合法
     * @return promise
     * @public
     */
    verifyRequest() {
        var _this = this;
        return new Promise(function(resolve, reject){
            var verify = crypto.createVerify('RSA-SHA1');

            if(!_this.verifyRequestSign) {
                resolve(true);
            }

            _this._getRequestPublicKey().then(function(publicKey){

                if(!publicKey || !_this.data) {
                    reject();
                }

                verify.update(_this.data);
                let isSignatureValid = verify.verify(publicKey.toString(), _this.getRequestSig(), 'base64');
                if(isSignatureValid) {
                    resolve(isSignatureValid);
                }else {

                    reject();
                }

            }, function(){
                reject();
            }); 
        });
    }

    /**
     * @return string
     * @public
     */
    getRequestSig() {
        return this.headers.signature;
    }
}
 
module.exports = Certificate;