""" Проверка внешних скриптов, собирающих данные пользователей. Google Analytics, Facebook Pixel, Яндекс.Метрика и другие — отправляют данные на сервера за пределами РФ. """ from __future__ import annotations import re from playwright.async_api import Page from scanner.checks.base import BaseCheck from scanner.models import CheckResult, RiskLevel class ExternalScriptsCheck(BaseCheck): """Проверяет наличие внешних скриптов, передающих данные за пределы РФ.""" name = "external_scripts" title = "Внешние скрипты аналитики" description = "Ищет скрипты Google Analytics, Facebook Pixel и другие иностранные сервисы" risk_on_fail = RiskLevel.HIGH default_weight = 15 EXTERNAL_PATTERNS = [ r"google-analytics\.com", r"googletagmanager\.com", r"googlesyndication\.com", r"googleadservices\.com", r"googleapis\.com", r"google\.com/recaptcha", r"facebook\.com/tr", r"fbcdn\.net", r"connect\.facebook\.net", r"mc\.yandex\.ru", r"monitoring\.yandex\.ru", r"top\.mail\.ru", r"clarity\.microsoft\.com", r"hotjar\.com", r"mixpanel\.com", r"segment\.com", r"amplitude\.com", r"zendesk\.com", r"intercom\.io", r"chatra\.com", r"tilda\.cdn", r"wix\.com", r"wordpress\.com", r"shopify\.com", ] async def check(self, page: Page, url: str) -> CheckResult: try: html = await page.evaluate("() => document.documentElement.outerHTML") found_scripts = [] for pattern in self.EXTERNAL_PATTERNS: matches = re.findall(pattern, html, re.IGNORECASE) if matches: found_scripts.append({ "pattern": pattern, "matches": len(matches), }) if not found_scripts: return self._pass_result( message="Внешние скрипты аналитики не найдены.", ) critical_services = [ "google-analytics", "googletagmanager", "facebook", "clarity", "segment", "amplitude", ] has_critical = False for script in found_scripts: if any(re.search(c, script["pattern"]) for c in critical_services): has_critical = True break if has_critical: return self._fail_result( message=( f"Найдены внешние скрипты передачи данных: " f"{', '.join(s['pattern'] for s in found_scripts)}. " f"Они передают персональные данные за пределы РФ." ), details={ "scripts_found": found_scripts, "has_critical": True, }, ) return self._fail_result( message=( f"Найдены внешние скрипты: " f"{', '.join(s['pattern'] for s in found_scripts)}. " f"Требуется согласие пользователя." ), details={ "scripts_found": found_scripts, "has_critical": False, }, ) except Exception as e: return self._error_result(message=f"Ошибка: {str(e)}")