FetchIt 4.0.0 - один пакет для MODX 2 и 3 и защита от спама из коробки
Долгожданное обновление: три года компонент почти не развивался, и это было заметно. В четвёртой версии — один пакет для MODX 2.8 и MODX 3, защита от спама из коробки, закрытые уязвимости и новые примеры в документации.
Привет форум!
Последний раз я писал про FetchIt в 2023 году, когда вышла версия 3.0.0-pl для MODX 3. С тех пор компонент жил двумя линиями: 1.* для MODX 2 и 3.* для MODX 3. Работал, но почти не развивался. Этим летом я наконец-то за него взялся, и в итоге вышла версия 4.0.0. Ниже рассказываю, что к ней привело и что изменилось.

Сначала накопились баги. На PHP 8.3 формы падали с фатальной ошибкой Serialization of 'PDO' is not allowed, сообщения об успешной отправке через AJAX не показывались, на PHP 8 сыпались предупреждения про $_SESSION. Тут очень помог @Иван Бочкарев: прислал исправления для обеих веток и настроил выпуск релизов через GitHub Actions. Так вышли 1.1.3 и 3.1.4.
Потом на форуме появилась статья про спам в формах AjaxForm и FetchIt. Суть простая: бот один раз открывает страницу, а дальше сколько угодно шлёт запросы прямо в action.php. Меня спросили, решает ли это FetchIt на MODX 2.8. Честно? Нет, не решал.
Иван предложил отправлять с формой токен, сразу для обеих веток. Пока я это ревьюил, вылезло несколько неприятных вещей. На сайтах без анонимных сессий формы с защитой просто переставали работать. А отказ из плагина через return false на самом деле ничего не отменял, MODX его только записывал в журнал. Стало понятно, что защиту надо делать по-другому. И делать её два раза, отдельно для 1.x и для 3.x, мне совсем не хотелось.
Так и появилась четвёртая версия: один пакет для MODX 2.8 и MODX 3 и защита от спама, которая включена по умолчанию.
FetchIt 4 ставится и на MODX 2.8, и на MODX 3. Поверх 1.x на MODX 2 и поверх 3.x на MODX 3 он встаёт обычным обновлением через Менеджер пакетов, системные настройки и чанки остаются как есть. Вызовы сниппета на страницах менять не нужно.
Прежний API работает на обеих версиях. В своих сниппетах теперь проще всего брать FetchIt так:
И ещё одна вещь, которая раньше раздражала: на MODX 3 FormIt не ставился вместе с FetchIt. Теперь ставится, а если скачать его не получилось, установщик прямо напишет почему.
Это главное в релизе. Каждая форма FetchIt теперь защищена без всякой настройки, причём и при отправке через FetchIt, и при обычной отправке без JavaScript. Проверки проходят до FormIt или вашего сниппета:
Первый это proof-of-work: перед отправкой браузер решает небольшую задачку на SHA-256. Считать он начинает, как только посетитель зашёл в форму, так что к нажатию кнопки всё обычно уже готово. А вот боту каждая отправка стоит процессорного времени. При 16 битах компьютеру нужно около трети секунды, телефону в несколько раз больше.
Второй это капча: Cloudflare Turnstile, Google reCAPTCHA v3 или Яндекс SmartCaptcha. Выбираете сервис в fetchit.captcha, указываете два ключа, а скрипт сервиса FetchIt подключит сам. Ответ капчи проверяется на сервере последним, так что боты без токена до сервиса даже не доходят.
Заодно я закрыл две уязвимости, из-за которых форму FetchIt можно было обработать в обход проверок. Подробности есть в changelog. Если FetchIt стоит у вас на сайте с важными формами, обновиться стоит в любом случае.
Раньше настройка fetchit.frontend.default.notifier подключала библиотеку Notyf. Теперь у FetchIt свои уведомления, и без лишних файлов:



Документацию тоже перебрал. Примеры уведомлений и модальных окон переписал под четвёртую версию, а заброшенные библиотеки (NOTY, toastr, iziToast, tingle.js и другие) убрал. Добавил раздел готовых сценариев: индикатор отправки, благодарность вместо формы, редирект, маска телефона, загрузка файлов, цели в Метрике и GA4, заявки в Telegram. Модальных окон стало больше: нативные dialog и popover, a11y-dialog, UIkit и Fancybox. А для проверки полей теперь есть примеры на Zod, Valibot, validator.js и силами самого браузера, без библиотек. Код можно брать как есть.
Все подробности про настройки, события и переход с прошлых версий есть в README на GitHub. Если после обновления что-то сломалось или спам всё равно пролезает, пишите в комментариях или создавайте issue.
Отдельное спасибо @Иван Бочкарев за помощь с обеими ветками.
Спасибо всем за внимание и мира над головой.
Привет форум!
Последний раз я писал про FetchIt в 2023 году, когда вышла версия 3.0.0-pl для MODX 3. С тех пор компонент жил двумя линиями: 1.* для MODX 2 и 3.* для MODX 3. Работал, но почти не развивался. Этим летом я наконец-то за него взялся, и в итоге вышла версия 4.0.0. Ниже рассказываю, что к ней привело и что изменилось.

С чего всё началось
Сначала накопились баги. На PHP 8.3 формы падали с фатальной ошибкой Serialization of 'PDO' is not allowed, сообщения об успешной отправке через AJAX не показывались, на PHP 8 сыпались предупреждения про $_SESSION. Тут очень помог @Иван Бочкарев: прислал исправления для обеих веток и настроил выпуск релизов через GitHub Actions. Так вышли 1.1.3 и 3.1.4.
Потом на форуме появилась статья про спам в формах AjaxForm и FetchIt. Суть простая: бот один раз открывает страницу, а дальше сколько угодно шлёт запросы прямо в action.php. Меня спросили, решает ли это FetchIt на MODX 2.8. Честно? Нет, не решал.
Иван предложил отправлять с формой токен, сразу для обеих веток. Пока я это ревьюил, вылезло несколько неприятных вещей. На сайтах без анонимных сессий формы с защитой просто переставали работать. А отказ из плагина через return false на самом деле ничего не отменял, MODX его только записывал в журнал. Стало понятно, что защиту надо делать по-другому. И делать её два раза, отдельно для 1.x и для 3.x, мне совсем не хотелось.
Так и появилась четвёртая версия: один пакет для MODX 2.8 и MODX 3 и защита от спама, которая включена по умолчанию.
Один пакет вместо двух
FetchIt 4 ставится и на MODX 2.8, и на MODX 3. Поверх 1.x на MODX 2 и поверх 3.x на MODX 3 он встаёт обычным обновлением через Менеджер пакетов, системные настройки и чанки остаются как есть. Вызовы сниппета на страницах менять не нужно.
Прежний API работает на обеих версиях. В своих сниппетах теперь проще всего брать FetchIt так:
$FetchIt = FetchIt::service($modx);Вызовы из 1.x ($modx->getService(...)) и из 3.x ($modx->services->get('FetchIt')) возвращают тот же объект, класс FetchIt\FetchIt тоже на месте. Чанки на Fenom и через @FILE работают через pdoTools на обеих версиях.
И ещё одна вещь, которая раньше раздражала: на MODX 3 FormIt не ставился вместе с FetchIt. Теперь ставится, а если скачать его не получилось, установщик прямо напишет почему.
Защита от спама
Это главное в релизе. Каждая форма FetchIt теперь защищена без всякой настройки, причём и при отправке через FetchIt, и при обычной отправке без JavaScript. Проверки проходят до FormIt или вашего сниппета:
- Одноразовый токен. В форму добавляется скрытое поле fetchit_token с подписью. Сессия для него не нужна, так что сайты без анонимных сессий тоже работают. Следующий токен приходит в ответе, поэтому форму можно отправлять повторно без перезагрузки.
- Время заполнения. Форма, отправленная быстрее чем через 3 секунды после вывода страницы, отклоняется. Человек, который исправил поле после ошибки, отказ не получит: время считается от того же вывода.
- Ловушка. Скрытое поле со случайным для каждой установки именем. Бот, который его заполнил, получает «успех», но форма не обрабатывается и письмо никуда не уходит.
- Лимит. По умолчанию не больше 10 отправок одной формы с одного адреса за 10 минут. Если сайт за прокси или CDN, укажите их адреса и заголовок с IP посетителя, иначе лимит станет общим на весь сайт.
Proof-of-work и капча
Если спам всё равно проходит, есть ещё два уровня. Оба выключены по умолчанию.Первый это proof-of-work: перед отправкой браузер решает небольшую задачку на SHA-256. Считать он начинает, как только посетитель зашёл в форму, так что к нажатию кнопки всё обычно уже готово. А вот боту каждая отправка стоит процессорного времени. При 16 битах компьютеру нужно около трети секунды, телефону в несколько раз больше.
Второй это капча: Cloudflare Turnstile, Google reCAPTCHA v3 или Яндекс SmartCaptcha. Выбираете сервис в fetchit.captcha, указываете два ключа, а скрипт сервиса FetchIt подключит сам. Ответ капчи проверяется на сервере последним, так что боты без токена до сервиса даже не доходят.
Свои правила
Появилось событие OnFetchItBeforeProcess. Плагин получает поля формы и может отклонить отправку:// Плагин на событие OnFetchItBeforeProcess
$email = isset($fields['email']) && is_string($fields['email']) ? $fields['email'] : '';
if (preg_match('/@(mailinator|tempmail)\./i', $email)) {
$modx->event->output('Одноразовые адреса не принимаются.');
}Обратите внимание: отклоняет именно $modx->event->output(). Строку из return MODX только запишет в журнал. Как раз на этом споткнулась первая версия защиты.Безопасность
Заодно я закрыл две уязвимости, из-за которых форму FetchIt можно было обработать в обход проверок. Подробности есть в changelog. Если FetchIt стоит у вас на сайте с важными формами, обновиться стоит в любом случае.
Свои уведомления вместо Notyf
Раньше настройка fetchit.frontend.default.notifier подключала библиотеку Notyf. Теперь у FetchIt свои уведомления, и без лишних файлов:

- Программы экранного доступа их зачитывают: ошибку сразу, успех в свою очередь.
- Пока на уведомлении курсор или фокус, оно не закрывается.
- Одновременно видно не больше трёх.
- Цвета задаются CSS-переменными, по умолчанию это пастельные зелёный и красный из Tailwind CSS 4.
- Если на сайте Content-Security-Policy, стили берут nonce скрипта FetchIt.


Скрипт
- Собирается в синтаксис ES2019, так что работает во всех актуальных браузерах. Минифицированная версия весит около 7 КБ в gzip.
- Рядом со скриптом лежат типы для TypeScript, fetchit.d.ts: FetchIt, экземпляры форм и detail каждого события.
- Раньше при сбое сети или чужом ответе (страница с ошибкой PHP, JSON от файрвола) ошибка уходила только в консоль, и посетитель ничего не видел. Теперь он получает сообщение, а fetchit:error срабатывает и в этом случае.
- fetchit:success можно отменить, тогда поля останутся заполненными.
- Повторное нажатие, пока идёт запрос, игнорируется, а два одинаковых вызова сниппета на странице больше не отправляют форму дважды.
Что ещё исправлено
- Форма без JavaScript не показывала сообщение об успехе или ошибке, если в чанке стояли фильтры на плейсхолдерах FormIt. Да, как в чанке-примере.
- Скрипт не подключался на сайтах без анонимных сессий и когда тег head был с атрибутами или написан заглавными.
- Поля, отключённые в разметке, после отправки становились активными.
- Несуществующий набор параметров сниппета ронял action.php на PHP 8.
Что может задеть при обновлении
- В форму добавляются служебные поля защиты. Если у вас свой JS вместо встроенного скрипта, он должен отправлять fetchit_token и брать следующий токен из заголовка X-FetchIt-Token.
- Notyf больше не подключается. Стили для .notyf__toast и вызовы new Notyf() придётся поменять или подключить Notyf самим.
- Обрабатывающий сниппет получает только отправленную форму: $_POST и файлы, без GET-параметров и cookies.
- fetchit:error срабатывает и при сбое запроса, тогда detail.response равен null.
- Сниппет и плагин FetchIt при обновлении заменяются, так что правки в их коде пропадут.
Примеры в документации
Документацию тоже перебрал. Примеры уведомлений и модальных окон переписал под четвёртую версию, а заброшенные библиотеки (NOTY, toastr, iziToast, tingle.js и другие) убрал. Добавил раздел готовых сценариев: индикатор отправки, благодарность вместо формы, редирект, маска телефона, загрузка файлов, цели в Метрике и GA4, заявки в Telegram. Модальных окон стало больше: нативные dialog и popover, a11y-dialog, UIkit и Fancybox. А для проверки полей теперь есть примеры на Zod, Valibot, validator.js и силами самого браузера, без библиотек. Код можно брать как есть.
Требования
- MODX 2.8 или MODX 3.
- PHP 7.4+.
- FormIt, если формы обрабатывает он. Ставится вместе с FetchIt.
- pdoTools, если чанки на Fenom или в файлах.
Заключение
Все подробности про настройки, события и переход с прошлых версий есть в README на GitHub. Если после обновления что-то сломалось или спам всё равно пролезает, пишите в комментариях или создавайте issue.
Отдельное спасибо @Иван Бочкарев за помощь с обеими ветками.
Спасибо всем за внимание и мира над головой.
Техническая поддержка MODX
Сайт лежит, тормозит или остался без разработчика?
Переезд с MODX 2 на 3, PHP 7 на 8, скорость и безопасность. Поддержка со сроками и ответственностью, а не совет в чате.
Подробнее
Реклама
0
Комментарии: 0