@yawetse/pkgcloud
Version:
An infrastructure-as-a-service agnostic cloud library for node.js
158 lines (135 loc) • 5.5 kB
JavaScript
/**
* Copyright (c) Microsoft. 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* derived from azure-sdk-for-node/lib/services/blob/sharedkey.js
*
* Modified to sign an Azure request using node request parameters instead of a WebResource
*/
// Module dependencies.
var HeaderConstants = require('./constants').HeaderConstants;
var HmacSha256Sign = require('./hmacsha256sign');
/**
* Creates a new SharedKey object.
*
* @constructor
* @param {string} storageAccount The storage account.
* @param {string} storageAccessKey The storage account's access key.
*/
function SharedKey(storageAccount, storageAccessKey) {
this.storageAccount = storageAccount;
this.storageAccessKey = storageAccessKey;
this.signer = new HmacSha256Sign(storageAccessKey);
}
var getvalueToAppend = function (value) {
return value ? value + '\n' : '\n';
};
/**
* Signs a request with the Authentication header.
*
* @param {req} The request request object.
* @return {undefined}
*/
SharedKey.prototype.signRequest = function (req) {
var httpVerb = req.method || 'GET';
req.headers = req.headers || {};
req.headers['x-ms-date'] = new Date().toUTCString();
req.headers['x-ms-version'] = HeaderConstants.TARGET_STORAGE_VERSION;
if (!req.headers[HeaderConstants.CONTENT_LENGTH]) {
req.headers[HeaderConstants.CONTENT_LENGTH] = '0';
}
var stringToSign =
httpVerb + '\n' +
getvalueToAppend(req.headers[HeaderConstants.CONTENT_ENCODING]) +
getvalueToAppend(req.headers[HeaderConstants.CONTENT_LANGUAGE]) +
getvalueToAppend(req.headers[HeaderConstants.CONTENT_LENGTH]) +
getvalueToAppend(req.headers[HeaderConstants.CONTENT_MD5]) +
getvalueToAppend(req.headers[HeaderConstants.CONTENT_TYPE]) +
getvalueToAppend(req.headers[HeaderConstants.DATE]) +
getvalueToAppend(req.headers[HeaderConstants.IF_MODIFIED_SINCE]) +
getvalueToAppend(req.headers[HeaderConstants.IF_MATCH]) +
getvalueToAppend(req.headers[HeaderConstants.IF_NONE_MATCH]) +
getvalueToAppend(req.headers[HeaderConstants.IF_UNMODIFIED_SINCE]) +
getvalueToAppend(req.headers[HeaderConstants.RANGE]) +
this._getCanonicalizedHeaders(req) +
this._getCanonicalizedResource(req);
var signature = this.signer.sign(stringToSign);
req.headers[HeaderConstants.AUTHORIZATION] = 'SharedKey ' + this.storageAccount + ':' + signature;
};
/*
* Retrieves the requests's canonicalized resource string.
* @param {req} request The request to get the canonicalized resource string from.
* @return {string} The canonicalized resource string.
*/
SharedKey.prototype._getCanonicalizedResource = function (req) {
var path = '/';
if (req.path) {
path = '/' + req.path;
}
var canonicalizedResource = '/' + this.storageAccount;
if (path) {
canonicalizedResource += path;
}
// Get the raw query string values for signing
if (req.qs) {
var queryStringValues = req.qs;
// Build the canonicalized resource by sorting the values by name.
if (queryStringValues) {
var paramNames = [];
for (var n in queryStringValues) {
paramNames.push(n);
}
paramNames = paramNames.sort();
for (var name in paramNames) {
canonicalizedResource += '\n' + paramNames[name] + ':' + queryStringValues[paramNames[name]];
}
}
}
return canonicalizedResource;
};
/*
* Constructs the Canonicalized Headers string.
*
* To construct the CanonicalizedHeaders portion of the signature string,
* follow these steps: 1. Retrieve all headers for the resource that begin
* with x-ms-, including the x-ms-date header. 2. Convert each HTTP header
* name to lowercase. 3. Sort the headers lexicographically by header name,
* in ascending order. Each header may appear only once in the
* string. 4. Unfold the string by replacing any breaking white space with a
* single space. 5. Trim any white space around the colon in the header. 6.
* Finally, append a new line character to each canonicalized header in the
* resulting list. Construct the CanonicalizedHeaders string by
* concatenating all headers in this list into a single string.
*
* @param {object} The request object.
* @return {string} The canonicalized headers.
*/
SharedKey.prototype._getCanonicalizedHeaders = function (req) {
// Build canonicalized headers
var canonicalizedHeaders = '';
if (req.headers) {
var canonicalizedHeadersArray = [];
for (var header in req.headers) {
if (header.indexOf(HeaderConstants.PREFIX_FOR_STORAGE_HEADER) === 0) {
canonicalizedHeadersArray.push(header);
}
}
canonicalizedHeadersArray.sort();
for (var headerName in canonicalizedHeadersArray) {
canonicalizedHeaders += canonicalizedHeadersArray[headerName].toLowerCase() + ':' + req.headers[canonicalizedHeadersArray[headerName]] + '\n';
}
}
return canonicalizedHeaders;
};
// Expose 'SharedKey'.
exports = module.exports = SharedKey;