akamai-edgegrid
Version:
Authentication handler for the Akamai OPEN EdgeGrid Authentication scheme in Node.js
165 lines (146 loc) • 5.86 kB
JavaScript
const axios = require('axios'),
auth = require('./auth'),
edgerc = require('./edgerc'),
helpers = require('./helpers'),
logger = require('./logger');
/**
*
* @param {String} client_token The client token value from the .edgerc file.
* @param {String} client_secret The client secret value from the .edgerc file.
* @param {String} access_token The access token value from the .edgerc file.
* @param {String} host The host a unique string followed by luna.akamaiapis.net from the .edgerc file.
* @param {Boolean} debug The debug value allows to enable debugging.
* @param {Number} max_body This value is deprecated.
* @constructor
* @deprecated max_body
*/
const EdgeGrid = function (client_token, client_secret, access_token, host, debug, max_body) {
// accepting an object containing a path to .edgerc and a config section
if (typeof arguments[0] === 'object') {
let edgercPath = arguments[0];
this._setConfigFromObj(edgercPath);
} else {
this._setConfigFromStrings(client_token, client_secret, access_token, host);
}
if (process.env.EG_VERBOSE || debug || (typeof arguments[0] === 'object' && arguments[0].debug)) {
axios.interceptors.request.use(request => {
console.log('Starting Request', request);
return request;
});
axios.interceptors.response.use(response => {
console.log('Response:', response);
return response;
});
}
};
/**
* Builds the request using the properties of the local config Object.
*
* @param {Object} req The request Object. Can optionally contain a
* 'headersToSign' property: An ordered list header names
* that will be included in the signature. This will be
* provided by specific APIs.
* @return EdgeGrid object (self)
*/
EdgeGrid.prototype.auth = function (req) {
req = helpers.extend(req, {
baseURL: this.config.host,
url: req.path,
method: 'GET',
headers: {},
maxRedirects: 0
});
req.headers = helpers.extendHeaders(req.headers);
let isTarball = req.body instanceof Uint8Array &&
(req.headers['Content-Type'] === 'application/gzip' || req.headers['Content-Type'] === 'application/tar+gzip');
// Convert body object to properly formatted string
if (req.body) {
if (typeof (req.body) == 'object' && !isTarball) {
req.body = JSON.stringify(req.body);
}
}
// this assignment is done in order to assert backwards compatibility of this library - a `body` field is accepted in this library, whereas axios expects the request body to be in `data` field
req.data = req.body;
this.request = auth.generateAuth(
req,
this.config.client_token,
this.config.client_secret,
this.config.access_token,
this.config.host,
helpers.MAX_BODY
);
if (req.headers['Accept'] === 'application/gzip' || req.headers['Accept'] === 'application/tar+gzip') {
this.request["responseType"] = 'arraybuffer';
}
return this;
};
/**
* Sends the request and invokes the callback function.
*
* @param {Function} callback The callback function.
* @return EdgeGrid object (self)
*/
EdgeGrid.prototype.send = function (callback) {
axios(this.request).then(response => {
callback(null, response, JSON.stringify(response.data));
}).catch(error => {
// handling redirects has to be handled in catch (with maxRedirects set to 0) because axios does not allow modifying headers between redirects
if (error.response && helpers.isRedirect(error.response.status)) {
this._handleRedirect(error.response, callback);
return;
}
callback(error);
});
return this;
};
EdgeGrid.prototype._handleRedirect = function (resp, callback) {
const parsedUrl = new URL(resp.headers['location']);
resp.headers['authorization'] = undefined;
this.request.url = undefined;
this.request.path = parsedUrl.pathname + parsedUrl.search;
this.auth(this.request);
this.send(callback);
};
/**
* Creates a config object from a set of parameters.
*
* @param {String} client_token The client token value from the .edgerc file.
* @param {String} client_secret The client secret value from the .edgerc file.
* @param {String} access_token The access token value from the .edgerc file.
* @param {String} host The host a unique string followed by luna.akamaiapis.net from the .edgerc file.
*/
EdgeGrid.prototype._setConfigFromStrings = function (client_token, client_secret, access_token, host) {
if (!validatedArgs([client_token, client_secret, access_token, host])) {
throw new Error('Insufficient Akamai credentials');
}
this.config = {
client_token: client_token,
client_secret: client_secret,
access_token: access_token,
host: host.indexOf('https://') > -1 ? host : 'https://' + host,
max_body: helpers.MAX_BODY
};
};
function validatedArgs(args) {
const expected = [
'client_token', 'client_secret', 'access_token', 'host'
];
let valid = true;
expected.forEach(function (arg, i) {
if (!args[i]) {
logger.error('No defined ' + arg);
valid = false;
}
});
return valid;
}
/**
* Creates a config Object from the section of a defined .edgerc file.
*
* @param {Object} obj An Object containing a path and section property that
* define the .edgerc section to use to create the Object.
*/
EdgeGrid.prototype._setConfigFromObj = function (obj) {
this.config = edgerc(obj.path, obj.section);
};
module.exports = EdgeGrid;