|   | 
| const crypto = require('crypto'); | 
| const is = require('is-type-of'); | 
|   | 
| /** | 
|  * | 
|  * @param {String} resourcePath | 
|  * @param {Object} parameters | 
|  * @return | 
|  */ | 
| exports.buildCanonicalizedResource = function buildCanonicalizedResource(resourcePath, parameters) { | 
|   let canonicalizedResource = `${resourcePath}`; | 
|   let separatorString = '?'; | 
|   | 
|   if (is.string(parameters) && parameters.trim() !== '') { | 
|     canonicalizedResource += separatorString + parameters; | 
|   } else if (is.array(parameters)) { | 
|     parameters.sort(); | 
|     canonicalizedResource += separatorString + parameters.join('&'); | 
|   } else if (parameters) { | 
|     const compareFunc = (entry1, entry2) => { | 
|       if (entry1[0] > entry2[0]) { | 
|         return 1; | 
|       } else if (entry1[0] < entry2[0]) { | 
|         return -1; | 
|       } | 
|       return 0; | 
|     }; | 
|     const processFunc = (key) => { | 
|       canonicalizedResource += separatorString + key; | 
|       if (parameters[key]) { | 
|         canonicalizedResource += `=${parameters[key]}`; | 
|       } | 
|       separatorString = '&'; | 
|     }; | 
|     Object.keys(parameters).sort(compareFunc).forEach(processFunc); | 
|   } | 
|   | 
|   return canonicalizedResource; | 
| }; | 
|   | 
| /** | 
|  * @param {String} method | 
|  * @param {String} resourcePath | 
|  * @param {Object} request | 
|  * @param {String} expires | 
|  * @return {String} canonicalString | 
|  */ | 
| exports.buildCanonicalString = function canonicalString(method, resourcePath, request, expires) { | 
|   request = request || {}; | 
|   const headers = request.headers || {}; | 
|   const OSS_PREFIX = 'x-oss-'; | 
|   const ossHeaders = []; | 
|   const headersToSign = {}; | 
|   | 
|   let signContent = [ | 
|     method.toUpperCase(), | 
|     headers['Content-Md5'] || '', | 
|     headers['Content-Type'] || headers['Content-Type'.toLowerCase()], | 
|     expires || headers['x-oss-date'] | 
|   ]; | 
|   | 
|   Object.keys(headers).forEach((key) => { | 
|     const lowerKey = key.toLowerCase(); | 
|     if (lowerKey.indexOf(OSS_PREFIX) === 0) { | 
|       headersToSign[lowerKey] = String(headers[key]).trim(); | 
|     } | 
|   }); | 
|   | 
|   Object.keys(headersToSign).sort().forEach((key) => { | 
|     ossHeaders.push(`${key}:${headersToSign[key]}`); | 
|   }); | 
|   | 
|   signContent = signContent.concat(ossHeaders); | 
|   | 
|   signContent.push(this.buildCanonicalizedResource(resourcePath, request.parameters)); | 
|   | 
|   return signContent.join('\n'); | 
| }; | 
|   | 
| /** | 
|  * @param {String} accessKeySecret | 
|  * @param {String} canonicalString | 
|  */ | 
| exports.computeSignature = function computeSignature(accessKeySecret, canonicalString) { | 
|   const signature = crypto.createHmac('sha1', accessKeySecret); | 
|   return signature.update(new Buffer(canonicalString, 'utf8')).digest('base64'); | 
| }; | 
|   | 
| /** | 
|  * @param {String} accessKeyId | 
|  * @param {String} accessKeySecret | 
|  * @param {String} canonicalString | 
|  */ | 
| exports.authorization = function authorization(accessKeyId, accessKeySecret, canonicalString) { | 
|   return `OSS ${accessKeyId}:${this.computeSignature(accessKeySecret, canonicalString)}`; | 
| }; | 
|   | 
| /** | 
|  * | 
|  * @param {String} accessKeySecret | 
|  * @param {Object} options | 
|  * @param {String} resource | 
|  * @param {Number} expires | 
|  */ | 
| exports._signatureForURL = function _signatureForURL(accessKeySecret, options, resource, expires) { | 
|   const headers = {}; | 
|   const subResource = {}; | 
|   | 
|   if (options.process) { | 
|     const processKeyword = 'x-oss-process'; | 
|     subResource[processKeyword] = options.process; | 
|   } | 
|   | 
|   if (options.response) { | 
|     Object.keys(options.response).forEach((k) => { | 
|       const key = `response-${k.toLowerCase()}`; | 
|       subResource[key] = options.response[k]; | 
|     }); | 
|   } | 
|   | 
|   Object.keys(options).forEach((key) => { | 
|     const lowerKey = key.toLowerCase(); | 
|     const value = options[key]; | 
|     if (lowerKey.indexOf('x-oss-') === 0) { | 
|       headers[lowerKey] = value; | 
|     } else if (lowerKey.indexOf('content-md5') === 0) { | 
|       headers[key] = value; | 
|     } else if (lowerKey.indexOf('content-type') === 0) { | 
|       headers[key] = value; | 
|     } else if (lowerKey !== 'expires' && lowerKey !== 'response' && lowerKey !== 'process' && lowerKey !== 'method') { | 
|       subResource[lowerKey] = value; | 
|     } | 
|   }); | 
|   | 
|   if (Object.prototype.hasOwnProperty.call(options, 'security-token')) { | 
|     subResource['security-token'] = options['security-token']; | 
|   } | 
|   | 
|   if (Object.prototype.hasOwnProperty.call(options, 'callback')) { | 
|     const json = { | 
|       callbackUrl: encodeURI(options.callback.url), | 
|       callbackBody: options.callback.body | 
|     }; | 
|     if (options.callback.host) { | 
|       json.callbackHost = options.callback.host; | 
|     } | 
|     if (options.callback.contentType) { | 
|       json.callbackBodyType = options.callback.contentType; | 
|     } | 
|     subResource.callback = new Buffer(JSON.stringify(json)).toString('base64'); | 
|   | 
|     if (options.callback.customValue) { | 
|       const callbackVar = {}; | 
|       Object.keys(options.callback.customValue).forEach((key) => { | 
|         callbackVar[`x:${key}`] = options.callback.customValue[key]; | 
|       }); | 
|       subResource['callback-var'] = new Buffer(JSON.stringify(callbackVar)).toString('base64'); | 
|     } | 
|   } | 
|   | 
|   const canonicalString = this.buildCanonicalString(options.method, resource, { | 
|     headers, | 
|     parameters: subResource | 
|   }, expires.toString()); | 
|   | 
|   return { | 
|     Signature: this.computeSignature(accessKeySecret, canonicalString), | 
|     subResource | 
|   }; | 
| }; |