async function validateConfig()

in cloudrun-malware-scanner/config.ts [89:235]


async function validateConfig(config: any, storage: Storage): Promise<Config> {
  delete config.comments;

  if (config.buckets == null || config.buckets.length === 0) {
    logger.fatal(`No buckets configured for scanning`);
    throw new Error('No buckets configured');
  }

  logger.info('BUCKET_CONFIG: ' + JSON.stringify(config, null, 2));

  // Check buckets are specified and exist.
  let success = true;
  for (let x = 0; x < config.buckets.length; x++) {
    const bucketDefs = config.buckets[x] as BucketDefs;
    for (const bucketType of BUCKET_TYPES) {
      if (
        !(await checkBucketExists(
          bucketDefs[bucketType],
          `config.buckets[${x.toString()}].${bucketType}`,
          storage,
        ))
      ) {
        success = false;
      }
    }
    if (
      bucketDefs.unscanned === bucketDefs.clean ||
      bucketDefs.unscanned === bucketDefs.quarantined ||
      bucketDefs.clean === bucketDefs.quarantined
    ) {
      logger.fatal(
        `Config Error: buckets[${x.toString()}]: bucket names are not unique`,
      );
      success = false;
    }
  }
  if (
    !(await checkBucketExists(
      config.ClamCvdMirrorBucket as string,
      'ClamCvdMirrorBucket',
      storage,
    ))
  ) {
    success = false;
  }

  // Validate ignoreZeroLengthFiles
  if (config.ignoreZeroLengthFiles == null) {
    config.ignoreZeroLengthFiles = false;
  } else if (typeof config.ignoreZeroLengthFiles !== 'boolean') {
    logger.fatal(
      `Config Error: ignoreZeroLengthFiles must be true or false: ${JSON.stringify(config.ignoreZeroLengthFiles)}`,
    );
    success = false;
  }

  // Validate fileExclusionPatterns[] and convert to fileExclusionRegexps[]
  config.fileExclusionRegexps = [];
  if (config.fileExclusionPatterns != null) {
    if (!(config.fileExclusionPatterns instanceof Array)) {
      logger.fatal(
        `Config Error: fileExclusionPatterns must be an array of Strings`,
      );
      success = false;
    } else {
      // config.fileExclusionPatterns is an array, check each value and
      // convert to a regexp in fileExclusionRegexps[]
      for (let i = 0; i < config.fileExclusionPatterns.length; i++) {
        let pattern: string | undefined;
        let flags: string | undefined;

        // Each element can either be a simple pattern:
        //   "^.*\\.tmp$"
        // or an array with pattern and flags, eg for case-insensive matching:
        //   [ "^.*\\tmp$", "i" ]
        const element = config.fileExclusionPatterns[i] as
          | string
          | Array<string>;
        if (typeof element === 'string') {
          // validate regex as simple string
          pattern = element;
        } else if (
          Array.isArray(element) &&
          element.length <= 2 &&
          element.length >= 1 &&
          typeof element[0] === 'string'
        ) {
          // validate regex as [pattern, flags]
          pattern = element[0];
          flags = element[1];
        } else {
          pattern = undefined;
        }

        if (pattern == null) {
          logger.fatal(
            `Config Error: fileExclusionPatterns[${i}] must be either a string or an array of 2 strings: ${JSON.stringify(config.fileExclusionPatterns[i])}`,
          );
          success = false;
        } else {
          try {
            config.fileExclusionRegexps[i] = new RegExp(pattern, flags);
          } catch (e) {
            logger.fatal(
              e,
              `Config Error: fileExclusionPatterns[${i}]:  Regexp compile failed for ${JSON.stringify(config.fileExclusionPatterns[i])}: ${e as Error}`,
            );
            success = false;
          }
        }
      }
    }
  }
  delete config.fileExclusionPatterns;

  // Validate quarantine.fileExtensionAllowList[]
  config.quarantine = config.quarantine ?? {};
  try {
    config.quarantine.fileExtensionAllowList = validateFileExtensionList(
      config.quarantine.fileExtensionAllowList,
    );
  } catch (e) {
    logger.fatal(
      e,
      `Config Error: quarantine.fileExtensionAllowList[]:  ${(e as Error).message}`,
    );
    success = false;
  }
  // Validate quarantine.fileExtensionDenyList[]
  try {
    config.quarantine.fileExtensionDenyList = validateFileExtensionList(
      config.quarantine.fileExtensionDenyList,
    );
  } catch (e) {
    logger.fatal(
      e,
      `Config Error: quarantine.fileExtensionDenyList[]:  ${(e as Error).message}`,
    );
    success = false;
  }

  if (!success) {
    throw new Error('Invalid configuration');
  }

  return Object.freeze(config as Config);
}