azure-storage-legacy
Version:
Microsoft Azure Storage Client Library for node for back compat with older versions of node sdk
193 lines (162 loc) • 7.99 kB
JavaScript
//
// Copyright (c) Microsoft and contributors. 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.
//
// Module dependencies.
var qs = require('querystring');
var azureCommon = require('azure-common');
var azureutil = azureCommon.util;
var HmacSha256Sign = azureCommon.HmacSha256Sign;
var Constants = azureCommon.Constants;
var BlobConstants = Constants.BlobConstants;
var QueryStringConstants = Constants.QueryStringConstants;
var SAS_VERSION = '2012-02-12';
/**
* Creates a new SharedAccessSignature object.
*
* @constructor
* @param {string} storageAccount The storage account.
* @param {string} storageAccessKey The storage account's access key.
* @param {array} permissionSet An array of URL's for which there is a permission defined.
*/
function SharedAccessSignature(storageAccount, storageAccessKey, permissionSet) {
this.storageAccount = storageAccount;
this.storageAccessKey = storageAccessKey;
this.permissionSet = permissionSet;
this.signer = new HmacSha256Sign(storageAccessKey);
}
/**
* Generates the query string for a shared access signature signing.
*
* @this {SharedAccessSignature}
* @param {string} path The path to the resource.
* @parma {ResourceTypes} resourceType The resource type.
* @param {object} sharedAccessPolicy The shared access policy.
* @param {string} [sharedAccessPolicy.Id] The signed identifier.
* @param {SharedAccessPermissions} sharedAccessPolicy.AccessPolicy.Permissions The permission type.
* @param {date} [sharedAccessPolicy.AccessPolicy.Start] The time at which the Shared Access Signature becomes valid.
* @param {date} sharedAccessPolicy.AccessPolicy.Expiry The time at which the Shared Access Signature becomes expired.
* @return {object} The shared access signature query string.
*/
SharedAccessSignature.prototype.generateSignedQueryString = function (path, queryString, resourceType, sharedAccessPolicy) {
if (sharedAccessPolicy.AccessPolicy) {
if (sharedAccessPolicy.AccessPolicy.Start) {
queryString[QueryStringConstants.SIGNED_START] = sharedAccessPolicy.AccessPolicy.Start;
}
if (sharedAccessPolicy.AccessPolicy.Expiry) {
queryString[QueryStringConstants.SIGNED_EXPIRY] = sharedAccessPolicy.AccessPolicy.Expiry;
}
if (sharedAccessPolicy.AccessPolicy.Permissions) {
queryString[QueryStringConstants.SIGNED_PERMISSIONS] = sharedAccessPolicy.AccessPolicy.Permissions;
}
}
queryString[QueryStringConstants.SIGNED_RESOURCE] = resourceType;
if (sharedAccessPolicy.Id) {
queryString[QueryStringConstants.SIGNED_IDENTIFIER] = sharedAccessPolicy.Id;
}
queryString[QueryStringConstants.SIGNED_VERSION] = SAS_VERSION;
queryString[QueryStringConstants.SIGNATURE] = this._generateSignature(path, resourceType, sharedAccessPolicy);
return queryString;
};
/**
* Signs a request with the signature header.
*
* @this {SharedAccessSignature}
* @param {WebResource} The webresource to be signed.
* @param {function(error)} callback The callback function.
* @return {undefined}
*/
SharedAccessSignature.prototype.signRequest = function (webResource, callback) {
var self = this;
for (var permission in this.permissionSet) {
if (this.permissionSet.hasOwnProperty(permission)) {
var sharedAccessSignature = this.permissionSet[permission];
if (self._permissionMatchesRequest(sharedAccessSignature, webResource,
webResource.properties[BlobConstants.ResourceTypeProperty],
webResource.properties[BlobConstants.SharedAccessPermissionProperty])) {
if (webResource.uri.indexOf('?') === -1) {
webResource.uri += '?';
} else {
webResource.uri += '&';
}
webResource.uri += qs.stringify(sharedAccessSignature.queryString);
break;
}
}
}
callback(null);
};
/**
* Generates the shared access signature for a resource.
*
* @this {SharedAccessSignature}
* @param {string} path The path to the resource.
* @parma {ResourceTypes} resourceType The resource type.
* @param {object} sharedAccessPolicy The shared access policy.
* @param {string} [sharedAccessPolicy.Id] The signed identifier.
* @param {SharedAccessPermissions} sharedAccessPolicy.AccessPolicy.Permissions The permission type.
* @param {date} [sharedAccessPolicy.AccessPolicy.Start] The time at which the Shared Access Signature becomes valid.
* @param {date} sharedAccessPolicy.AccessPolicy.Expiry The time at which the Shared Access Signature becomes expired.
* @return {string} The shared access signature.
*/
SharedAccessSignature.prototype._generateSignature = function (path, resourceType, sharedAccessPolicy) {
var getvalueToAppend = function (value, noNewLine) {
var returnValue = '';
if (!azureutil.objectIsNull(value)) {
returnValue = value;
}
if (noNewLine !== true) {
returnValue += '\n';
}
return returnValue;
};
// Add leading slash to path
if (path.substr(0, 1) !== '/') {
path = '/' + path;
}
var canonicalizedResource = '/' + this.storageAccount + path;
var stringToSign =
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Permissions : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Start : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Expiry : '') +
getvalueToAppend(canonicalizedResource) +
getvalueToAppend(sharedAccessPolicy.Id) +
SAS_VERSION;
return this.signer.sign(stringToSign);
};
/**
* Generates the query string for a shared access signature signing.
*
* @this {SharedAccessSignature}
* @param {object} sharedAccessSignature The shared access signature object.
* @parma {WebResource} webResource The web resource.
* @parma {ResourceTypes} resourceType The resource type.
* @param {SharedAccessPermissions} requiredPermission The time at which the Shared Access Signature becomes valid.
* @return {bool} true if the request matches the permission set; false otherwise.
*/
SharedAccessSignature.prototype._permissionMatchesRequest = function (sharedAccessSignature, webResource, resourceType, requiredPermission) {
var requiredResourceType = resourceType;
if (requiredResourceType === BlobConstants.ResourceTypes.BLOB) {
requiredResourceType += BlobConstants.ResourceTypes.CONTAINER;
}
for (var property in sharedAccessSignature.queryString) {
if (property === QueryStringConstants.SIGNED_RESOURCE && requiredResourceType.indexOf(sharedAccessSignature.queryString[property]) === -1) {
return false;
} else if (property === QueryStringConstants.SIGNED_PERMISSIONS && requiredPermission.indexOf(sharedAccessSignature.queryString[property]) === -1) {
return false;
}
}
return webResource.path.indexOf(sharedAccessSignature.path) !== -1;
};
module.exports = SharedAccessSignature;