signUtils.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. const crypto = require('crypto');
  2. const is = require('is-type-of');
  3. /**
  4. *
  5. * @param {String} resourcePath
  6. * @param {Object} parameters
  7. * @return
  8. */
  9. exports.buildCanonicalizedResource = function buildCanonicalizedResource(resourcePath, parameters) {
  10. let canonicalizedResource = `${resourcePath}`;
  11. let separatorString = '?';
  12. if (is.string(parameters) && parameters.trim() !== '') {
  13. canonicalizedResource += separatorString + parameters;
  14. } else if (is.array(parameters)) {
  15. parameters.sort();
  16. canonicalizedResource += separatorString + parameters.join('&');
  17. } else if (parameters) {
  18. const compareFunc = (entry1, entry2) => {
  19. if (entry1[0] > entry2[0]) {
  20. return 1;
  21. } else if (entry1[0] < entry2[0]) {
  22. return -1;
  23. }
  24. return 0;
  25. };
  26. const processFunc = (key) => {
  27. canonicalizedResource += separatorString + key;
  28. if (parameters[key]) {
  29. canonicalizedResource += `=${parameters[key]}`;
  30. }
  31. separatorString = '&';
  32. };
  33. Object.keys(parameters).sort(compareFunc).forEach(processFunc);
  34. }
  35. return canonicalizedResource;
  36. };
  37. /**
  38. * @param {String} method
  39. * @param {String} resourcePath
  40. * @param {Object} request
  41. * @param {String} expires
  42. * @return {String} canonicalString
  43. */
  44. exports.buildCanonicalString = function canonicalString(method, resourcePath, request, expires) {
  45. request = request || {};
  46. const headers = request.headers || {};
  47. const OSS_PREFIX = 'x-oss-';
  48. const ossHeaders = [];
  49. const headersToSign = {};
  50. let signContent = [
  51. method.toUpperCase(),
  52. headers['Content-Md5'] || '',
  53. headers['Content-Type'] || headers['Content-Type'.toLowerCase()],
  54. expires || headers['x-oss-date']
  55. ];
  56. Object.keys(headers).forEach((key) => {
  57. const lowerKey = key.toLowerCase();
  58. if (lowerKey.indexOf(OSS_PREFIX) === 0) {
  59. headersToSign[lowerKey] = String(headers[key]).trim();
  60. }
  61. });
  62. Object.keys(headersToSign).sort().forEach((key) => {
  63. ossHeaders.push(`${key}:${headersToSign[key]}`);
  64. });
  65. signContent = signContent.concat(ossHeaders);
  66. signContent.push(this.buildCanonicalizedResource(resourcePath, request.parameters));
  67. return signContent.join('\n');
  68. };
  69. /**
  70. * @param {String} accessKeySecret
  71. * @param {String} canonicalString
  72. */
  73. exports.computeSignature = function computeSignature(accessKeySecret, canonicalString, headerEncoding = 'utf-8') {
  74. const signature = crypto.createHmac('sha1', accessKeySecret);
  75. return signature.update(Buffer.from(canonicalString, headerEncoding)).digest('base64');
  76. };
  77. /**
  78. * @param {String} accessKeyId
  79. * @param {String} accessKeySecret
  80. * @param {String} canonicalString
  81. */
  82. exports.authorization = function authorization(accessKeyId, accessKeySecret, canonicalString, headerEncoding) {
  83. return `OSS ${accessKeyId}:${this.computeSignature(accessKeySecret, canonicalString, headerEncoding)}`;
  84. };
  85. /**
  86. *
  87. * @param {String} accessKeySecret
  88. * @param {Object} options
  89. * @param {String} resource
  90. * @param {Number} expires
  91. */
  92. exports._signatureForURL = function _signatureForURL(accessKeySecret, options = {}, resource, expires, headerEncoding) {
  93. const headers = {};
  94. const { subResource = {} } = options;
  95. if (options.process) {
  96. const processKeyword = 'x-oss-process';
  97. subResource[processKeyword] = options.process;
  98. }
  99. if (options.trafficLimit) {
  100. const trafficLimitKey = 'x-oss-traffic-limit';
  101. subResource[trafficLimitKey] = options.trafficLimit;
  102. }
  103. if (options.response) {
  104. Object.keys(options.response).forEach((k) => {
  105. const key = `response-${k.toLowerCase()}`;
  106. subResource[key] = options.response[k];
  107. });
  108. }
  109. Object.keys(options).forEach((key) => {
  110. const lowerKey = key.toLowerCase();
  111. const value = options[key];
  112. if (lowerKey.indexOf('x-oss-') === 0) {
  113. headers[lowerKey] = value;
  114. } else if (lowerKey.indexOf('content-md5') === 0) {
  115. headers[key] = value;
  116. } else if (lowerKey.indexOf('content-type') === 0) {
  117. headers[key] = value;
  118. }
  119. });
  120. if (Object.prototype.hasOwnProperty.call(options, 'security-token')) {
  121. subResource['security-token'] = options['security-token'];
  122. }
  123. if (Object.prototype.hasOwnProperty.call(options, 'callback')) {
  124. const json = {
  125. callbackUrl: encodeURI(options.callback.url),
  126. callbackBody: options.callback.body
  127. };
  128. if (options.callback.host) {
  129. json.callbackHost = options.callback.host;
  130. }
  131. if (options.callback.contentType) {
  132. json.callbackBodyType = options.callback.contentType;
  133. }
  134. subResource.callback = Buffer.from(JSON.stringify(json)).toString('base64');
  135. if (options.callback.customValue) {
  136. const callbackVar = {};
  137. Object.keys(options.callback.customValue).forEach((key) => {
  138. callbackVar[`x:${key}`] = options.callback.customValue[key];
  139. });
  140. subResource['callback-var'] = Buffer.from(JSON.stringify(callbackVar)).toString('base64');
  141. }
  142. }
  143. const canonicalString = this.buildCanonicalString(options.method, resource, {
  144. headers,
  145. parameters: subResource
  146. }, expires.toString());
  147. return {
  148. Signature: this.computeSignature(accessKeySecret, canonicalString, headerEncoding),
  149. subResource
  150. };
  151. };