azure-storage
Version:
Microsoft Azure Storage Client Library for Node.js
500 lines (436 loc) • 28.4 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 _ = require('underscore');
var qs = require('querystring');
var azureutil = require('../util/util');
var HmacSha256Sign = require('./hmacsha256sign');
var SR = require('../util/sr');
var errors = require('../errors/errors');
var ArgumentError = errors.ArgumentError;
var Constants = require('../util/constants');
var HeaderConstants = Constants.HeaderConstants;
var QueryStringConstants = Constants.QueryStringConstants;
var HeaderConstants = Constants.HeaderConstants;
var CompatibleVersionConstants = Constants.CompatibleVersionConstants;
/**
* Creates a new SharedKey object.
*
* @constructor
* @param {string} storageAccount The storage account.
* @param {string} storageAccessKey The storage account's access key.
* @param {bool} usePathStyleUri Boolean value indicating if the path, or the hostname, should include the storage account.
*/
function SharedKey(storageAccount, storageAccessKey, usePathStyleUri) {
this.storageAccount = storageAccount;
this.storageAccessKey = storageAccessKey;
this.usePathStyleUri = usePathStyleUri;
this.signer = new HmacSha256Sign(storageAccessKey);
}
/**
* Generates the shared access signature for a account.
* For more detailed information, refer to https://msdn.microsoft.com/en-us/library/azure/mt584140.aspx
*
* @param {object} sharedAccessPolicy The shared access policy.
* @param {SharedAccessServices} sharedAccessPolicy.AccessPolicy.Services The services (blob, file, queue, table) for a shared access signature associated with this shared access policy.
* Refer to `Constants.AccountSasConstants.Services`.
* @param {SharedAccessResourceTypes} sharedAccessPolicy.AccessPolicy.ResourceTypes The resource type for a shared access signature associated with this shared access policy.
* Refer to `Constants.AccountSasConstants.ResourceTypes`.
* @param {SharedAccessPermissions} sharedAccessPolicy.AccessPolicy.Permissions The permissions for a shared access signature.
* Refer to `Constants.AccountSasConstants.Permissions`.
* @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.
* @param {string} sharedAccessPolicy.AccessPolicy.IPAddressOrRange An IP address or a range of IP addresses from which to accept requests. When specifying a range, note that the range is inclusive.
* @param {string} sharedAccessPolicy.AccessPolicy.Protocols The protocols permitted for a request made with the account SAS.
* Possible values are both HTTPS and HTTP (https,http) or HTTPS only (https). The default value is https,http.
* Refer to `Constants.AccountSasConstants.Protocols`.
* @return {string} The shared access signature.
*/
SharedKey.prototype.generateAccountSignedQueryString = function (sharedAccessPolicy) {
var addIfNotNull = function (queryString, name, value) {
if (!azureutil.objectIsNull(name) && !azureutil.objectIsNull(value)) {
queryString[name] = value;
}
};
var formatAccessPolicyDates = function (accessPolicy) {
if (!azureutil.objectIsNull(accessPolicy.Start)) {
if (!_.isDate(accessPolicy.Start)) {
accessPolicy.Start = new Date(accessPolicy.Start);
}
accessPolicy.Start = azureutil.truncatedISO8061Date(accessPolicy.Start);
}
if (!azureutil.objectIsNull(accessPolicy.Expiry)) {
if (!_.isDate(accessPolicy.Expiry)) {
accessPolicy.Expiry = new Date(accessPolicy.Expiry);
}
accessPolicy.Expiry = azureutil.truncatedISO8061Date(accessPolicy.Expiry);
}
};
var queryString = {};
addIfNotNull(queryString, QueryStringConstants.SIGNED_VERSION, HeaderConstants.TARGET_STORAGE_VERSION);
// add shared access policy params
if (sharedAccessPolicy.AccessPolicy) {
formatAccessPolicyDates(sharedAccessPolicy.AccessPolicy);
addIfNotNull(queryString, QueryStringConstants.SIGNED_SERVICES, sharedAccessPolicy.AccessPolicy.Services);
addIfNotNull(queryString, QueryStringConstants.SIGNED_RESOURCE_TYPES, sharedAccessPolicy.AccessPolicy.ResourceTypes);
addIfNotNull(queryString, QueryStringConstants.SIGNED_PERMISSIONS, sharedAccessPolicy.AccessPolicy.Permissions);
addIfNotNull(queryString, QueryStringConstants.SIGNED_START, sharedAccessPolicy.AccessPolicy.Start);
addIfNotNull(queryString, QueryStringConstants.SIGNED_EXPIRY, sharedAccessPolicy.AccessPolicy.Expiry);
addIfNotNull(queryString, QueryStringConstants.SIGNED_IP, sharedAccessPolicy.AccessPolicy.IPAddressOrRange);
addIfNotNull(queryString, QueryStringConstants.SIGNED_PROTOCOL, sharedAccessPolicy.AccessPolicy.Protocols);
}
// add signature
addIfNotNull(queryString, QueryStringConstants.SIGNATURE, this._generateAccountSharedAccessSignature(sharedAccessPolicy));
return qs.stringify(queryString);
};
/**
* Generates the signature part of the shared access signature for a account.
* For more detailed information, refer to https://msdn.microsoft.com/en-us/library/azure/mt584140.aspx
*
* @param {object} sharedAccessPolicy The shared access policy.
* @param {SharedAccessServices} sharedAccessPolicy.AccessPolicy.Services The services (blob, file, queue, table) for a shared access signature associated with this shared access policy.
* Refer to `Constants.AccountSasConstants.Services`.
* @param {SharedAccessResourceTypes} sharedAccessPolicy.AccessPolicy.ResourceTypes The resource type for a shared access signature associated with this shared access policy.
* Refer to `Constants.AccountSasConstants.ResourceTypes`.
* @param {SharedAccessPermissions} sharedAccessPolicy.AccessPolicy.Permissions The permissions for a shared access signature.
* Refer to `Constants.AccountSasConstants.Permissions`.
* @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.
* @param {string} sharedAccessPolicy.AccessPolicy.IPAddressOrRange An IP address or a range of IP addresses from which to accept requests. When specifying a range, note that the range is inclusive.
* @param {string} sharedAccessPolicy.AccessPolicy.Protocols The protocols permitted for a request made with the account SAS.
* Possible values are both HTTPS and HTTP (https,http) or HTTPS only (https). The default value is https,http.
* Refer to `Constants.AccountSasConstants.Protocols`.
* @return {string} The signature part of the shared access signature.
*/
SharedKey.prototype._generateAccountSharedAccessSignature = function(sharedAccessPolicy){
var getvalueToAppend = function (value, noNewLine) {
var returnValue = '';
if (!azureutil.objectIsNull(value)) {
returnValue = value;
}
if (noNewLine !== true) {
returnValue += '\n';
}
return returnValue;
};
var stringToSign = getvalueToAppend(this.storageAccount) +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Permissions : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Services : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.ResourceTypes : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Start : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Expiry : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.IPAddressOrRange : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Protocols : '') +
getvalueToAppend(HeaderConstants.TARGET_STORAGE_VERSION);
return this.signer.sign(stringToSign);
};
/**
* Signs a request with the Authentication header.
*
* @param {WebResource} The webresource to be signed.
* @param {function(error)} callback The callback function.
*/
SharedKey.prototype.signRequest = function (webResource, callback) {
var getvalueToAppend = function (value, headerName) {
// Do not sign content-length 0 in 2014-08-16 and later
if (headerName === HeaderConstants.CONTENT_LENGTH && (azureutil.objectIsNull(value[headerName]) || value[headerName].toString() === '0')) {
return '\n';
} else if (azureutil.objectIsNull(value) || azureutil.objectIsNull(value[headerName])) {
return '\n';
} else {
return value[headerName] + '\n';
}
};
var stringToSign =
webResource.method + '\n' +
getvalueToAppend(webResource.headers, HeaderConstants.CONTENT_ENCODING) +
getvalueToAppend(webResource.headers, HeaderConstants.CONTENT_LANGUAGE) +
getvalueToAppend(webResource.headers, HeaderConstants.CONTENT_LENGTH) +
getvalueToAppend(webResource.headers, HeaderConstants.CONTENT_MD5) +
getvalueToAppend(webResource.headers, HeaderConstants.CONTENT_TYPE) +
getvalueToAppend(webResource.headers, HeaderConstants.DATE) +
getvalueToAppend(webResource.headers, HeaderConstants.IF_MODIFIED_SINCE) +
getvalueToAppend(webResource.headers, HeaderConstants.IF_MATCH) +
getvalueToAppend(webResource.headers, HeaderConstants.IF_NONE_MATCH) +
getvalueToAppend(webResource.headers, HeaderConstants.IF_UNMODIFIED_SINCE) +
getvalueToAppend(webResource.headers, HeaderConstants.RANGE) +
this._getCanonicalizedHeaders(webResource) +
this._getCanonicalizedResource(webResource);
var signature = this.signer.sign(stringToSign);
webResource.withHeader(HeaderConstants.AUTHORIZATION, 'SharedKey ' + this.storageAccount + ':' + signature);
callback(null);
};
/*
* Retrieves the webresource's canonicalized resource string.
* @param {WebResource} webResource The webresource to get the canonicalized resource string from.
* @return {string} The canonicalized resource string.
*/
SharedKey.prototype._getCanonicalizedResource = function (webResource) {
var path = '/';
if (webResource.path) {
path = webResource.path;
}
var canonicalizedResource = '/' + this.storageAccount + path;
// Get the raw query string values for signing
var queryStringValues = webResource.queryString;
// Build the canonicalized resource by sorting the values by name.
if (queryStringValues) {
var paramNames = [];
Object.keys(queryStringValues).forEach(function (n) {
paramNames.push(n);
});
paramNames = paramNames.sort();
Object.keys(paramNames).forEach(function (name) {
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 webresource object.
* @return {string} The canonicalized headers.
*/
SharedKey.prototype._getCanonicalizedHeaders = function (webResource) {
// Build canonicalized headers
var canonicalizedHeaders = '';
if (webResource.headers) {
var canonicalizedHeadersArray = [];
for (var header in webResource.headers) {
if (header.indexOf(HeaderConstants.PREFIX_FOR_STORAGE) === 0) {
var headerItem = { canonicalized: header.toLowerCase(), original: header };
canonicalizedHeadersArray.push(headerItem);
}
}
canonicalizedHeadersArray.sort(function(a, b) { return a.canonicalized.localeCompare(b.canonicalized); });
_.each(canonicalizedHeadersArray, function (currentHeaderItem) {
var value = webResource.headers[currentHeaderItem.original];
if (!azureutil.IsNullOrEmptyOrUndefinedOrWhiteSpace(value)) {
canonicalizedHeaders += currentHeaderItem.canonicalized + ':' + value + '\n';
} else {
canonicalizedHeaders += currentHeaderItem.canonicalized + ':\n';
}
});
}
return canonicalizedHeaders;
};
/**
* Generates the query string for a shared access signature signing.
*
* @this {SharedAccessSignature}
* @param {string} serviceType The service type.
* @param {string} path The path to the resource.
* @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.
* @param {string} [sharedAccessPolicy.AccessPolicy.IPAddressOrRange] An IP address or a range of IP addresses from which to accept requests. When specifying a range, note that the range is inclusive.
* @param {string} [sharedAccessPolicy.AccessPolicy.Protocols] The protocols permitted for a request made with the account SAS.
* Possible values are both HTTPS and HTTP (https,http) or HTTPS only (https). The default value is https,http.
* @param {string} sasVersion A string indicating the desired SAS Version to use, in storage service version format. Value must be 2012-02-12 or later.
* @parma {ResourceTypes} [args.resourceType] The resource type, if the resource is a blob or container. Null if the resource is a queue or table.
* @parma {ResourceTypes} [args.tableName] The table name, if the resource is a table. Null if the resource is a blob orqueue.
* @parma {ResourceTypes} [args.queryString] The query string, if additional parameters are desired.
* @param {object} [args.headers] The optional header values to set for a blob returned wth this SAS.
* @param {string} [args.headers.CacheControl] The value of the Cache-Control response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentType] The value of the Content-Type response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentEncoding] The value of the Content-Encoding response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentLanguage] The value of the Content-Language response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentDisposition] The value of the Content-Disposition response header to be returned when this SAS is used.
* @return {object} The shared access signature query string.
*/
SharedKey.prototype.generateSignedQueryString = function (serviceType, path, sharedAccessPolicy, sasVersion, args) {
var addIfNotNull = function (queryString, name, value) {
if (!azureutil.objectIsNull(name) && !azureutil.objectIsNull(value)) {
queryString[name] = value;
}
};
var validateVersion = function (sasVersion) {
// validate and add version
if (azureutil.objectIsNull(sasVersion)) {
return HeaderConstants.TARGET_STORAGE_VERSION;
} else {
var values = _.values(CompatibleVersionConstants);
if (values.some(function(version) {
return version.toLowerCase() === sasVersion.toLowerCase();
})) {
return sasVersion;
} else {
throw new ArgumentError('sasVersion', azureutil.stringFormat(SR.INVALID_SAS_VERSION, sasVersion, values));
}
}
};
var formatAccessPolicyDates = function (accessPolicy) {
if (!azureutil.objectIsNull(accessPolicy.Start)) {
if (!_.isDate(accessPolicy.Start)) {
accessPolicy.Start = new Date(accessPolicy.Start);
}
accessPolicy.Start = azureutil.truncatedISO8061Date(accessPolicy.Start);
}
if (!azureutil.objectIsNull(accessPolicy.Expiry)) {
if (!_.isDate(accessPolicy.Expiry)) {
accessPolicy.Expiry = new Date(accessPolicy.Expiry);
}
accessPolicy.Expiry = azureutil.truncatedISO8061Date(accessPolicy.Expiry);
}
};
// set up optional args
var queryString;
var resourceType;
var headers;
var tableName;
if(args) {
queryString = args.queryString;
resourceType = args.resourceType;
tableName = args.tableName;
headers = args.headers;
}
if(!queryString) {
queryString = {};
}
// add shared access policy params
if (sharedAccessPolicy.AccessPolicy) {
formatAccessPolicyDates(sharedAccessPolicy.AccessPolicy);
addIfNotNull(queryString, QueryStringConstants.SIGNED_START, sharedAccessPolicy.AccessPolicy.Start);
addIfNotNull(queryString, QueryStringConstants.SIGNED_EXPIRY, sharedAccessPolicy.AccessPolicy.Expiry);
addIfNotNull(queryString, QueryStringConstants.SIGNED_PERMISSIONS, sharedAccessPolicy.AccessPolicy.Permissions);
addIfNotNull(queryString, QueryStringConstants.SIGNED_IP, sharedAccessPolicy.AccessPolicy.IPAddressOrRange);
addIfNotNull(queryString, QueryStringConstants.SIGNED_PROTOCOL, sharedAccessPolicy.AccessPolicy.Protocols);
// tables only
addIfNotNull(queryString, QueryStringConstants.STARTPK, sharedAccessPolicy.AccessPolicy.StartPk);
addIfNotNull(queryString, QueryStringConstants.ENDPK, sharedAccessPolicy.AccessPolicy.EndPk);
addIfNotNull(queryString, QueryStringConstants.STARTRK, sharedAccessPolicy.AccessPolicy.StartRk);
addIfNotNull(queryString, QueryStringConstants.ENDRK, sharedAccessPolicy.AccessPolicy.EndRk);
}
// validate and add version
var validatedSASVersionString = validateVersion(sasVersion);
addIfNotNull(queryString, QueryStringConstants.SIGNED_VERSION, validatedSASVersionString);
// add signed identifier
addIfNotNull(queryString, QueryStringConstants.SIGNED_IDENTIFIER, sharedAccessPolicy.Id);
// blobs only
addIfNotNull(queryString, QueryStringConstants.SIGNED_RESOURCE, resourceType);
if (headers) {
addIfNotNull(queryString, QueryStringConstants.CACHE_CONTROL, headers.cacheControl);
addIfNotNull(queryString, QueryStringConstants.CONTENT_TYPE, headers.contentType);
addIfNotNull(queryString, QueryStringConstants.CONTENT_ENCODING, headers.contentEncoding);
addIfNotNull(queryString, QueryStringConstants.CONTENT_LANGUAGE, headers.contentLanguage);
addIfNotNull(queryString, QueryStringConstants.CONTENT_DISPOSITION, headers.contentDisposition);
}
// tables only
addIfNotNull(queryString, QueryStringConstants.TABLENAME, tableName);
// add signature
addIfNotNull(queryString, QueryStringConstants.SIGNATURE, this._generateSignature(serviceType, path, sharedAccessPolicy, validatedSASVersionString, {resourceType: resourceType, headers: headers, tableName: tableName}));
return qs.stringify(queryString);
};
/**
* Generates the shared access signature for a resource.
*
* @this {SharedAccessSignature}
* @param {string} serviceType The service type.
* @param {string} path The path to the resource.
* @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.
* @param {string} [sharedAccessPolicy.AccessPolicy.IPAddressOrRange] An IP address or a range of IP addresses from which to accept requests. When specifying a range, note that the range is inclusive.
* @param {string} [sharedAccessPolicy.AccessPolicy.Protocols] The protocols permitted for a request made with the account SAS.
* Possible values are both HTTPS and HTTP (https,http) or HTTPS only (https). The default value is https,http.
* @param {string} sasVersion A string indicating the desired SAS Version to use, in storage service version format. Value must be 2012-02-12 or later.
* @parma {ResourceTypes} [args.resourceType] The resource type, if the resource is a blob or container. Null if the resource is a queue or table.
* @parma {ResourceTypes} [args.tableName] The table name, if the resource is a table. Null if the resource is a blob or queue.
* @param {object} [args.headers] The optional header values to set for a blob returned wth this SAS.
* @param {string} [args.headers.CacheControl] The value of the Cache-Control response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentType] The value of the Content-Type response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentEncoding] The value of the Content-Encoding response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentLanguage] The value of the Content-Language response header to be returned when this SAS is used.
* @param {string} [args.headers.ContentDisposition] The value of the Content-Disposition response header to be returned when this SAS is used.
* @return {string} The shared access signature.
*/
SharedKey.prototype._generateSignature = function (serviceType, path, sharedAccessPolicy, sasVersion, args) {
var getvalueToAppend = function (value, noNewLine) {
var returnValue = '';
if (!azureutil.objectIsNull(value)) {
returnValue = value;
}
if (noNewLine !== true) {
returnValue += '\n';
}
return returnValue;
};
// set up optional args
var resourceType;
var tableName;
var headers;
if(args) {
resourceType = args.resourceType;
tableName = args.tableName;
headers = args.headers;
}
// Add leading slash to path
if (path.substr(0, 1) !== '/') {
path = '/' + path;
}
var canonicalizedResource;
if (sasVersion === CompatibleVersionConstants.FEBRUARY_2012 || sasVersion === CompatibleVersionConstants.AUGUST_2013) {
// Do not prepend service name for older versions
canonicalizedResource = '/' + this.storageAccount + path;
} else {
canonicalizedResource = '/' + serviceType + '/' + 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) +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.IPAddressOrRange : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.Protocols : '') +
sasVersion;
if(sasVersion == CompatibleVersionConstants.FEBRUARY_2012) {
if(headers) {
throw new ArgumentError('args.headers', SR.INVALID_HEADERS);
}
} else if (resourceType) {
stringToSign += '\n' +
getvalueToAppend(headers ? headers.cacheControl : '') +
getvalueToAppend(headers ? headers.contentDisposition : '') +
getvalueToAppend(headers ? headers.contentEncoding : '') +
getvalueToAppend(headers ? headers.contentLanguage : '') +
getvalueToAppend(headers ? headers.contentType : '', true);
}
if(tableName) {
stringToSign += '\n' +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.StartPk : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.StartRk : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.EndPk : '') +
getvalueToAppend(sharedAccessPolicy.AccessPolicy ? sharedAccessPolicy.AccessPolicy.EndRk : '', true);
}
return this.signer.sign(stringToSign);
};
module.exports = SharedKey;