UNPKG

pkgcloud

Version:

An infrastructure-as-a-service agnostic cloud library for node.js

112 lines (88 loc) 3.19 kB
/* * aws-signature.js: Implmentation of authentication for Amazon AWS APIs. * * (C) 2012 Nodejitsu Inc. * */ var url = require('url'), qs = require('querystring'), crypto = require('crypto'), Buffer = require('buffer').Buffer; exports.signBody = function signBody(req, options) { if (!options) options = {}; if (typeof options.key !== 'string') { throw new TypeError('`key` is a required argument for aws-signature'); } if (typeof options.keyId !== 'string') { throw new TypeError('`keyId` is a required argument for aws-signature'); } var signatureString = [ req.method, '\n', this.serversUrl, '\n', '/', '\n' ], query = req.body; query.AWSAccessKeyId = options.keyId; query.SignatureMethod = 'HmacSHA256'; query.SignatureVersion = 2; query.Version = this.version; query.Timestamp = new Date(+new Date + 36e5 * 30).toISOString(); Object.keys(query).sort().forEach(function (key, i) { if (i !== 0) signatureString.push('&'); signatureString.push(encodeURIComponent(key), '=', encodeURIComponent(query[key])); }); var toSign = signatureString.join(''); // Crappy code, but AWS seems to need it toSign = toSign.replace(/!/g, '%21'); toSign = toSign.replace(/'/g, '%27'); toSign = toSign.replace(/\*/g, '%2A'); toSign = toSign.replace(/\(/g, '%28'); toSign = toSign.replace(/\)/g, '%29'); query.Signature = crypto.createHmac( 'sha256', options.key ).update(toSign).digest('base64'); req.path.push('?Action=' + query.Action); delete query.Action; req.body = Object.keys(query).sort().map(function (key) { return encodeURIComponent(key) + '=' + encodeURIComponent(query[key]); }).join('&'); req.headers['Content-Type'] = 'application/x-www-form-urlencoded'; req.headers['Content-Length'] = Buffer.byteLength(req.body); }; exports.signHeaders = function signHeaders(req, options) { if (!options) options = {}; if (typeof options.key !== 'string') { throw new TypeError('`key` is a required argument for aws-signature'); } if (typeof options.keyId !== 'string') { throw new TypeError('`keyId` is a required argument for aws-signature'); } req.headers = req.headers || {}; // Lower-case keys in headers hashmap var headers = {}; Object.keys(req.headers).forEach(function (key) { headers[key.toLowerCase()] = req.headers[key]; }); var now = new Date(), signatureString = [ req.method || 'GET', '\n', headers['content-md5'] || '', '\n', headers['content-type'] || '', '\n', now.toUTCString(), '\n' ]; // Push amz headers to signature string Object.keys(headers).forEach(function (key) { if (/^x-amz/.test(key)) { signatureString.push(key, ':', headers[value], '\n'); } }); signatureString.push('/' + req.path.join('/')); if (req.path.length === 1 && req.path[0] !== '') signatureString.push('/'); var signature = crypto.createHmac( 'sha1', options.key ).update(signatureString.join('')).digest('base64'); req.headers.Date = now.toUTCString(); req.headers.Authorization = 'AWS ' + options.keyId + ':' + signature; };