Your IP : 3.21.46.13


Current Path : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/landing/lib/
Upload File :
Current File : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/landing/lib/urlchecker.php

<?php
namespace Bitrix\Landing;

use Bitrix\Landing\Internals\UrlCheckerStatusTable;
use Bitrix\Landing\Internals\UrlCheckerWhitelistTable;
use Bitrix\Landing\Internals\UrlCheckerHostTable;
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Json;

/**
 * Class for check urls at external virus tools
 */
class UrlChecker
{
	private const EXTERNAL_CHECKER_URL_LOAD_URL = 'https://www.virustotal.com/api/v3/urls';
	private const EXTERNAL_CHECKER_URL_GET_ANALYSE = 'https://www.virustotal.com/api/v3/analyses/';

	private const STATUS_KEY_GOOD = 'harmless';
	private const STATUS_KEY_AVERAGE = 'suspicious';
	private const STATUS_KEY_BAD = 'malicious';

	private const AVERAGE_STATUS_PERCENT = 33;

	private $apiKey;
	private $hostUrl;

	/**
	 * UrlChecker constructor.
	 *
	 * @param string $apiKey Google Service api key.
	 * @param string|null $hostUrl External URL, where was checking and bad URL was detected.
	 */
	public function __construct(string $apiKey, ?string $hostUrl = null)
	{
		$this->apiKey = $apiKey;
		$this->hostUrl = $hostUrl;
		if ($this->hostUrl)
		{
			$this->hostUrl = mb_strtolower(trim($this->hostUrl));
		}
	}

	/**
	 * Checks passed url for some threats.
	 * Returns threat's status or null on no threats.
	 *
	 * @param string $url
	 * @return string|null
	 */
	protected function getUrlStatus(string $url): ?string
	{
		try
		{
			$http = new HttpClient;
			$http->setHeader('x-apikey', $this->apiKey);
			$res = Json::decode($http->post(self::EXTERNAL_CHECKER_URL_LOAD_URL, [
				'url' => $url,
			]));
			if (!isset($res['error']) && $res['data'] && $res['data']['id'])
			{
				$resAnalysis = Json::decode($http->get(self::EXTERNAL_CHECKER_URL_GET_ANALYSE . $res['data']['id']));
				if (isset($resAnalysis['error']))
				{
					// todo: set VT error
					return $res['error']['status'];
				}
				$stats = [
					self::STATUS_KEY_GOOD => $resAnalysis['data']['attributes']['stats'][self::STATUS_KEY_GOOD],
					self::STATUS_KEY_AVERAGE => $resAnalysis['data']['attributes']['stats'][self::STATUS_KEY_AVERAGE],
					self::STATUS_KEY_BAD => $resAnalysis['data']['attributes']['stats'][self::STATUS_KEY_BAD],
				];

				// check stats
				$total = $stats[self::STATUS_KEY_GOOD] + $stats[self::STATUS_KEY_AVERAGE] + $stats[self::STATUS_KEY_BAD];
				if (
					$stats[self::STATUS_KEY_BAD] === 0
					&& $stats[self::STATUS_KEY_AVERAGE] <= $total * self::AVERAGE_STATUS_PERCENT * 0.01
				)
				{
					return null;
				}

				return
					self::STATUS_KEY_GOOD . ':' . $stats[self::STATUS_KEY_GOOD]
					. '_' . self::STATUS_KEY_AVERAGE . ':' . $stats[self::STATUS_KEY_AVERAGE]
					. '_' . self::STATUS_KEY_BAD . ':' . $stats[self::STATUS_KEY_BAD];
			}
		}
		catch (\Exception $e){}

		return null;
	}

	/**
	 * Saves host for specified status.
	 *
	 * @param int $statusId Status id.
	 * @return void
	 */
	protected function saveHost(int $statusId): void
	{
		if (!$this->hostUrl)
		{
			return;
		}
		$res = UrlCheckerHostTable::getList([
			'select' => [
				'ID'
			],
			'filter' => [
				'STATUS_ID' => $statusId,
				'=HOST' => $this->hostUrl
			],
			'limit' => 1
		]);
		if (!$res->fetch())
		{
			UrlCheckerHostTable::add([
				'STATUS_ID' => $statusId,
				'HOST' => $this->hostUrl
			])->isSuccess();
		}
	}

	/**
	 * Checks passed url for some threats. Returns true on no threats.
	 * Before external checking check whitelist list and stored links.
	 *
	 * @param string $url
	 * @return bool
	 */
	public function check(string $url): bool
	{
		$url = mb_strtolower($url);
		$urlMd5 = md5(explode('//', $url)[1] ?? $url);
		$urlParts = parse_url($url);
		$domain = $urlParts['host'] ?? null;

		if (!$domain)
		{
			return true;
		}

		// check domain in white list
		$res = UrlCheckerWhitelistTable::getList([
			'filter' => [
				'=DOMAIN' => $domain
			],
			'limit' => 1
		]);
		if ($res->fetch())
		{
			return true;
		}

		// check exists url
		$res = UrlCheckerStatusTable::getList([
			'select' => [
				'ID', 'STATUS'
			],
			'filter' => [
				'=HASH' => $urlMd5
			]
		]);
		if ($row = $res->fetch())
		{
			if ($row['STATUS'])
			{
				$this->saveHost($row['ID']);
			}
			return !$row['STATUS'];
		}

		// new check
		$status = $this->getUrlStatus($url);
		$res = UrlCheckerStatusTable::add([
			'STATUS' => $status,
			'HASH' => $urlMd5,
			'URL' => $url
		]);
		// save host if status is bad
		if ($res->isSuccess() && $status)
		{
			$this->saveHost($res->getId());
		}

		return $status === null;
	}
}