function batchCreate()

in src/emulator/auth/operations.ts [294:489]


function batchCreate(
  state: ProjectState,
  reqBody: Schemas["GoogleCloudIdentitytoolkitV1UploadAccountRequest"]
): Schemas["GoogleCloudIdentitytoolkitV1UploadAccountResponse"] {
  assert(!state.disableAuth, "PROJECT_DISABLED");
  assert(state.usageMode !== UsageMode.PASSTHROUGH, "UNSUPPORTED_PASSTHROUGH_OPERATION");
  assert(reqBody.users?.length, "MISSING_USER_ACCOUNT");

  if (reqBody.sanityCheck) {
    if (state.oneAccountPerEmail) {
      const existingEmails = new Set<string>();
      for (const userInfo of reqBody.users) {
        if (userInfo.email) {
          assert(!existingEmails.has(userInfo.email), `DUPLICATE_EMAIL : ${userInfo.email}`);
          existingEmails.add(userInfo.email);
        }
      }
    }

    // Check that there is no duplicate (providerId, rawId) tuple.
    const existingProviderAccounts = new Set<string>();
    for (const userInfo of reqBody.users) {
      for (const { providerId, rawId } of userInfo.providerUserInfo ?? []) {
        const key = `${providerId}:${rawId}`;
        assert(
          !existingProviderAccounts.has(key),
          `DUPLICATE_RAW_ID : Provider id(${providerId}), Raw id(${rawId})`
        );
        existingProviderAccounts.add(key);
      }
    }
  }

  if (!reqBody.allowOverwrite) {
    const existingLocalIds = new Set<string>();
    for (const userInfo of reqBody.users) {
      const localId = userInfo.localId || "";
      assert(!existingLocalIds.has(localId), `DUPLICATE_LOCAL_ID : ${localId}`);
      existingLocalIds.add(localId);
    }
  }

  const errors: { index: number; message: string }[] = [];
  for (let index = 0; index < reqBody.users.length; index++) {
    const userInfo = reqBody.users[index];

    try {
      assert(userInfo.localId, "localId is missing");
      const uploadTime = new Date();
      const fields: Omit<Partial<UserInfo>, "localId"> = {
        displayName: userInfo.displayName,
        photoUrl: userInfo.photoUrl,
        lastLoginAt: userInfo.lastLoginAt,
      };
      if (userInfo.tenantId) {
        assert(
          state instanceof TenantProjectState && state.tenantId === userInfo.tenantId,
          "Tenant id in userInfo does not match the tenant id in request."
        );
      }
      if (state instanceof TenantProjectState) {
        fields.tenantId = state.tenantId;
      }

      // password
      if (userInfo.passwordHash) {
        // TODO: Check and block non-emulator hashes.
        fields.passwordHash = userInfo.passwordHash;
        fields.salt = userInfo.salt;
        fields.passwordUpdatedAt = uploadTime.getTime();
      } else if (userInfo.rawPassword) {
        fields.salt = userInfo.salt || "fakeSalt" + randomId(20);
        fields.passwordHash = hashPassword(userInfo.rawPassword, fields.salt);
        fields.passwordUpdatedAt = uploadTime.getTime();
      }

      // custom attrs
      if (userInfo.customAttributes) {
        validateSerializedCustomClaims(userInfo.customAttributes);
        fields.customAttributes = userInfo.customAttributes;
      }

      // federated
      if (userInfo.providerUserInfo) {
        fields.providerUserInfo = [];
        for (const providerUserInfo of userInfo.providerUserInfo) {
          const { providerId, rawId, federatedId } = providerUserInfo;
          if (providerId === PROVIDER_PASSWORD || providerId === PROVIDER_PHONE) {
            // These providers are handled automatically by create / update.
            continue;
          }
          if (!rawId || !providerId) {
            if (!federatedId) {
              assert(false, "federatedId or (providerId & rawId) is required");
            } else {
              // TODO
              assert(
                false,
                "((Parsing federatedId is not implemented in Auth Emulator; please specify providerId AND rawId as a workaround.))"
              );
            }
          }
          const existingUserWithRawId = state.getUserByProviderRawId(providerId, rawId);
          assert(
            !existingUserWithRawId || existingUserWithRawId.localId === userInfo.localId,
            "raw id exists in other account in database"
          );
          fields.providerUserInfo.push({ ...providerUserInfo, providerId, rawId });
        }
      }

      // phone number
      if (userInfo.phoneNumber) {
        assert(isValidPhoneNumber(userInfo.phoneNumber), "phone number format is invalid");
        fields.phoneNumber = userInfo.phoneNumber;
      }

      fields.validSince = toUnixTimestamp(uploadTime).toString();
      fields.createdAt = uploadTime.getTime().toString();
      if (fields.createdAt && !isNaN(Number(userInfo.createdAt))) {
        fields.createdAt = userInfo.createdAt;
      }
      if (userInfo.email) {
        const email = userInfo.email;
        assert(isValidEmailAddress(email), "email is invalid");

        // For simplicity, Auth Emulator performs this check in all cases
        // (unlike production which checks only if (reqBody.sanityCheck && state.oneAccountPerEmail)).
        // We return a non-standard error message in other cases to clarify.
        const existingUserWithEmail = state.getUserByEmail(email);
        assert(
          !existingUserWithEmail || existingUserWithEmail.localId === userInfo.localId,
          reqBody.sanityCheck && state.oneAccountPerEmail
            ? "email exists in other account in database"
            : `((Auth Emulator does not support importing duplicate email: ${email}))`
        );
        fields.email = canonicalizeEmailAddress(email);
      }
      fields.emailVerified = !!userInfo.emailVerified;
      fields.disabled = !!userInfo.disabled;

      // MFA
      if (userInfo.mfaInfo) {
        fields.mfaInfo = [];
        assert(fields.email, "Second factor account requires email to be presented.");
        assert(fields.emailVerified, "Second factor account requires email to be verified.");
        const existingIds = new Set<string>();
        for (const enrollment of userInfo.mfaInfo) {
          if (enrollment.mfaEnrollmentId) {
            assert(!existingIds.has(enrollment.mfaEnrollmentId), "Enrollment id already exists.");
            existingIds.add(enrollment.mfaEnrollmentId);
          }
        }

        for (const enrollment of userInfo.mfaInfo) {
          enrollment.mfaEnrollmentId = enrollment.mfaEnrollmentId || newRandomId(28, existingIds);
          enrollment.enrolledAt = enrollment.enrolledAt || new Date().toISOString();
          assert(enrollment.phoneInfo, "Second factor not supported.");
          assert(isValidPhoneNumber(enrollment.phoneInfo), "Phone number format is invalid");
          enrollment.unobfuscatedPhoneInfo = enrollment.phoneInfo;
          fields.mfaInfo.push(enrollment);
        }
      }

      if (state.getUserByLocalId(userInfo.localId)) {
        assert(
          reqBody.allowOverwrite,
          "localId belongs to an existing account - can not overwrite."
        );
      }
      state.overwriteUserWithLocalId(userInfo.localId, fields);
    } catch (e: any) {
      if (e instanceof BadRequestError) {
        // Use friendlier messages for some codes, consistent with production.
        let message = e.message;
        if (message === "INVALID_CLAIMS") {
          message = "Invalid custom claims provided.";
        } else if (message === "CLAIMS_TOO_LARGE") {
          message = "Custom claims provided are too large.";
        } else if (message.startsWith("FORBIDDEN_CLAIM")) {
          message = "Custom claims provided include a reserved claim.";
        }
        errors.push({
          index,
          message,
        });
      } else {
        throw e;
      }
    }
  }
  return {
    kind: "identitytoolkit#UploadAccountResponse",
    error: errors,
  };
}