You are here

function httpbl_comment_presave in http:BL 8

Same name and namespace in other branches
  1. 7 httpbl.module \httpbl_comment_presave()

Implements hook_comment_presave().

Checks and Blocks comment submissions from nuisance IPs.

File

./httpbl.module, line 88
Implements Project Honeypot's http:BL for Drupal. It provides IP-based blacklisting through http:BL and allows linking to a honeypot.

Code

function httpbl_comment_presave($comment) {

  // Exit immediately if not configured for comment blocking only.
  if (\Drupal::state()
    ->get('httpbl.check') != HTTPBL_CHECK_COMMENTS) {
    return;
  }

  //Get the log service.
  $logTrapper = \Drupal::service('httpbl.logtrapper');

  // Check available storage options.  These are used while blocking comment to
  // inform comment reviewer of the extent of their options.
  if (\Drupal::state()
    ->get('httpbl.storage') == HTTPBL_DB_HH || \Drupal::state()
    ->get('httpbl.storage') == HTTPBL_DB_HH_DRUPAL) {

    // If auto-banning is enabled (using Httpbl with Ban module).
    if (\Drupal::state()
      ->get('httpbl.storage') == HTTPBL_DB_HH_DRUPAL) {
      $blacklist_and_ban = TRUE;
      $no_storage = FALSE;
      $blacklist_only = FALSE;
    }
    elseif (\Drupal::state()
      ->get('httpbl.storage') == HTTPBL_DB_HH) {
      $no_storage = FALSE;
      $blacklist_and_ban = FALSE;
      $blacklist_only = TRUE;
    }
  }
  else {
    $no_storage = TRUE;
    $blacklist_and_ban = FALSE;
    $blacklist_only = FALSE;
  }

  // Get request info needed below.
  $request = Drupal::request();
  $requestUri = $request
    ->getRequestUri();
  $ip = $request
    ->getClientIp();

  // Log this comment check.
  $logTrapper
    ->trapDebug('Checking @ip during comment pre-save.', [
    '@ip' => $ip,
  ]);

  //Get Evaluator service.
  $httpblEvaluator = \Drupal::service('httpbl.evaluator');

  // No Project Honeypot support for IPv6 addresses.
  // If this is not an IPv4, set to skip evaluation.
  $project_supported = TRUE;
  if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
    $project_supported = FALSE;
  }

  // Evaluation and comment processing begins.
  if (!isset($evaluated)) {

    // Evaluate this visitor IP.
    $evaluated = $httpblEvaluator
      ->evaluateVisitor($ip, $request, $project_supported);

    // If visitor was evaluated as not safe...
    if ($evaluated[1] > HTTPBL_LIST_SAFE) {

      // Comment user's IP found in Project Honeypot.
      // Let them know.
      drupal_set_message(t('Your comment was rejected because your IP address (@ip) is ranked "suspicious" by Project Honeypot.', [
        '@ip' => $ip,
      ]), 'error', FALSE);

      // Prepare to alter the comment subject and body.
      // Make link to the blocked host profile on Project Honeypot.
      $url = Url::fromUri('http://www.projecthoneypot.org/search_ip.php?ip=' . $ip);
      $url_options = [
        'attributes' => [
          'class' => [
            'httpbl-comment-blocked',
            'httpbl-comment-blocked-profile',
          ],
          'absolute' => TRUE,
        ],
      ];
      $url
        ->setOptions($url_options);
      $link = Link::fromTextAndUrl(t('Project Honeypot'), $url)
        ->toString();
      $honeypot_profile = 'http://www.projecthoneypot.org/search_ip.php?ip=' . $ip;

      // Force the comment to unpublished status.
      $comment
        ->setPublished(0);

      // Save original subject, then alter.
      $original_subject = $comment
        ->getSubject();
      $subject = t('(THIS COMMENT HAS BEEN Http:BL BLOCKED!)');
      $comment
        ->setSubject($subject);

      // Save original body, then alter
      $original_body = $comment
        ->get('comment_body')->value;

      // Add details for later comment review.  Why the comment was blocked,
      // with a link to the host's profile, if further research is desired.
      $blocked_body = t('<p><strong>!!! This comment was blocked and unpublished by the httpbl module!!!</strong></p>');
      $blocked_body .= t('<p><strong>Host IP (@ip) has been identified as a nuisance, by @Project.</strong></p>', [
        '@ip' => $ip,
        '@Project' => $link,
      ]);

      // Prepare a suggestion link for using httpbl to blacklist (and possibly
      // ban) a grey-listed host that makes repeated, comment annoyances.
      $blacklistUrl = Url::fromRoute('httpbl.host_add');
      $blacklistUrl_options = [
        'attributes' => [
          'class' => [
            'httpbl-comment-blocked',
            'httpbl-comment-blocked-config',
          ],
          'target' => '_blank',
        ],
      ];
      $blacklistUrl
        ->setOptions($blacklistUrl_options);
      $blacklistLink = Link::fromTextAndUrl(t('blacklisting'), $blacklistUrl)
        ->toString();

      // Prepare a suggestion link for using ban manager to ban IP.
      $banUrl = Url::fromRoute('ban.admin_page');
      $banUrl_options = [
        'attributes' => [
          'class' => [
            'httpbl-comment-blocked',
            'httpbl-comment-blocked-config',
          ],
          'target' => '_blank',
        ],
      ];
      $banUrl
        ->setOptions($banUrl_options);
      $banLink = Link::fromTextAndUrl(t('banning'), $banUrl)
        ->toString();

      // If this host is blacklisted...
      if ($evaluated[1] == HTTPBL_LIST_BLACK) {

        // Check for blacklisting & auto-banning
        if ($blacklist_and_ban) {

          // Find the host and get its ID and expiry date.
          $hosts = HostQuery::loadHostsByIp($ip);

          // Get the host expire time (from httpbl).
          foreach ($hosts as $host) {
            $hostId = $host->hid->value;
            $expires = \Drupal::service('date.formatter')
              ->formatTimeDiffUntil($host->expire->value);
          }

          //Get BanManager service.
          $banManager = \Drupal::service('ban.ip_manager');

          //Is this IP now successfully banned?
          if ($banManager
            ->isBanned($ip)) {

            // Advise comment reviewer that this visiting host is now
            // blacklisted and banned, for some (configured) amount of time.
            $blocked_body .= t('<p><strong>@ip has now been blacklisted and auto-banned from future site visits for @time.</strong></p>', [
              '@ip' => $ip,
              '@time' => $expires,
            ]);
          }
          else {

            // Prepare a suggestion link for using httpbl to update and auto-ban
            // a previously blacklisted host that was not previously banned, or
            // they can just ban it.
            $blacklistUrl2 = Url::fromUri('internal:/admin/httpbl/host/' . $hostId . '/edit');
            $blacklistUrl2_options = [
              'attributes' => [
                'class' => [
                  'httpbl-comment-blocked',
                  'httpbl-comment-blocked-config',
                ],
                'target' => '_blank',
              ],
            ];
            $blacklistUrl2
              ->setOptions($blacklistUrl2_options);
            $blacklistLink2 = Link::fromTextAndUrl(t('updating'), $blacklistUrl2)
              ->toString();

            // Advise comment reviewer that this visiting host is already
            // blacklisted, but was not previously banned.
            $blocked_body .= t('<p><strong>@ip is already blacklisted on this site, but is not yet banned. Consider @banning it or @updating it.</strong></p>', [
              '@ip' => $ip,
              '@banning' => $banLink,
              '@updating' => $blacklistLink2,
            ]);
          }

          // Advise commenter they are history!
          drupal_set_message(t('Your address (@ip) has been blacklisted for @time.', [
            '@ip' => $ip,
            '@time' => $expires,
          ]), 'error', FALSE);
        }

        // Check for blacklisting storage only (no auto-banning configured).
        if ($blacklist_only) {

          // Advise comment review that blacklisting commenters alone will not
          // prevent future visits from the same nuisance IP, but they can ban it.
          $blocked_body .= t('<p><strong>@ip is blacklisted on this site, but neither auto-banning or page-checking are configured to prevent future site visits. Consider @banning it.</strong></p>', [
            '@ip' => $ip,
            '@banning' => $banLink,
          ]);
        }

        // No blacklisting or banning storage options configured.
        // Advise comment reviewer of this situation.
        if ($no_storage) {
          $blocked_body .= t('<p><strong>@ip is blacklisted on this site, but NO http:BL options are configured to prevent future site visits.</strong></p>', [
            '@ip' => $ip,
          ]);
        }

        // Log this (blacklisted) blocked comment.
        $logTrapper
          ->trapWarning('Blocked comment from blacklisted @ip.', [
          '@ip' => $ip,
        ]);
      }
      elseif ($evaluated[1] == HTTPBL_LIST_GREY) {

        // Advise comment reviewer of this situation.
        $blocked_body .= t('<p><strong>@ip is currently grey-listed on this site.  If @ip is becoming a repeated nuisance, then consider @blacklisting it.  In the meantime, the commenter was offered a challenge for session white-listing, if they pass. </strong></p>', [
          '@ip' => $ip,
          '@blacklisting' => $blacklistLink,
        ]);

        // Since commenter is only greylisted, offer them a  chance (a link)
        // to take the whitelist challenge.
        $whitelistUrl = Url::fromRoute('httpbl.whitelist_challenge_form');
        $whitelistUrl_options = [
          'attributes' => [
            'class' => [
              'httpbl-whitelist-message',
            ],
            'target' => '_blank',
          ],
        ];
        $whitelistUrl
          ->setOptions($whitelistUrl_options);
        $whitelistLink = Link::fromTextAndUrl(t('challenge'), $whitelistUrl)
          ->toString();
        drupal_set_message(t('You can become white-listed for your current session by passing this @challenge.', [
          '@challenge' => $whitelistLink,
        ]), 'warning', FALSE);

        // Log this (greylisted) blocked comment.
        $logTrapper
          ->trapNotice('Blocked comment from grey-listed @ip.', [
          '@ip' => $ip,
        ]);
      }

      // Add in original comment content, in case it wasn't that bad, even
      // though the host IP comes up dirty.
      $blocked_body .= t('<p><strong>Original subject:&nbsp;</strong>' . $original_subject . '</p>');
      $blocked_body .= t('<p><strong>Original comment below:</strong></p>');
      $blocked_body .= $original_body;

      // Force filter on this comment to full html to be sure we see the profile
      // link with its attributes.
      $comment_body = [
        'summary' => '',
        'value' => $blocked_body,
        'format' => 'full_html',
      ];

      // Set the altered comment.
      $comment
        ->set('comment_body', $comment_body);

      // Update statistics if configured.
      if (\Drupal::state()
        ->get('httpbl.stats')) {
        \Drupal::state()
          ->set('httpbl.stat_comment', \Drupal::state()
          ->get('httpbl.stat_comment') + 1);
      }
    }
  }
}