util.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * @copyright
  3. * Copyright © Microsoft Open Technologies, Inc.
  4. *
  5. * All Rights Reserved
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http: *www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
  14. * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
  15. * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
  16. * PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
  17. *
  18. * See the Apache License, Version 2.0 for the specific language
  19. * governing permissions and limitations under the License.
  20. */
  21. 'use strict';
  22. var _ = require('underscore');
  23. var adalIdConstants = require('./constants').AdalIdParameters;
  24. var os = require('os');
  25. var url = require('url');
  26. var ADAL_VERSION;
  27. /**
  28. * @namespace Util
  29. * @private
  30. */
  31. function loadAdalVersion() {
  32. ADAL_VERSION = require('../package.json').version;
  33. }
  34. function adalInit() {
  35. loadAdalVersion();
  36. }
  37. /**
  38. * @static
  39. * @memberOf Util
  40. * @param {string|int} statusCode An HTTP status code.
  41. */
  42. function isHttpSuccess(statusCode) {
  43. return statusCode >= 200 && statusCode < 300;
  44. }
  45. function addDefaultRequestHeaders (self, options) {
  46. if (!options.headers) {
  47. options.headers = {};
  48. }
  49. var headers = options.headers;
  50. if (!headers['Accept-Charset']) {
  51. headers['Accept-Charset'] = 'utf-8';
  52. }
  53. headers['client-request-id'] = self._callContext._logContext.correlationId;
  54. headers['return-client-request-id'] = 'true';
  55. // ADAL Id headers
  56. headers[adalIdConstants.SKU] = adalIdConstants.NODE_SKU;
  57. headers[adalIdConstants.VERSION] = ADAL_VERSION;
  58. headers[adalIdConstants.OS] = os.platform();
  59. headers[adalIdConstants.CPU] = os.arch();
  60. }
  61. /**
  62. * Central place for housing default request options. This is a place holder
  63. * for when SSL validation is implemented an all requests are subject to that
  64. * policy.
  65. * @static
  66. * @memberOf Util
  67. * @param {object} options A set of options that will be merged with teh default options
  68. * These will override any default options.
  69. * @returns {object} Returns the merged options.
  70. */
  71. function createRequestOptions(self, options) {
  72. var defaultOptions = {}; //{ strictSSL : true };
  73. var mergedOptions = defaultOptions;
  74. if (options) {
  75. _.extend(mergedOptions, options);
  76. }
  77. if (self._callContext.options && self._callContext.options.http) {
  78. _.extend(mergedOptions, self._callContext.options.http);
  79. }
  80. addDefaultRequestHeaders(self, mergedOptions);
  81. return mergedOptions;
  82. }
  83. function logReturnCorrelationId(log, operationMessage, response) {
  84. if (response && response.headers && response.headers['client-request-id']) {
  85. log.info(operationMessage + 'Server returned this correlationId: ' + response.headers['client-request-id'], true);
  86. }
  87. }
  88. /**
  89. * Creates a function that can be used as the callback for http request operations. This is meant
  90. * to centralize error handling in one place.
  91. * @static
  92. * @memberOf Util
  93. * @param {string} operationMessage A message to be prepended to logged error strings. This should be something like 'Mex Request'
  94. * and summarize the purpose of the http request.
  95. * @param {object} log A Logger object being used by the calling component.
  96. * @param {Util.CreateRequestHandlerErrorCallback} errorCallback Called in the event of an error.
  97. * @param {Util.CreateRequestHandlerSuccessCallabck} successCallback Called on successfull completion of the request.
  98. */
  99. function createRequestHandler(operationMessage, log, errorCallback, successCallback) {
  100. return function(err, response, body) {
  101. logReturnCorrelationId(log, operationMessage, response);
  102. if (err) {
  103. log.error(operationMessage + ' request failed with', err, true);
  104. errorCallback(err);
  105. return;
  106. }
  107. if (!isHttpSuccess(response.statusCode)) {
  108. var returnErrorString = operationMessage + ' request returned http error: ' + response.statusCode;
  109. var errorResponse;
  110. if (body) {
  111. returnErrorString += ' and server response: ' + body;
  112. try {
  113. errorResponse = JSON.parse(body);
  114. } catch (e) {
  115. // No problem if it doesn't parse.
  116. }
  117. }
  118. errorCallback(log.createError(returnErrorString, true), errorResponse);
  119. return;
  120. }
  121. successCallback(response, body);
  122. };
  123. }
  124. /**
  125. * @callback CreateRequestHandlerErrorCallback
  126. * @memberOf Util
  127. * @param {Error} error An error object.
  128. */
  129. /**
  130. * @callback CreateRequestHandlerSuccessCallabck
  131. * @memberOf Util
  132. * @param {object} response The response object returned from request.
  133. * @param {string} body The body of the http response.
  134. */
  135. /**
  136. * Deep copies a url object.
  137. * @static
  138. * @memberOf Util
  139. * @param {URL} urlSource The source url object to copy.
  140. * @returns {URL} A deep copy of sourceUrl.
  141. */
  142. function copyUrl(urlSource) {
  143. return url.parse(url.format(urlSource));
  144. }
  145. function convertUrlSafeToRegularBase64EncodedString(str) {
  146. return str.replace(/-/g, '+').replace(/_/g, '/');
  147. }
  148. function convertRegularToUrlSafeBase64EncodedString(str) {
  149. return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
  150. }
  151. function base64DecodeStringUrlSafe(str) {
  152. var base64 = convertUrlSafeToRegularBase64EncodedString(str);
  153. return (new Buffer(base64, 'base64')).toString('utf8');
  154. }
  155. function base64EncodeStringUrlSafe(str) {
  156. var base64 = (new Buffer(str, 'utf8').toString('base64'));
  157. var converted = convertRegularToUrlSafeBase64EncodedString(base64);
  158. return converted;
  159. }
  160. module.exports.adalInit = adalInit;
  161. module.exports.isHttpSuccess = isHttpSuccess;
  162. module.exports.createRequestHandler = createRequestHandler;
  163. module.exports.createRequestOptions = createRequestOptions;
  164. module.exports.copyUrl = copyUrl;
  165. module.exports.base64DecodeStringUrlSafe = base64DecodeStringUrlSafe;
  166. module.exports.base64EncodeStringUrlSafe = base64EncodeStringUrlSafe;
  167. module.exports.convertRegularToUrlSafeBase64EncodedString = convertRegularToUrlSafeBase64EncodedString;