UNPKG

@azure/cosmos

Version:
416 lines (415 loc) • 15.1 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var helper_exports = {}; __export(helper_exports, { canApplyExcludedLocations: () => canApplyExcludedLocations, copyObject: () => copyObject, createDeserializer: () => createDeserializer, createSerializer: () => createSerializer, extractPath: () => extractPath, getContainerLink: () => getContainerLink, getHexaDigit: () => getHexaDigit, getIdFromLink: () => getIdFromLink, getPathFromLink: () => getPathFromLink, getResourceIdFromPath: () => getResourceIdFromPath, isItemResourceValid: () => isItemResourceValid, isReadRequest: () => isReadRequest, isResourceValid: () => isResourceValid, isStringNullOrEmpty: () => isStringNullOrEmpty, jsonStringifyAndEscapeNonASCII: () => jsonStringifyAndEscapeNonASCII, parseConnectionString: () => parseConnectionString, parseLink: () => parseLink, parsePath: () => parsePath, prepareURL: () => prepareURL, sleep: () => sleep, trimSlashFromLeftAndRight: () => trimSlashFromLeftAndRight, trimSlashes: () => trimSlashes, validateClientEncryptionPolicy: () => validateClientEncryptionPolicy, validateItemResourceId: () => validateItemResourceId, validateResourceId: () => validateResourceId }); module.exports = __toCommonJS(helper_exports); var import_Serializers = require("../encryption/Serializers/index.js"); var import_EncryptionType = require("../encryption/enums/EncryptionType.js"); var import_TypeMarker = require("../encryption/enums/TypeMarker.js"); var import_ErrorResponse = require("../request/ErrorResponse.js"); var import_constants = require("./constants.js"); const trimLeftSlashes = new RegExp("^[/]+"); const trimRightSlashes = new RegExp("[/]+$"); const illegalResourceIdCharacters = new RegExp("[/\\\\?#]"); const illegalItemResourceIdCharacters = new RegExp("[/\\\\#]"); function jsonStringifyAndEscapeNonASCII(arg) { return JSON.stringify(arg).replace(/[\u007F-\uFFFF]/g, (m) => { return "\\u" + ("0000" + m.charCodeAt(0).toString(16)).slice(-4); }); } function parseLink(resourcePath) { if (resourcePath.length === 0) { return { type: void 0, objectBody: void 0 }; } if (resourcePath[resourcePath.length - 1] !== "/") { resourcePath = resourcePath + "/"; } if (resourcePath[0] !== "/") { resourcePath = "/" + resourcePath; } const pathParts = resourcePath.split("/"); let id; let type; if (pathParts.length % 2 === 0) { id = pathParts[pathParts.length - 2]; type = pathParts[pathParts.length - 3]; } else { id = pathParts[pathParts.length - 3]; type = pathParts[pathParts.length - 2]; } const result = { type, objectBody: { id, self: resourcePath } }; return result; } function isReadRequest(operationType) { return operationType === import_constants.OperationType.Read || operationType === import_constants.OperationType.Query; } function sleep(time) { return new Promise((resolve) => { setTimeout(() => { resolve(); }, time); }); } function getContainerLink(link) { return link.split("/").slice(0, 4).join("/"); } function prepareURL(endpoint, path) { return trimSlashes(endpoint) + path; } function trimSlashes(source) { return source.replace(trimLeftSlashes, "").replace(trimRightSlashes, ""); } function getHexaDigit() { return Math.floor(Math.random() * 16).toString(16); } function parsePath(path) { const pathParts = []; let currentIndex = 0; const throwError = () => { throw new Error("Path " + path + " is invalid at index " + currentIndex); }; const getEscapedToken = () => { const quote = path[currentIndex]; let newIndex = ++currentIndex; for (; ; ) { newIndex = path.indexOf(quote, newIndex); if (newIndex === -1) { throwError(); } if (path[newIndex - 1] !== "\\") { break; } ++newIndex; } const token = path.substr(currentIndex, newIndex - currentIndex); currentIndex = newIndex + 1; return token; }; const getToken = () => { const newIndex = path.indexOf("/", currentIndex); let token = null; if (newIndex === -1) { token = path.substr(currentIndex); currentIndex = path.length; } else { token = path.substr(currentIndex, newIndex - currentIndex); currentIndex = newIndex; } token = token.trim(); return token; }; while (currentIndex < path.length) { if (path[currentIndex] !== "/") { throwError(); } if (++currentIndex === path.length) { break; } if (path[currentIndex] === '"' || path[currentIndex] === "'") { pathParts.push(getEscapedToken()); } else { pathParts.push(getToken()); } } return pathParts; } function isResourceValid(resource, err) { if (resource.id) { if (typeof resource.id !== "string") { err.message = "Id must be a string."; return false; } if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1 || resource.id.indexOf("?") !== -1 || resource.id.indexOf("#") !== -1) { err.message = "Id contains illegal chars."; return false; } if (resource.id[resource.id.length - 1] === " ") { err.message = "Id ends with a space."; return false; } } return true; } function isItemResourceValid(resource, err) { if (resource.id) { if (typeof resource.id !== "string") { err.message = "Id must be a string."; return false; } if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1 || resource.id.indexOf("#") !== -1) { err.message = "Id contains illegal chars."; return false; } } return true; } function getIdFromLink(resourceLink) { resourceLink = trimSlashes(resourceLink); return resourceLink; } function getPathFromLink(resourceLink, resourceType) { resourceLink = trimSlashes(resourceLink); if (resourceType) { return "/" + encodeURI(resourceLink) + "/" + resourceType; } else { return "/" + encodeURI(resourceLink); } } function isStringNullOrEmpty(inputString) { return !inputString || /^\s*$/.test(inputString); } function trimSlashFromLeftAndRight(inputString) { if (typeof inputString !== "string") { throw new Error("invalid input: input is not string"); } return inputString.replace(trimLeftSlashes, "").replace(trimRightSlashes, ""); } function validateResourceId(resourceId) { if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) { throw new Error("Resource ID must be a string and cannot be undefined, null or empty"); } if (illegalResourceIdCharacters.test(resourceId)) { throw new Error("Illegal characters ['/', '\\', '#', '?'] cannot be used in Resource ID"); } return true; } function validateItemResourceId(resourceId) { if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) { throw new Error("Resource ID must be a string and cannot be undefined, null or empty"); } if (illegalItemResourceIdCharacters.test(resourceId)) { throw new Error("Illegal characters ['/', '\\', '#'] cannot be used in Resource ID"); } return true; } function getResourceIdFromPath(resourcePath) { if (!resourcePath || typeof resourcePath !== "string") { return null; } const trimmedPath = trimSlashFromLeftAndRight(resourcePath); const pathSegments = trimmedPath.split("/"); if (pathSegments.length % 2 !== 0) { return null; } return pathSegments[pathSegments.length - 1]; } function parseConnectionString(connectionString) { const keyValueStrings = connectionString.split(";"); const { AccountEndpoint, AccountKey } = keyValueStrings.reduce( (connectionObject, keyValueString) => { const [key, ...value] = keyValueString.split("="); connectionObject[key] = value.join("="); return connectionObject; }, {} ); if (!AccountEndpoint || !AccountKey) { throw new Error("Could not parse the provided connection string"); } return { endpoint: AccountEndpoint, key: AccountKey }; } function copyObject(obj) { return JSON.parse( JSON.stringify(obj, (_, value) => { if (typeof value === "bigint") { throw new Error(`BigInt type is not supported`); } return value; }) ); } function createDeserializer(typeMarker) { switch (typeMarker) { case import_TypeMarker.TypeMarker.Long: { return new import_Serializers.NumberSerializer(); } case import_TypeMarker.TypeMarker.Double: return new import_Serializers.FloatSerializer(); case import_TypeMarker.TypeMarker.String: return new import_Serializers.StringSerializer(); case import_TypeMarker.TypeMarker.Boolean: return new import_Serializers.BooleanSerializer(); default: throw new Error("Invalid or Unsupported data type passed."); } } function extractPath(path) { const secondSlashIndex = path.indexOf("/", path.indexOf("/") + 1); return secondSlashIndex === -1 ? path : path.substring(0, secondSlashIndex); } function createSerializer(propertyValue, type) { if (type) { if (type === import_TypeMarker.TypeMarker.Long) { return [import_TypeMarker.TypeMarker.Long, new import_Serializers.NumberSerializer()]; } else if (type === import_TypeMarker.TypeMarker.Double) { return [import_TypeMarker.TypeMarker.Double, new import_Serializers.FloatSerializer()]; } else if (type === import_TypeMarker.TypeMarker.String) { return [import_TypeMarker.TypeMarker.String, new import_Serializers.StringSerializer()]; } else if (type === import_TypeMarker.TypeMarker.Boolean) { return [import_TypeMarker.TypeMarker.Boolean, new import_Serializers.BooleanSerializer()]; } else { throw new Error("Invalid or Unsupported data type passed."); } } else { switch (typeof propertyValue) { case "boolean": return [import_TypeMarker.TypeMarker.Boolean, new import_Serializers.BooleanSerializer()]; case "string": return [import_TypeMarker.TypeMarker.String, new import_Serializers.StringSerializer()]; case "object": if (propertyValue.constructor === Date) { return [import_TypeMarker.TypeMarker.String, new import_Serializers.StringSerializer()]; } throw new Error("Invalid or Unsupported data type passed."); case "number": if (!Number.isInteger(propertyValue)) { return [import_TypeMarker.TypeMarker.Double, new import_Serializers.FloatSerializer()]; } else { return [import_TypeMarker.TypeMarker.Long, new import_Serializers.NumberSerializer()]; } default: throw new Error("Invalid or Unsupported data type passed."); } } } function validateClientEncryptionPolicy(clientEncryptionPolicy, partitionKey) { const policyFormatVersion = clientEncryptionPolicy.policyFormatVersion; if (policyFormatVersion < 1 || policyFormatVersion > 2) { throw new import_ErrorResponse.ErrorResponse("Supported versions of client encryption policy are 1 and 2."); } const paths = /* @__PURE__ */ new Set(); for (const includedPath of clientEncryptionPolicy.includedPaths) { if (paths.has(includedPath.path)) { throw new import_ErrorResponse.ErrorResponse( `Duplicate path found: ${includedPath.path} in client encryption policy.` ); } if (includedPath.path === void 0 || includedPath.path === null || includedPath.path === "" || includedPath.path === "/") { throw new import_ErrorResponse.ErrorResponse("Path needs to be defined in ClientEncryptionIncludedPath."); } if (includedPath.clientEncryptionKeyId === void 0 || includedPath.clientEncryptionKeyId === null || includedPath.clientEncryptionKeyId === "" || typeof includedPath.clientEncryptionKeyId !== "string") { throw new import_ErrorResponse.ErrorResponse( "ClientEncryptionKeyId needs to be defined as string type in ClientEncryptionIncludedPath." ); } if (includedPath.path[0] !== "/") { throw new import_ErrorResponse.ErrorResponse("Path in ClientEncryptionIncludedPath must start with '/'."); } const pathSegments = includedPath.path.split("/").filter((segment) => segment.length > 0); if (pathSegments.length > 1) { throw new import_ErrorResponse.ErrorResponse("Only top-level paths are currently supported for encryption"); } paths.add(includedPath.path); } const encryptedPaths = clientEncryptionPolicy.includedPaths; const partitionKeyPaths = partitionKey.paths.map(extractPath); let isPartitionKeyEncrypted = false; let isIdEncrypted = false; for (const encryptedPath of encryptedPaths) { if (encryptedPath.path === "/id") { isIdEncrypted = true; if (encryptedPath.encryptionType !== import_EncryptionType.EncryptionType.DETERMINISTIC) { throw new import_ErrorResponse.ErrorResponse( "The '/id' property must be encrypted using Deterministic encryption." ); } } if (partitionKeyPaths.includes(encryptedPath.path)) { isPartitionKeyEncrypted = true; if (encryptedPath.encryptionType !== import_EncryptionType.EncryptionType.DETERMINISTIC) { throw new import_ErrorResponse.ErrorResponse( `Path: ${encryptedPath.path} which is part of the partition key has to be encrypted with Deterministic type Encryption.` ); } } } if ((isPartitionKeyEncrypted || isIdEncrypted) && clientEncryptionPolicy.policyFormatVersion === 1) { throw new import_ErrorResponse.ErrorResponse( "Encryption of partition key or id is only supported with policy format version 2." ); } } function canApplyExcludedLocations(resourceType) { return resourceType === import_constants.ResourceType.item; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { canApplyExcludedLocations, copyObject, createDeserializer, createSerializer, extractPath, getContainerLink, getHexaDigit, getIdFromLink, getPathFromLink, getResourceIdFromPath, isItemResourceValid, isReadRequest, isResourceValid, isStringNullOrEmpty, jsonStringifyAndEscapeNonASCII, parseConnectionString, parseLink, parsePath, prepareURL, sleep, trimSlashFromLeftAndRight, trimSlashes, validateClientEncryptionPolicy, validateItemResourceId, validateResourceId });