/*
* @copyright
* Copyright © Microsoft Open Technologies, 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
*
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
* ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
* PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
*
* See the Apache License, Version 2.0 for the specific language
* governing permissions and limitations under the License.
*/
'use strict';
var _ = require('underscore');
var adalIdConstants = require('./constants').AdalIdParameters;
var fs = require('fs');
var os = require('os');
var url = require('url');
var ADAL_VERSION;
/**
* @namespace Util
* @private
*/
function loadAdalVersion() {
var packagePath = __dirname + '/../package.json';
var packageJson = JSON.parse(fs.readFileSync(packagePath));
ADAL_VERSION = packageJson.version;
}
function adalInit() {
loadAdalVersion();
}
/**
* @static
* @memberOf Util
* @param {string|int} statusCode An HTTP status code.
*/
function isHttpSuccess(statusCode) {
return statusCode >= 200 && statusCode < 300;
}
function addDefaultRequestHeaders (self, options) {
if (!options.headers) {
options.headers = {};
}
var headers = options.headers;
Eif (!headers['Accept-Charset']) {
headers['Accept-Charset'] = 'utf-8';
}
headers['client-request-id'] = self._callContext._logContext.correlationId;
headers['return-client-request-id'] = 'true';
// ADAL Id headers
headers[adalIdConstants.SKU] = adalIdConstants.NODE_SKU;
headers[adalIdConstants.VERSION] = ADAL_VERSION;
headers[adalIdConstants.OS] = os.platform();
headers[adalIdConstants.CPU] = os.arch();
}
/**
* Central place for housing default request options. This is a place holder
* for when SSL validation is implemented an all requests are subject to that
* policy.
* @static
* @memberOf Util
* @param {object} options A set of options that will be merged with teh default options
* These will override any default options.
* @returns {object} Returns the merged options.
*/
function createRequestOptions(self, options) {
var defaultOptions = {}; //{ strictSSL : true };
var mergedOptions = defaultOptions;
if (options) {
_.extend(mergedOptions, options);
}
Iif (self._callContext.options && self._callContext.options.http) {
_.extend(mergedOptions, self._callContext.options.http);
}
addDefaultRequestHeaders(self, mergedOptions);
return mergedOptions;
}
function logReturnCorrelationId(log, operationMessage, response) {
if (response && response.headers && response.headers['client-request-id']) {
log.info(operationMessage + 'Server returned this correlationId: ' + response.headers['client-request-id']);
}
}
/**
* Creates a function that can be used as the callback for http request operations. This is meant
* to centralize error handling in one place.
* @static
* @memberOf Util
* @param {string} operationMessage A message to be prepended to logged error strings. This should be something like 'Mex Request'
* and summarize the purpose of the http request.
* @param {object} log A Logger object being used by the calling component.
* @param {Util.CreateRequestHandlerErrorCallback} errorCallback Called in the event of an error.
* @param {Util.CreateRequestHandlerSuccessCallabck} successCallback Called on successfull completion of the request.
*/
function createRequestHandler(operationMessage, log, errorCallback, successCallback) {
return function(err, response, body) {
logReturnCorrelationId(log, operationMessage, response);
if (err) {
log.error(operationMessage + ' request failed with', err);
errorCallback(err);
return;
}
if (!isHttpSuccess(response.statusCode)) {
var returnErrorString = operationMessage + ' request returned http error: ' + response.statusCode;
var errorResponse;
if (body) {
returnErrorString += ' and server response: ' + body;
try {
errorResponse = JSON.parse(body);
} catch (e) {
// No problem if it doesn't parse.
}
}
errorCallback(log.createError(returnErrorString), errorResponse);
return;
}
successCallback(response, body);
};
}
/**
* @callback CreateRequestHandlerErrorCallback
* @memberOf Util
* @param {Error} error An error object.
*/
/**
* @callback CreateRequestHandlerSuccessCallabck
* @memberOf Util
* @param {object} response The response object returned from request.
* @param {string} body The body of the http response.
*/
/**
* Deep copies a url object.
* @static
* @memberOf Util
* @param {URL} urlSource The source url object to copy.
* @returns {URL} A deep copy of sourceUrl.
*/
function copyUrl(urlSource) {
return url.parse(url.format(urlSource));
}
function convertUrlSafeToRegularBase64EncodedString(str) {
return str.replace(/-/g, '+').replace(/_/g, '/');
}
function convertRegularToUrlSafeBase64EncodedString(str) {
return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
function base64DecodeStringUrlSafe(str) {
var base64 = convertUrlSafeToRegularBase64EncodedString(str);
return (new Buffer(base64, 'base64')).toString('utf8');
}
function base64EncodeStringUrlSafe(str) {
var base64 = (new Buffer(str, 'utf8').toString('base64'));
var converted = convertRegularToUrlSafeBase64EncodedString(base64);
return converted;
}
module.exports.adalInit = adalInit;
module.exports.isHttpSuccess = isHttpSuccess;
module.exports.createRequestHandler = createRequestHandler;
module.exports.createRequestOptions = createRequestOptions;
module.exports.copyUrl = copyUrl;
module.exports.base64DecodeStringUrlSafe = base64DecodeStringUrlSafe;
module.exports.base64EncodeStringUrlSafe = base64EncodeStringUrlSafe;
module.exports.convertRegularToUrlSafeBase64EncodedString = convertRegularToUrlSafeBase64EncodedString; |