@azure/storage-queue
Version:
Microsoft Azure Storage SDK for JavaScript - Queue
1,358 lines (1,332 loc) • 224 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var coreRestPipeline = require('@azure/core-rest-pipeline');
var crypto = require('crypto');
var coreUtil = require('@azure/core-util');
var tslib = require('tslib');
var coreHttpCompat = require('@azure/core-http-compat');
var coreClient = require('@azure/core-client');
var coreXml = require('@azure/core-xml');
var coreAuth = require('@azure/core-auth');
var logger$2 = require('@azure/logger');
var abortController = require('@azure/abort-controller');
var coreTracing = require('@azure/core-tracing');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var coreHttpCompat__namespace = /*#__PURE__*/_interopNamespaceDefault(coreHttpCompat);
var coreClient__namespace = /*#__PURE__*/_interopNamespaceDefault(coreClient);
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* ONLY AVAILABLE IN NODE.JS RUNTIME.
*
* This is a helper class to construct a string representing the permissions granted by an AccountSAS. Setting a value
* to true means that any SAS which uses these permissions will grant permissions for that operation. Once all the
* values are set, this should be serialized with toString and set as the permissions field on an
* {@link AccountSASSignatureValues} object. It is possible to construct the permissions string without this class, but
* the order of the permissions is particular and this class guarantees correctness.
*/
class AccountSASPermissions {
constructor() {
/**
* Permission to read resources granted.
*/
this.read = false;
/**
* Permission to write resources granted.
*/
this.write = false;
/**
* Permission to delete queues and messages granted.
*/
this.delete = false;
/**
* Permission to list queues granted.
*/
this.list = false;
/**
* Permission to add messages, table entities, and append to blobs granted.
*/
this.add = false;
/**
* Permission to create queues, blobs and files granted.
*/
this.create = false;
/**
* Permissions to update messages and table entities granted.
*/
this.update = false;
/**
* Permission to get and delete messages granted.
*/
this.process = false;
}
/**
* Parse initializes the AccountSASPermissions fields from a string.
*
* @param permissions -
*/
static parse(permissions) {
const accountSASPermissions = new AccountSASPermissions();
for (const c of permissions) {
switch (c) {
case "r":
accountSASPermissions.read = true;
break;
case "w":
accountSASPermissions.write = true;
break;
case "d":
accountSASPermissions.delete = true;
break;
case "l":
accountSASPermissions.list = true;
break;
case "a":
accountSASPermissions.add = true;
break;
case "c":
accountSASPermissions.create = true;
break;
case "u":
accountSASPermissions.update = true;
break;
case "p":
accountSASPermissions.process = true;
break;
default:
throw new RangeError(`Invalid permission character: ${c}`);
}
}
return accountSASPermissions;
}
/**
* Produces the SAS permissions string for an Azure Storage account.
* Call this method to set AccountSASSignatureValues Permissions field.
*
* Using this method will guarantee the resource types are in
* an order accepted by the service.
*
* @see https://learn.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
*
*/
toString() {
// The order of the characters should be as specified here to ensure correctness:
// https://learn.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
// Use a string array instead of string concatenating += operator for performance
const permissions = [];
if (this.read) {
permissions.push("r");
}
if (this.write) {
permissions.push("w");
}
if (this.delete) {
permissions.push("d");
}
if (this.list) {
permissions.push("l");
}
if (this.add) {
permissions.push("a");
}
if (this.create) {
permissions.push("c");
}
if (this.update) {
permissions.push("u");
}
if (this.process) {
permissions.push("p");
}
return permissions.join("");
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* ONLY AVAILABLE IN NODE.JS RUNTIME.
*
* This is a helper class to construct a string representing the resources accessible by an AccountSAS. Setting a value
* to true means that any SAS which uses these permissions will grant access to that resource type. Once all the
* values are set, this should be serialized with toString and set as the resources field on an
* {@link AccountSASSignatureValues} object. It is possible to construct the resources string without this class, but
* the order of the resources is particular and this class guarantees correctness.
*/
class AccountSASResourceTypes {
constructor() {
/**
* Permission to access service level APIs granted.
*/
this.service = false;
/**
* Permission to access container level APIs (Blob Containers, Tables, Queues, File Shares) granted.
*/
this.container = false;
/**
* Permission to access object level APIs (Blobs, Table Entities, Queue Messages, Files) granted.
*/
this.object = false;
}
/**
* Creates an {@link AccountSASResourceTypes} from the specified resource types string. This method will throw an
* Error if it encounters a character that does not correspond to a valid resource type.
*
* @param resourceTypes -
*/
static parse(resourceTypes) {
const accountSASResourceTypes = new AccountSASResourceTypes();
for (const c of resourceTypes) {
switch (c) {
case "s":
accountSASResourceTypes.service = true;
break;
case "c":
accountSASResourceTypes.container = true;
break;
case "o":
accountSASResourceTypes.object = true;
break;
default:
throw new RangeError(`Invalid resource type: ${c}`);
}
}
return accountSASResourceTypes;
}
/**
* Converts the given resource types to a string.
*
* @see https://learn.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
*
*/
toString() {
const resourceTypes = [];
if (this.service) {
resourceTypes.push("s");
}
if (this.container) {
resourceTypes.push("c");
}
if (this.object) {
resourceTypes.push("o");
}
return resourceTypes.join("");
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* ONLY AVAILABLE IN NODE.JS RUNTIME.
*
* This is a helper class to construct a string representing the services accessible by an AccountSAS. Setting a value
* to true means that any SAS which uses these permissions will grant access to that service. Once all the
* values are set, this should be serialized with toString and set as the services field on an
* {@link AccountSASSignatureValues} object. It is possible to construct the services string without this class, but
* the order of the services is particular and this class guarantees correctness.
*/
class AccountSASServices {
constructor() {
/**
* Permission to access blob resources granted.
*/
this.blob = false;
/**
* Permission to access file resources granted.
*/
this.file = false;
/**
* Permission to access queue resources granted.
*/
this.queue = false;
/**
* Permission to access table resources granted.
*/
this.table = false;
}
/**
* Creates an {@link AccountSASServices} from the specified services string. This method will throw an
* Error if it encounters a character that does not correspond to a valid service.
*
* @param services -
*/
static parse(services) {
const accountSASServices = new AccountSASServices();
for (const c of services) {
switch (c) {
case "b":
accountSASServices.blob = true;
break;
case "f":
accountSASServices.file = true;
break;
case "q":
accountSASServices.queue = true;
break;
case "t":
accountSASServices.table = true;
break;
default:
throw new RangeError(`Invalid service character: ${c}`);
}
}
return accountSASServices;
}
/**
* Converts the given services to a string.
*
*/
toString() {
const services = [];
if (this.blob) {
services.push("b");
}
if (this.table) {
services.push("t");
}
if (this.queue) {
services.push("q");
}
if (this.file) {
services.push("f");
}
return services.join("");
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* Generate SasIPRange format string. For example:
*
* "8.8.8.8" or "1.1.1.1-255.255.255.255"
*
* @param ipRange -
*/
function ipRangeToString(ipRange) {
return ipRange.end ? `${ipRange.start}-${ipRange.end}` : ipRange.start;
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
const SDK_VERSION = "12.26.0";
const SERVICE_VERSION = "2025-05-05";
/**
* The OAuth scope to use with Azure Storage.
*/
const StorageOAuthScopes = "https://storage.azure.com/.default";
const DevelopmentConnectionString = `DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;
AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;
QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;`;
const StorageQueueLoggingAllowedHeaderNames = [
"Access-Control-Allow-Origin",
"Cache-Control",
"Content-Length",
"Content-Type",
"Date",
"Request-Id",
"traceparent",
"Transfer-Encoding",
"User-Agent",
"x-ms-client-request-id",
"x-ms-date",
"x-ms-error-code",
"x-ms-request-id",
"x-ms-return-client-request-id",
"x-ms-version",
"x-ms-approximate-messages-count",
"x-ms-popreceipt",
"x-ms-time-next-visible",
];
const StorageQueueLoggingAllowedQueryParameters = [
"comp",
"maxresults",
"rscc",
"rscd",
"rsce",
"rscl",
"rsct",
"se",
"si",
"sip",
"sp",
"spr",
"sr",
"srt",
"ss",
"st",
"sv",
"include",
"marker",
"prefix",
"messagettl",
"numofmessages",
"peekonly",
"popreceipt",
"visibilitytimeout",
];
/// List of ports used for path style addressing.
/// Path style addressing means that storage account is put in URI's Path segment in instead of in host.
const PathStylePorts = [
"10000",
"10001",
"10002",
"10003",
"10004",
"10100",
"10101",
"10102",
"10103",
"10104",
"11000",
"11001",
"11002",
"11003",
"11004",
"11100",
"11101",
"11102",
"11103",
"11104",
];
/**
* Append a string to URL path. Will remove duplicated "/" in front of the string
* when URL path ends with a "/".
*
* @param url - Source URL string
* @param name - String to be appended to URL
* @returns An updated URL string
*/
function appendToURLPath(url, name) {
const urlParsed = new URL(url);
let path = urlParsed.pathname;
path = path ? (path.endsWith("/") ? `${path}${name}` : `${path}/${name}`) : name;
urlParsed.pathname = path;
return urlParsed.toString();
}
function getProxyUriFromDevConnString(connectionString) {
// Development Connection String
// https://learn.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string#connect-to-the-emulator-account-using-the-well-known-account-name-and-key
let proxyUri = "";
if (connectionString.search("DevelopmentStorageProxyUri=") !== -1) {
// CONNECTION_STRING=UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://myProxyUri
const matchCredentials = connectionString.split(";");
for (const element of matchCredentials) {
if (element.trim().startsWith("DevelopmentStorageProxyUri=")) {
proxyUri = element.trim().match("DevelopmentStorageProxyUri=(.*)")[1];
}
}
}
return proxyUri;
}
/**
*
* @param connectionString - Account connection string.
* @param argument - property to get value from the connection string.
* @returns Value of the property specified in argument.
*/
function getValueInConnString(connectionString, argument) {
const elements = connectionString.split(";");
for (const element of elements) {
if (element.trim().startsWith(argument)) {
return element.trim().match(argument + "=(.*)")[1];
}
}
return "";
}
/**
* Extracts the parts of an Azure Storage account connection string.
*
* @param connectionString - Connection string.
* @returns String key value pairs of the storage account's url and credentials.
*/
function extractConnectionStringParts(connectionString) {
let proxyUri = "";
if (connectionString.startsWith("UseDevelopmentStorage=true")) {
// Development connection string
proxyUri = getProxyUriFromDevConnString(connectionString);
connectionString = DevelopmentConnectionString;
}
// Matching QueueEndpoint in the Account connection string
let queueEndpoint = getValueInConnString(connectionString, "QueueEndpoint");
// Slicing off '/' at the end if exists
// (The methods that use `extractConnectionStringParts` expect the url to not have `/` at the end)
queueEndpoint = queueEndpoint.endsWith("/") ? queueEndpoint.slice(0, -1) : queueEndpoint;
if (connectionString.search("DefaultEndpointsProtocol=") !== -1 &&
connectionString.search("AccountKey=") !== -1) {
// Account connection string
let defaultEndpointsProtocol = "";
let accountName = "";
let accountKey = Buffer.from("accountKey", "base64");
let endpointSuffix = "";
// Get account name and key
accountName = getValueInConnString(connectionString, "AccountName");
accountKey = Buffer.from(getValueInConnString(connectionString, "AccountKey"), "base64");
if (!queueEndpoint) {
// QueueEndpoint is not present in the Account connection string
// Can be obtained from `${defaultEndpointsProtocol}://${accountName}.queue.${endpointSuffix}`
defaultEndpointsProtocol = getValueInConnString(connectionString, "DefaultEndpointsProtocol");
const protocol = defaultEndpointsProtocol.toLowerCase();
if (protocol !== "https" && protocol !== "http") {
throw new Error("Invalid DefaultEndpointsProtocol in the provided Connection String. Expecting 'https' or 'http'");
}
endpointSuffix = getValueInConnString(connectionString, "EndpointSuffix");
if (!endpointSuffix) {
throw new Error("Invalid EndpointSuffix in the provided Connection String");
}
queueEndpoint = `${defaultEndpointsProtocol}://${accountName}.queue.${endpointSuffix}`;
}
if (!accountName) {
throw new Error("Invalid AccountName in the provided Connection String");
}
else if (accountKey.length === 0) {
throw new Error("Invalid AccountKey in the provided Connection String");
}
return {
kind: "AccountConnString",
url: queueEndpoint,
accountName,
accountKey,
proxyUri,
};
}
else {
// SAS connection string
const accountSas = getValueInConnString(connectionString, "SharedAccessSignature");
let accountName = getValueInConnString(connectionString, "AccountName");
// if accountName is empty, try to read it from BlobEndpoint
if (!accountName) {
accountName = getAccountNameFromUrl(queueEndpoint);
}
if (!queueEndpoint) {
throw new Error("Invalid QueueEndpoint in the provided SAS Connection String");
}
else if (!accountSas) {
throw new Error("Invalid SharedAccessSignature in the provided SAS Connection String");
}
return { kind: "SASConnString", url: queueEndpoint, accountName, accountSas };
}
}
/**
* Rounds a date off to seconds.
*
* @param date -
* @param withMilliseconds - If true, YYYY-MM-DDThh:mm:ss.fffffffZ will be returned;
* If false, YYYY-MM-DDThh:mm:ssZ will be returned.
* @returns Date string in ISO8061 format, with or without 7 milliseconds component
*/
function truncatedISO8061Date(date, withMilliseconds = true) {
// Date.toISOString() will return like "2018-10-29T06:34:36.139Z"
const dateString = date.toISOString();
return withMilliseconds
? dateString.substring(0, dateString.length - 1) + "0000" + "Z"
: dateString.substring(0, dateString.length - 5) + "Z";
}
/**
* Extracts account name from the url
* @param url - url to extract the account name from
* @returns with the account name
*/
function getAccountNameFromUrl(url) {
const parsedUrl = new URL(url);
let accountName;
try {
if (parsedUrl.hostname.split(".")[1] === "queue") {
// `${defaultEndpointsProtocol}://${accountName}.queue.${endpointSuffix}`;
accountName = parsedUrl.hostname.split(".")[0];
}
else if (isIpEndpointStyle(parsedUrl)) {
// IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/
// Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/
// .getPath() -> /devstoreaccount1/
accountName = parsedUrl.pathname.split("/")[1];
}
else {
// Custom domain case: "https://customdomain.com/containername/blob".
accountName = "";
}
return accountName;
}
catch (error) {
throw new Error("Unable to extract accountName with provided information.");
}
}
function isIpEndpointStyle(parsedUrl) {
const host = parsedUrl.host;
// Case 1: Ipv6, use a broad regex to find out candidates whose host contains two ':'.
// Case 2: localhost(:port) or host.docker.internal, use broad regex to match port part.
// Case 3: Ipv4, use broad regex which just check if host contains Ipv4.
// For valid host please refer to https://man7.org/linux/man-pages/man7/hostname.7.html.
return (/^.*:.*:.*$|^(localhost|host.docker.internal)(:[0-9]+)?$|^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}(:[0-9]+)?$/.test(host) ||
(Boolean(parsedUrl.port) && PathStylePorts.includes(parsedUrl.port)));
}
/**
* Append a string to URL query.
*
* @param url - Source URL string.
* @param queryParts - String to be appended to the URL query.
* @returns An updated URL string.
*/
function appendToURLQuery(url, queryParts) {
const urlParsed = new URL(url);
let query = urlParsed.search;
if (query) {
query += "&" + queryParts;
}
else {
query = queryParts;
}
urlParsed.search = query;
return urlParsed.toString();
}
/**
* A typesafe helper for ensuring that a given response object has
* the original _response attached.
* @param response - A response object from calling a client operation
* @returns The same object, but with known _response property
*/
function assertResponse(response) {
if (`_response` in response) {
return response;
}
throw new TypeError(`Unexpected response object ${response}`);
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* Protocols for generated SAS.
*/
exports.SASProtocol = void 0;
(function (SASProtocol) {
/**
* Protocol that allows HTTPS only
*/
SASProtocol["Https"] = "https";
/**
* Protocol that allows both HTTPS and HTTP
*/
SASProtocol["HttpsAndHttp"] = "https,http";
})(exports.SASProtocol || (exports.SASProtocol = {}));
/**
* Represents the components that make up an Azure Storage SAS' query parameters. This type is not constructed directly
* by the user; it is only generated by the {@link AccountSASSignatureValues} and {@link QueueSASSignatureValues}
* types. Once generated, it can be encoded into a {@link String} and appended to a URL directly (though caution should
* be taken here in case there are existing query parameters, which might affect the appropriate means of appending
* these query parameters).
*
* NOTE: Instances of this class are immutable.
*/
class SASQueryParameters {
/**
* Optional. IP range allowed for this SAS.
*
* @readonly
*/
get ipRange() {
if (this.ipRangeInner) {
return {
end: this.ipRangeInner.end,
start: this.ipRangeInner.start,
};
}
return undefined;
}
/**
* Creates an instance of SASQueryParameters.
*
* @param version - Representing the storage version
* @param signature - Representing the signature for the SAS token
* @param permissions - Representing the storage permissions
* @param services - Representing the storage services being accessed (only for Account SAS)
* @param resourceTypes - Representing the storage resource types being accessed (only for Account SAS)
* @param protocol - Representing the allowed HTTP protocol(s)
* @param startsOn - Representing the start time for this SAS token
* @param expiresOn - Representing the expiry time for this SAS token
* @param ipRange - Representing the range of valid IP addresses for this SAS token
* @param identifier - Representing the signed identifier (only for Service SAS)
* @param resource - Representing the storage queue (only for Service SAS)
*/
constructor(version, signature, permissions, services, resourceTypes, protocol, startsOn, expiresOn, ipRange, identifier, resource) {
this.version = version;
this.services = services;
this.resourceTypes = resourceTypes;
this.expiresOn = expiresOn;
this.permissions = permissions;
this.protocol = protocol;
this.startsOn = startsOn;
this.ipRangeInner = ipRange;
this.identifier = identifier;
this.resource = resource;
this.signature = signature;
}
/**
* Encodes all SAS query parameters into a string that can be appended to a URL.
*
*/
toString() {
const params = ["sv", "ss", "srt", "spr", "st", "se", "sip", "si", "sr", "sp", "sig"];
const queries = [];
for (const param of params) {
switch (param) {
case "sv":
this.tryAppendQueryParameter(queries, param, this.version);
break;
case "ss":
this.tryAppendQueryParameter(queries, param, this.services);
break;
case "srt":
this.tryAppendQueryParameter(queries, param, this.resourceTypes);
break;
case "spr":
this.tryAppendQueryParameter(queries, param, this.protocol);
break;
case "st":
this.tryAppendQueryParameter(queries, param, this.startsOn ? truncatedISO8061Date(this.startsOn, false) : undefined);
break;
case "se":
this.tryAppendQueryParameter(queries, param, this.expiresOn ? truncatedISO8061Date(this.expiresOn, false) : undefined);
break;
case "sip":
this.tryAppendQueryParameter(queries, param, this.ipRange ? ipRangeToString(this.ipRange) : undefined);
break;
case "si":
this.tryAppendQueryParameter(queries, param, this.identifier);
break;
case "sr":
this.tryAppendQueryParameter(queries, param, this.resource);
break;
case "sp":
this.tryAppendQueryParameter(queries, param, this.permissions);
break;
case "sig":
this.tryAppendQueryParameter(queries, param, this.signature);
break;
}
}
return queries.join("&");
}
/**
* A private helper method used to filter and append query key/value pairs into an array.
*
* @param queries -
* @param key -
* @param value -
*/
tryAppendQueryParameter(queries, key, value) {
if (!value) {
return;
}
key = encodeURIComponent(key);
value = encodeURIComponent(value);
if (key.length > 0 && value.length > 0) {
queries.push(`${key}=${value}`);
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* ONLY AVAILABLE IN NODE.JS RUNTIME.
*
* Generates a {@link SASQueryParameters} object which contains all SAS query parameters needed to make an actual
* REST request.
*
* @see https://learn.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas
*
* @param accountSASSignatureValues - SAS Signature values of the account
* @param sharedKeyCredential - Shared key credential.
*/
function generateAccountSASQueryParameters(accountSASSignatureValues, sharedKeyCredential) {
return generateAccountSASQueryParametersInternal(accountSASSignatureValues, sharedKeyCredential)
.sasQueryParameters;
}
function generateAccountSASQueryParametersInternal(accountSASSignatureValues, sharedKeyCredential) {
const version = accountSASSignatureValues.version
? accountSASSignatureValues.version
: SERVICE_VERSION;
const parsedPermissions = AccountSASPermissions.parse(accountSASSignatureValues.permissions.toString()).toString();
const parsedServices = AccountSASServices.parse(accountSASSignatureValues.services).toString();
const parsedResourceTypes = AccountSASResourceTypes.parse(accountSASSignatureValues.resourceTypes).toString();
let stringToSign;
if (version >= "2020-12-06") {
stringToSign = [
sharedKeyCredential.accountName,
parsedPermissions,
parsedServices,
parsedResourceTypes,
accountSASSignatureValues.startsOn
? truncatedISO8061Date(accountSASSignatureValues.startsOn, false)
: "",
truncatedISO8061Date(accountSASSignatureValues.expiresOn, false),
accountSASSignatureValues.ipRange ? ipRangeToString(accountSASSignatureValues.ipRange) : "",
accountSASSignatureValues.protocol ? accountSASSignatureValues.protocol : "",
version,
"", // Reserved for encryption scope
"", // Account SAS requires an additional newline character
].join("\n");
}
else {
stringToSign = [
sharedKeyCredential.accountName,
parsedPermissions,
parsedServices,
parsedResourceTypes,
accountSASSignatureValues.startsOn
? truncatedISO8061Date(accountSASSignatureValues.startsOn, false)
: "",
truncatedISO8061Date(accountSASSignatureValues.expiresOn, false),
accountSASSignatureValues.ipRange ? ipRangeToString(accountSASSignatureValues.ipRange) : "",
accountSASSignatureValues.protocol ? accountSASSignatureValues.protocol : "",
version,
"", // Account SAS requires an additional newline character
].join("\n");
}
const signature = sharedKeyCredential.computeHMACSHA256(stringToSign);
return {
sasQueryParameters: new SASQueryParameters(version, signature, parsedPermissions, parsedServices, parsedResourceTypes, accountSASSignatureValues.protocol, accountSASSignatureValues.startsOn, accountSASSignatureValues.expiresOn, accountSASSignatureValues.ipRange),
stringToSign: stringToSign,
};
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* The base class from which all request policies derive.
*/
class BaseRequestPolicy {
/**
* The main method to implement that manipulates a request/response.
*/
constructor(
/**
* The next policy in the pipeline. Each policy is responsible for executing the next one if the request is to continue through the pipeline.
*/
_nextPolicy,
/**
* The options that can be passed to a given request policy.
*/
_options) {
this._nextPolicy = _nextPolicy;
this._options = _options;
}
/**
* Get whether or not a log with the provided log level should be logged.
* @param logLevel - The log level of the log that will be logged.
* @returns Whether or not a log with the provided log level should be logged.
*/
shouldLog(logLevel) {
return this._options.shouldLog(logLevel);
}
/**
* Attempt to log the provided message to the provided logger. If no logger was provided or if
* the log level does not meat the logger's threshold, then nothing will be logged.
* @param logLevel - The log level of this log.
* @param message - The message of this log.
*/
log(logLevel, message) {
this._options.log(logLevel, message);
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* Credential policy used to sign HTTP(S) requests before sending. This is an
* abstract class.
*/
class CredentialPolicy extends BaseRequestPolicy {
/**
* Sends out request.
*
* @param request -
*/
sendRequest(request) {
return this._nextPolicy.sendRequest(this.signRequest(request));
}
/**
* Child classes must implement this method with request signing. This method
* will be executed in {@link sendRequest}.
*
* @param request -
*/
signRequest(request) {
// Child classes must override this method with request signing. This method
// will be executed in sendRequest().
return request;
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* AnonymousCredentialPolicy is used with HTTP(S) requests that read public resources
* or for use with Shared Access Signatures (SAS).
*/
class AnonymousCredentialPolicy extends CredentialPolicy {
/**
* Creates an instance of AnonymousCredentialPolicy.
* @param nextPolicy -
* @param options -
*/
// The base class has a protected constructor. Adding a public one to enable constructing of this class.
/* eslint-disable-next-line @typescript-eslint/no-useless-constructor*/
constructor(nextPolicy, options) {
super(nextPolicy, options);
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* Credential is an abstract class for Azure Storage HTTP requests signing. This
* class will host an credentialPolicyCreator factory which generates CredentialPolicy.
*/
class Credential {
/**
* Creates a RequestPolicy object.
*
* @param _nextPolicy -
* @param _options -
*/
create(_nextPolicy, _options) {
throw new Error("Method should be implemented in children classes.");
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* AnonymousCredential provides a credentialPolicyCreator member used to create
* AnonymousCredentialPolicy objects. AnonymousCredentialPolicy is used with
* HTTP(S) requests that read public resources or for use with Shared Access
* Signatures (SAS).
*/
class AnonymousCredential extends Credential {
/**
* Creates an {@link AnonymousCredentialPolicy} object.
*
* @param nextPolicy -
* @param options -
*/
create(nextPolicy, options) {
return new AnonymousCredentialPolicy(nextPolicy, options);
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
const URLConstants = {
Parameters: {
FORCE_BROWSER_NO_CACHE: "_",
TIMEOUT: "timeout",
},
};
const HeaderConstants = {
AUTHORIZATION: "Authorization",
CONTENT_ENCODING: "Content-Encoding",
CONTENT_LANGUAGE: "Content-Language",
CONTENT_LENGTH: "Content-Length",
CONTENT_MD5: "Content-Md5",
CONTENT_TYPE: "Content-Type",
COOKIE: "Cookie",
DATE: "date",
IF_MATCH: "if-match",
IF_MODIFIED_SINCE: "if-modified-since",
IF_NONE_MATCH: "if-none-match",
IF_UNMODIFIED_SINCE: "if-unmodified-since",
PREFIX_FOR_STORAGE: "x-ms-",
RANGE: "Range",
X_MS_DATE: "x-ms-date"};
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* Set URL parameter name and value. If name exists in URL parameters, old value
* will be replaced by name key. If not provide value, the parameter will be deleted.
*
* @param url - Source URL string
* @param name - Parameter name
* @param value - Parameter value
* @returns An updated URL string
*/
function setURLParameter(url, name, value) {
const urlParsed = new URL(url);
const encodedName = encodeURIComponent(name);
const encodedValue = value ? encodeURIComponent(value) : undefined;
// mutating searchParams will change the encoding, so we have to do this ourselves
const searchString = urlParsed.search === "" ? "?" : urlParsed.search;
const searchPieces = [];
for (const pair of searchString.slice(1).split("&")) {
if (pair) {
const [key] = pair.split("=", 2);
if (key !== encodedName) {
searchPieces.push(pair);
}
}
}
if (encodedValue) {
searchPieces.push(`${encodedName}=${encodedValue}`);
}
urlParsed.search = searchPieces.length ? `?${searchPieces.join("&")}` : "";
return urlParsed.toString();
}
/**
* Set URL host.
*
* @param url - Source URL string
* @param host - New host string
* @returns An updated URL string
*/
function setURLHost(url, host) {
const urlParsed = new URL(url);
urlParsed.hostname = host;
return urlParsed.toString();
}
/**
* Get URL path from an URL string.
*
* @param url - Source URL string
*/
function getURLPath(url) {
try {
const urlParsed = new URL(url);
return urlParsed.pathname;
}
catch (e) {
return undefined;
}
}
/**
* Get URL query key value pairs from an URL string.
*
* @param url -
*/
function getURLQueries(url) {
let queryString = new URL(url).search;
if (!queryString) {
return {};
}
queryString = queryString.trim();
queryString = queryString.startsWith("?") ? queryString.substring(1) : queryString;
let querySubStrings = queryString.split("&");
querySubStrings = querySubStrings.filter((value) => {
const indexOfEqual = value.indexOf("=");
const lastIndexOfEqual = value.lastIndexOf("=");
return (indexOfEqual > 0 && indexOfEqual === lastIndexOfEqual && lastIndexOfEqual < value.length - 1);
});
const queries = {};
for (const querySubString of querySubStrings) {
const splitResults = querySubString.split("=");
const key = splitResults[0];
const value = splitResults[1];
queries[key] = value;
}
return queries;
}
/**
* Delay specified time interval.
*
* @param timeInMs -
* @param aborter -
* @param abortError -
*/
async function delay(timeInMs, aborter, abortError) {
return new Promise((resolve, reject) => {
/* eslint-disable-next-line prefer-const */
let timeout;
const abortHandler = () => {
if (timeout !== undefined) {
clearTimeout(timeout);
}
reject(abortError);
};
const resolveHandler = () => {
if (aborter !== undefined) {
aborter.removeEventListener("abort", abortHandler);
}
resolve();
};
timeout = setTimeout(resolveHandler, timeInMs);
if (aborter !== undefined) {
aborter.addEventListener("abort", abortHandler);
}
});
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/*
* We need to imitate .Net culture-aware sorting, which is used in storage service.
* Below tables contain sort-keys for en-US culture.
*/
const table_lv0 = new Uint32Array([
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71c, 0x0, 0x71f, 0x721,
0x723, 0x725, 0x0, 0x0, 0x0, 0x72d, 0x803, 0x0, 0x0, 0x733, 0x0, 0xd03, 0xd1a, 0xd1c, 0xd1e,
0xd20, 0xd22, 0xd24, 0xd26, 0xd28, 0xd2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe02, 0xe09, 0xe0a,
0xe1a, 0xe21, 0xe23, 0xe25, 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, 0xe70, 0xe7c, 0xe7e, 0xe89,
0xe8a, 0xe91, 0xe99, 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, 0x0, 0x0, 0x0, 0x743, 0x744, 0x748,
0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25, 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, 0xe70,
0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99, 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, 0x0, 0x74c,
0x0, 0x750, 0x0,
]);
const table_lv2 = new Uint32Array([
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
]);
const table_lv4 = new Uint32Array([
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x8012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8212, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
]);
function compareHeader(lhs, rhs) {
if (isLessThan(lhs, rhs))
return -1;
return 1;
}
function isLessThan(lhs, rhs) {
const tables = [table_lv0, table_lv2, table_lv4];
let curr_level = 0;
let i = 0;
let j = 0;
while (curr_level < tables.length) {
if (curr_level === tables.length - 1 && i !== j) {
return i > j;
}
const weight1 = i < lhs.length ? tables[curr_level][lhs[i].charCodeAt(0)] : 0x1;
const weight2 = j < rhs.length ? tables[curr_level][rhs[j].charCodeAt(0)] : 0x1;
if (weight1 === 0x1 && weight2 === 0x1) {
i = 0;
j = 0;
++curr_level;
}
else if (weight1 === weight2) {
++i;
++j;
}
else if (weight1 === 0) {
++i;
}
else if (weight2 === 0) {
++j;
}
else {
return weight1 < weight2;
}
}
return false;
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* StorageSharedKeyCredentialPolicy is a policy used to sign HTTP request with a shared key.
*/
class StorageSharedKeyCredentialPolicy extends CredentialPolicy {
/**
* Creates an instance of StorageSharedKeyCredentialPolicy.
* @param nextPolicy -
* @param options -
* @param factory -
*/
constructor(nextPolicy, options, factory) {
super(nextPolicy, options);
this.factory = factory;
}
/**
* Signs request.
*
* @param request -
*/
signRequest(request) {
request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString());
if (request.body &&
(typeof request.body === "string" || request.body !== undefined) &&
request.body.length > 0) {
request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body));
}
const stringToSign = [
request.method.toUpperCase(),
this.getHeaderValueToSign(request, HeaderConstants.CONTENT_LANGUAGE),
this.getHeaderValueToSign(request, HeaderConstants.CONTENT_ENCODING),
this.getHeaderValueToSign(request, HeaderConstants.CONTENT_LENGTH),
this.getHeaderValueToSign(request, HeaderConstants.CONTENT_MD5),
this.getHeaderValueToSign(request, HeaderConstants.CONTENT_TYPE),
this.getHeaderValueToSign(request, HeaderConstants.DATE),
this.getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE),
this.getHeaderValueToSign(request, HeaderConstants.IF_MATCH),
this.getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH),
this.getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE),
this.getHeaderValueToSign(request, HeaderConstants.RANGE),
].join("\n") +
"\n" +
this.getCanonicalizedHeadersString(request) +
this.getCanonicalizedResourceString(request);
const signature = this.factory.computeHMACSHA256(stringToSign);
request.headers.set(HeaderConstants.AUTHORIZATION, `SharedKey ${this.factory.accountName}:${signature}`);
// console.log(`[URL]:${request.url}`);
// console.log(`[HEADERS]:${request.headers.toString()}`);
// console.log(`[STRING TO SIGN]:${JSON.stringify(stringToSign)}`);
// console.log(`[KEY]: ${request.headers.get(HeaderConstants.AUTHORIZATION)}`);
return request;
}
/**
* Retrieve header value according to shared key sign rules.
* @see https://learn.microsoft.com/en-us/rest/api/storageservices/authenticate-with-shared-key
*
* @param request -
* @param headerName -
*/
getHeaderValueToSign(request, headerName) {
const value = request.headers.get(headerName);
if (!value) {
return "";
}
// When using version 2015-02-21 or later, if Content-Length is zero, then
// set the Content-Length part of the StringToSign to an empty string.
// https://learn.microsoft.com/en-us/rest/api/storageservices/authenticate-with-shared-key
if (headerName === HeaderConstants.CONTENT_LENGTH && value === "0") {
return "";
}
return value;
}
/**
* 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. Replace any linear whitespace in the header value with a single space.
* 5. Trim any whitespace 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 request -
*/
getCanonicalizedHeadersString(request) {
let headersArray = request.headers.headersArray().filter((value) => {
return value.name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE);
});
headersArray.sort((a, b) => {
return compareHeader(a.name.toLowerCase(), b.name.toLowerCase());
});
// Remove duplicate headers
headersArray = headersArray.filter((value, index, array) => {
if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) {
return false;
}
return true;
});
let canonicalizedHeadersStringToSign = "";
headersArray.forEach((header) => {
canonicalizedHeadersStringToSign += `${header.name
.toLowerCase()
.trimRight()}:${header.value.trimLeft()}\n`;
});
return canonicalizedHeadersStringToSign;
}
/**
* Retrieves the webResource canonicalized resource string.
*
* @param request -
*/
getCanonicalizedResourceString(request) {
const path = getURLPath(request.url) || "/";
let canonicalizedResourceString = "";
canonicalizedResourceString += `/${this.factory.accountName}${path}`;
const queries = getURLQueries(request.url);
const lowercaseQueries = {};
if (queries) {
const queryKeys = [];
for (const key in queries) {
if (Object.prototype.hasOwnProperty.call(queries, key)) {
const lowercaseKey = key.toLowerCase();
lowercaseQueries[lowercaseKey] = queries[key];
queryKeys.push(lowercaseKey);
}
}
queryKeys.sort();
for (const key of queryKeys) {
canonicalizedResourceString += `\n${key}:${decodeURIComponent(lowercaseQueries[key])}`;
}
}
return canonicalizedResourceString;
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* ONLY AVAILABLE IN NODE.JS RUNTIME.
*
* StorageSharedKeyCredential for account key authorization of Azure Storage service.
*/
class StorageSharedKeyCredential extends Credential {
/**
* Creates an instance of StorageSharedKeyCredential.
* @param accountName -
* @param accountKey -
*/
constructor(accountName, accountKey) {
super();
this.accountName = accountName;
this.accountKey = Buffer.from(accountKey, "base64");
}
/**
* Creates a StorageSharedKeyCredentialPolicy object.
*
* @param nextPolicy -
* @param options -
*/
create(nextPolicy, options) {
return new StorageSharedKeyCredentialPolicy(nextPolicy, options, this);
}
/**
* Generates a hash signature for an HTTP request or for a SAS.
*
* @param stringToSign -
*/
computeHMACSHA256(stringToSign) {
return crypto.createHmac("sha256", this.accountKey).update(stringToSign, "utf8").digest("base64");
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* The `@azure/logger` configuration for this package.
*/
const logger$1 = logger$2.createClientLogger("storage-queue");
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* The `@azure/logger` configuration for this package.
*/
const logger = logger$2.createClientLogger("storage-blob");
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* RetryPolicy types.
*/
exports.StorageRetryPolicyType = void 0;
(function (StorageRetryPolicyType) {
/**
* Exponential retry. Retry time delay grows exponentially.
*/
StorageRetryPolicyType[StorageRetryPolicyType["EXPONENTIAL"] = 0] = "EXPONENTIAL";
/**
* Linear retry. Retry time delay grows linearly.
*/
StorageRetryPolicyType[StorageRetryPolicyType["FIXED"] = 1] = "FIXED";
})(exports.StorageRetryPolicyType || (exports.StorageRetryPolicyType = {}));
// Default values of StorageRetryOptions
const DEFAULT_RETRY_OPTIONS$1 = {