export function validateClientEncryptionPolicy()

in sdk/cosmosdb/cosmos/src/common/helper.ts [465:541]


export function validateClientEncryptionPolicy(
  clientEncryptionPolicy: ClientEncryptionPolicy,
  partitionKey: PartitionKeyDefinition,
) {
  const policyFormatVersion = clientEncryptionPolicy.policyFormatVersion;
  if (policyFormatVersion < 1 || policyFormatVersion > 2) {
    throw new ErrorResponse("Supported versions of client encryption policy are 1 and 2.");
  }
  const paths = new Set<string>();
  // checks for duplicate paths and validates the path format and clientEncryptionKeyId
  for (const includedPath of clientEncryptionPolicy.includedPaths) {
    if (paths.has(includedPath.path)) {
      throw new ErrorResponse(
        `Duplicate path found: ${includedPath.path} in client encryption policy.`,
      );
    }
    if (
      includedPath.path === undefined ||
      includedPath.path === null ||
      includedPath.path === "" ||
      includedPath.path === "/"
    ) {
      throw new ErrorResponse("Path needs to be defined in ClientEncryptionIncludedPath.");
    }
    if (
      includedPath.clientEncryptionKeyId === undefined ||
      includedPath.clientEncryptionKeyId === null ||
      includedPath.clientEncryptionKeyId === "" ||
      typeof includedPath.clientEncryptionKeyId !== "string"
    ) {
      throw new ErrorResponse(
        "ClientEncryptionKeyId needs to be defined as string type in ClientEncryptionIncludedPath.",
      );
    }
    if (includedPath.path[0] !== "/") {
      throw new ErrorResponse("Path in ClientEncryptionIncludedPath must start with '/'.");
    }
    const pathSegments = includedPath.path.split("/").filter((segment) => segment.length > 0);
    if (pathSegments.length > 1) {
      throw new ErrorResponse("Only top-level paths are currently supported for encryption");
    }
    paths.add(includedPath.path);
  }

  // checks if id and partition key paths are encrypted using Deterministic encryption algorithm.
  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 !== EncryptionType.DETERMINISTIC) {
        throw new ErrorResponse(
          "The '/id' property must be encrypted using Deterministic encryption.",
        );
      }
    }
    if (partitionKeyPaths.includes(encryptedPath.path)) {
      isPartitionKeyEncrypted = true;
      if (encryptedPath.encryptionType !== EncryptionType.DETERMINISTIC) {
        throw new ErrorResponse(
          `Path: ${encryptedPath.path} which is part of the partition key has to be encrypted with Deterministic type Encryption.`,
        );
      }
    }
  }
  // Ensures that the policy format version is 2 if id or partition key paths are encrypted.
  if (
    (isPartitionKeyEncrypted || isIdEncrypted) &&
    clientEncryptionPolicy.policyFormatVersion === 1
  ) {
    throw new ErrorResponse(
      "Encryption of partition key or id is only supported with policy format version 2.",
    );
  }
}