<commit_before><?php

namespace wcf\data\blacklist\entry;

use wcf\data\DatabaseObject;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\WCF;
use wcf\util\UserUtil;

/**
 * Represents a blacklist entry.
 *
 * @author      <NAME>
 * @copyright   2001-2019 WoltLab GmbH
 * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package     WoltLabSuite\Core\Data\Blacklist\Entry
 *
 * @property-read string $type One of 'email', 'ipv4', 'ipv6' or 'username'
 * @property-read string $hash SHA256 hash of the original value
 * @property-read int $lastSeen Timestamp of the last report, derivation is up to 24hrs
 * @property-read int $occurrences Number of times this value was reported, capped at 32,767
 * @since 5.2
 */
class BlacklistEntry extends DatabaseObject
{
    /**
     * @param string $username
     * @param string $email
     * @param string $ipAddress
     * @return string[]
     */
    public static function getMatches($username, $email, $ipAddress)
    {
        if (BLACKLIST_SFS_USERNAME === 'skip' && BLACKLIST_SFS_EMAIL_ADDRESS === 'skip' && BLACKLIST_SFS_IP_ADDRESS === 'skip') {
            return [];
        }

        $conditions = new PreparedStatementConditionBuilder(true, 'OR');
        if (BLACKLIST_SFS_USERNAME) {
            $conditions->add('(type = ? AND hash = ?)', ['username', self::getHash($username)]);
        }
        if (BLACKLIST_SFS_EMAIL_ADDRESS) {
            $conditions->add('(type = ? AND hash = ?)', ['email', self::getHash($email)]);
        }
        if (BLACKLIST_SFS_IP_ADDRESS) {
            $ipAddress = UserUtil::convertIPv6To4($ipAddress);
            if ($ipAddress) {
                if (\filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) !== false) {
                    $conditions->add('(type = ? AND hash = ?)', ['ipv4', self::getHash($ipAddress)]);
                } else {
                    $parts = \explode(':', $ipAddress);

                    // StopForumSpam uses the first two to four segments of an IPv6 address.
                    $ipv6TwoParts = self::getHash("{$parts[0]}:{$parts[1]}::");
                    $ipv6ThreeParts = self::getHash("{$parts[0]}:{$parts[1]}:{$parts[2]}::");

                    // If the enviorment is locally avaiable via IPv6, the ip address can be `::1`. Therefore
                    // we must check, if the third part is set. If not, we use the IPv6 with three parts
                    // again, to simplify the code.
                    // See: https://github.com/WoltLab/WCF/issues/4689
                    if (isset($parts[3])) {
                        $ipv6FourParts = self::getHash("{$parts[0]}:{$parts[1]}:{$parts[2]}:{$parts[3]}::");
                    } else {
                        $ipv6FourParts = self::getHash("{$parts[0]}:{$parts[1]}:{$parts[2]}::");
                    }

                    $conditions->add(
                        '(type = ? AND hash IN (?))',
                        ['ipv6', [$ipv6TwoParts, $ipv6ThreeParts, $ipv6FourParts]]
                    );
                }
            }
        }

        $sql = "SELECT  type, occurrences
                FROM    wcf" . WCF_N . "_blacklist_entry
                " . $conditions;
        $statement = WCF::getDB()->prepareStatement($sql);
        $statement->execute($conditions->getParameters());
        $matches = [];
        while ($row = $statement->fetchArray()) {
            if (self::isMatch($row['type'], $row['occurrences'])) {
                $matches[] = ($row['type'] === 'ipv4' || $row['type'] === 'ipv6') ? 'ip' : $row['type'];
            }
        }

        return $matches;
    }

    protected static function getHash($string)<commit_msg>Use internal class to mask IP addresses<commit_after><?php

namespace wcf\data\blacklist\entry;

use wcf\data\DatabaseObject;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\WCF;
use wcf\util\IpAddress;
use wcf\util\UserUtil;

/**
 * Represents a blacklist entry.
 *
 * @author      <NAME>
 * @copyright   2001-2019 WoltLab GmbH
 * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package     WoltLabSuite\Core\Data\Blacklist\Entry
 *
 * @property-read string $type One of 'email', 'ipv4', 'ipv6' or 'username'
 * @property-read string $hash SHA256 hash of the original value
 * @property-read int $lastSeen Timestamp of the last report, derivation is up to 24hrs
 * @property-read int $occurrences Number of times this value was reported, capped at 32,767
 * @since 5.2
 */
class BlacklistEntry extends DatabaseObject
{
    /**
     * @param string $username
     * @param string $email
     * @param string $ipAddress
     * @return string[]
     */
    public static function getMatches($username, $email, $ipAddress)
    {
        if (BLACKLIST_SFS_USERNAME === 'skip' && BLACKLIST_SFS_EMAIL_ADDRESS === 'skip' && BLACKLIST_SFS_IP_ADDRESS === 'skip') {
            return [];
        }

        $conditions = new PreparedStatementConditionBuilder(true, 'OR');
        if (BLACKLIST_SFS_USERNAME) {
            $conditions->add('(type = ? AND hash = ?)', ['username', self::getHash($username)]);
        }
        if (BLACKLIST_SFS_EMAIL_ADDRESS) {
            $conditions->add('(type = ? AND hash = ?)', ['email', self::getHash($email)]);
        }
        if (BLACKLIST_SFS_IP_ADDRESS) {
            if ($ipAddress) {
                $ipAddress = new IpAddress($ipAddress);
                if (($ipv4 = $ipAddress->asV4()) !== null) {
                    $conditions->add('(type = ? AND hash = ?)', ['ipv4', self::getHash($ipv4->getIpAddress())]);
                } else {
                    // StopForumSpam uses the first two to four segments of an IPv6 address.
                    $ipv6TwoParts = $ipAddress->toMasked(32, 32)->getIpAddress();
                    $ipv6ThreeParts = $ipAddress->toMasked(32, 48)->getIpAddress();
                    $ipv6FourParts = $ipAddress->toMasked(32, 64)->getIpAddress();

                    $conditions->add(
                        '(type = ? AND hash IN (?))',
                        ['ipv6', [$ipv6TwoParts, $ipv6ThreeParts, $ipv6FourParts]]
                    );
                }
            }
        }

        $sql = "SELECT  type, occurrences
                FROM    wcf" . WCF_N . "_blacklist_entry
                " . $conditions;
        $statement = WCF::getDB()->prepareStatement($sql);
        $statement->execute($conditions->getParameters());
        $matches = [];
        while ($row = $statement->fetchArray()) {
            if (self::isMatch($row['type'], $row['occurrences'])) {
                $matches[] = ($row['type'] === 'ipv4' || $row['type'] === 'ipv6') ? 'ip' : $row['type'];
            }
        }

        return $matches;
    }

    protected static function getHash($string)
{'fraction_non_alphanumeric': 0.1495937318630296, 'fraction_numerical': 0.015235055136390018, 'mean_word_length': 2.2075383899488132, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 31, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '984038', 'n_tokens_mistral': 2124, 'n_tokens_neox': 2018, 'n_words': 458}