host: emulatorHost()

in src/auth/auth-api-request.ts [202:502]


        host: emulatorHost()
      });
    } else {
      this.urlFormat = FIREBASE_AUTH_TENANT_URL_FORMAT;
    }
  }

  /**
   * Returns the resource URL corresponding to the provided parameters.
   *
   * @param api - The backend API name.
   * @param params - The optional additional parameters to substitute in the
   *     URL path.
   * @returns The corresponding resource URL.
   */
  public getUrl(api?: string, params?: object): Promise<string> {
    return super.getUrl(api, params)
      .then((url) => {
        return utils.formatString(url, { tenantId: this.tenantId });
      });
  }
}

/**
 * Auth-specific HTTP client which uses the special "owner" token
 * when communicating with the Auth Emulator.
 */
class AuthHttpClient extends AuthorizedHttpClient {

  protected getToken(): Promise<string> {
    if (useEmulator()) {
      return Promise.resolve('owner');
    }

    return super.getToken();
  }

}

/**
 * Validates an AuthFactorInfo object. All unsupported parameters
 * are removed from the original request. If an invalid field is passed
 * an error is thrown.
 *
 * @param request - The AuthFactorInfo request object.
 */
function validateAuthFactorInfo(request: AuthFactorInfo): void {
  const validKeys = {
    mfaEnrollmentId: true,
    displayName: true,
    phoneInfo: true,
    enrolledAt: true,
  };
  // Remove unsupported keys from the original request.
  for (const key in request) {
    if (!(key in validKeys)) {
      delete request[key];
    }
  }
  // No enrollment ID is available for signupNewUser. Use another identifier.
  const authFactorInfoIdentifier =
      request.mfaEnrollmentId || request.phoneInfo || JSON.stringify(request);
  // Enrollment uid may or may not be specified for update operations.
  if (typeof request.mfaEnrollmentId !== 'undefined' &&
      !validator.isNonEmptyString(request.mfaEnrollmentId)) {
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_UID,
      'The second factor "uid" must be a valid non-empty string.',
    );
  }
  if (typeof request.displayName !== 'undefined' &&
      !validator.isString(request.displayName)) {
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_DISPLAY_NAME,
      `The second factor "displayName" for "${authFactorInfoIdentifier}" must be a valid string.`,
    );
  }
  // enrolledAt must be a valid UTC date string.
  if (typeof request.enrolledAt !== 'undefined' &&
      !validator.isISODateString(request.enrolledAt)) {
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_ENROLLMENT_TIME,
      `The second factor "enrollmentTime" for "${authFactorInfoIdentifier}" must be a valid ` +
      'UTC date string.');
  }
  // Validate required fields depending on second factor type.
  if (typeof request.phoneInfo !== 'undefined') {
    // phoneNumber should be a string and a valid phone number.
    if (!validator.isPhoneNumber(request.phoneInfo)) {
      throw new FirebaseAuthError(
        AuthClientErrorCode.INVALID_PHONE_NUMBER,
        `The second factor "phoneNumber" for "${authFactorInfoIdentifier}" must be a non-empty ` +
        'E.164 standard compliant identifier string.');
    }
  } else {
    // Invalid second factor. For example, a phone second factor may have been provided without
    // a phone number. A TOTP based second factor may require a secret key, etc.
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_ENROLLED_FACTORS,
      'MFAInfo object provided is invalid.');
  }
}


/**
 * Validates a providerUserInfo object. All unsupported parameters
 * are removed from the original request. If an invalid field is passed
 * an error is thrown.
 *
 * @param request - The providerUserInfo request object.
 */
function validateProviderUserInfo(request: any): void {
  const validKeys = {
    rawId: true,
    providerId: true,
    email: true,
    displayName: true,
    photoUrl: true,
  };
  // Remove invalid keys from original request.
  for (const key in request) {
    if (!(key in validKeys)) {
      delete request[key];
    }
  }
  if (!validator.isNonEmptyString(request.providerId)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_PROVIDER_ID);
  }
  if (typeof request.displayName !== 'undefined' &&
      typeof request.displayName !== 'string') {
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_DISPLAY_NAME,
      `The provider "displayName" for "${request.providerId}" must be a valid string.`,
    );
  }
  if (!validator.isNonEmptyString(request.rawId)) {
    // This is called localId on the backend but the developer specifies this as
    // uid externally. So the error message should use the client facing name.
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_UID,
      `The provider "uid" for "${request.providerId}" must be a valid non-empty string.`,
    );
  }
  // email should be a string and a valid email.
  if (typeof request.email !== 'undefined' && !validator.isEmail(request.email)) {
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_EMAIL,
      `The provider "email" for "${request.providerId}" must be a valid email string.`,
    );
  }
  // photoUrl should be a URL.
  if (typeof request.photoUrl !== 'undefined' &&
      !validator.isURL(request.photoUrl)) {
    // This is called photoUrl on the backend but the developer specifies this as
    // photoURL externally. So the error message should use the client facing name.
    throw new FirebaseAuthError(
      AuthClientErrorCode.INVALID_PHOTO_URL,
      `The provider "photoURL" for "${request.providerId}" must be a valid URL string.`,
    );
  }
}


/**
 * Validates a create/edit request object. All unsupported parameters
 * are removed from the original request. If an invalid field is passed
 * an error is thrown.
 *
 * @param request - The create/edit request object.
 * @param writeOperationType - The write operation type.
 */
function validateCreateEditRequest(request: any, writeOperationType: WriteOperationType): void {
  const uploadAccountRequest = writeOperationType === WriteOperationType.Upload;
  // Hash set of whitelisted parameters.
  const validKeys = {
    displayName: true,
    localId: true,
    email: true,
    password: true,
    rawPassword: true,
    emailVerified: true,
    photoUrl: true,
    disabled: true,
    disableUser: true,
    deleteAttribute: true,
    deleteProvider: true,
    sanityCheck: true,
    phoneNumber: true,
    customAttributes: true,
    validSince: true,
    // Pass linkProviderUserInfo only for updates (i.e. not for uploads.)
    linkProviderUserInfo: !uploadAccountRequest,
    // Pass tenantId only for uploadAccount requests.
    tenantId: uploadAccountRequest,
    passwordHash: uploadAccountRequest,
    salt: uploadAccountRequest,
    createdAt: uploadAccountRequest,
    lastLoginAt: uploadAccountRequest,
    providerUserInfo: uploadAccountRequest,
    mfaInfo: uploadAccountRequest,
    // Only for non-uploadAccount requests.
    mfa: !uploadAccountRequest,
  };
  // Remove invalid keys from original request.
  for (const key in request) {
    if (!(key in validKeys)) {
      delete request[key];
    }
  }
  if (typeof request.tenantId !== 'undefined' &&
      !validator.isNonEmptyString(request.tenantId)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_TENANT_ID);
  }
  // For any invalid parameter, use the external key name in the error description.
  // displayName should be a string.
  if (typeof request.displayName !== 'undefined' &&
      !validator.isString(request.displayName)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_DISPLAY_NAME);
  }
  if ((typeof request.localId !== 'undefined' || uploadAccountRequest) &&
      !validator.isUid(request.localId)) {
    // This is called localId on the backend but the developer specifies this as
    // uid externally. So the error message should use the client facing name.
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_UID);
  }
  // email should be a string and a valid email.
  if (typeof request.email !== 'undefined' && !validator.isEmail(request.email)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_EMAIL);
  }
  // phoneNumber should be a string and a valid phone number.
  if (typeof request.phoneNumber !== 'undefined' &&
      !validator.isPhoneNumber(request.phoneNumber)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_PHONE_NUMBER);
  }
  // password should be a string and a minimum of 6 chars.
  if (typeof request.password !== 'undefined' &&
      !validator.isPassword(request.password)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_PASSWORD);
  }
  // rawPassword should be a string and a minimum of 6 chars.
  if (typeof request.rawPassword !== 'undefined' &&
      !validator.isPassword(request.rawPassword)) {
    // This is called rawPassword on the backend but the developer specifies this as
    // password externally. So the error message should use the client facing name.
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_PASSWORD);
  }
  // emailVerified should be a boolean.
  if (typeof request.emailVerified !== 'undefined' &&
      typeof request.emailVerified !== 'boolean') {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_EMAIL_VERIFIED);
  }
  // photoUrl should be a URL.
  if (typeof request.photoUrl !== 'undefined' &&
      !validator.isURL(request.photoUrl)) {
    // This is called photoUrl on the backend but the developer specifies this as
    // photoURL externally. So the error message should use the client facing name.
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_PHOTO_URL);
  }
  // disabled should be a boolean.
  if (typeof request.disabled !== 'undefined' &&
      typeof request.disabled !== 'boolean') {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_DISABLED_FIELD);
  }
  // validSince should be a number.
  if (typeof request.validSince !== 'undefined' &&
      !validator.isNumber(request.validSince)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_TOKENS_VALID_AFTER_TIME);
  }
  // createdAt should be a number.
  if (typeof request.createdAt !== 'undefined' &&
      !validator.isNumber(request.createdAt)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_CREATION_TIME);
  }
  // lastSignInAt should be a number.
  if (typeof request.lastLoginAt !== 'undefined' &&
      !validator.isNumber(request.lastLoginAt)) {
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_LAST_SIGN_IN_TIME);
  }
  // disableUser should be a boolean.
  if (typeof request.disableUser !== 'undefined' &&
      typeof request.disableUser !== 'boolean') {
    // This is called disableUser on the backend but the developer specifies this as
    // disabled externally. So the error message should use the client facing name.
    throw new FirebaseAuthError(AuthClientErrorCode.INVALID_DISABLED_FIELD);
  }
  // customAttributes should be stringified JSON with no blacklisted claims.
  // The payload should not exceed 1KB.
  if (typeof request.customAttributes !== 'undefined') {
    let developerClaims: object;
    try {
      developerClaims = JSON.parse(request.customAttributes);
    } catch (error) {
      // JSON parsing error. This should never happen as we stringify the claims internally.
      // However, we still need to check since setAccountInfo via edit requests could pass
      // this field.
      throw new FirebaseAuthError(AuthClientErrorCode.INVALID_CLAIMS, error.message);
    }
    const invalidClaims: string[] = [];
    // Check for any invalid claims.
    RESERVED_CLAIMS.forEach((blacklistedClaim) => {
      if (Object.prototype.hasOwnProperty.call(developerClaims, blacklistedClaim)) {