UNPKG

@azure/storage-queue

Version:

Microsoft Azure Storage SDK for JavaScript - Queue

1,358 lines (1,332 loc) 224 kB
'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 = {