# Архитектура API Sync ## Обзор API Sync — однопроходная утилита (не демон), запускаемая по cron. При каждом запуске выполняет три последовательных этапа: синхронизацию данных из API в PostgreSQL, очистку устаревших записей и обновление whitelist-файла в Git-репозитории. --- ## Поток выполнения ``` main() │ ├─ 1. Подключение к PostgreSQL │ ├─ 2. Загрузка списка клиентов (client_info) │ ├─ 3. Сбор SID (apps_settings WHERE mode = 'auto') │ ├─ 4. Параллельная обработка SID (worker pool) │ └─ processSID() для каждого SID │ ├─ GET /l7/resource/{sid}/global → whois │ ├─ GET /l7/origin/global?l7ResourceId={sid} → origins │ ├─ GET /l7/alias/global?l7ResourceId={sid} → aliases │ ├─ DNS резолв домена → проверка AntiDDOS │ └─ upsertAPIInfo() → сравнение + запись в API_info + алерты │ ├─ 5. Очистка устаревших SID из API_info (cleanupRemovedSIDs) │ └─ 6. Обновление WAF whitelist (updateWAFWhitelist) ├─ git pull ├─ Загрузка IP из API_info (auto) ├─ Загрузка IP из manual_info (ручные) ├─ Фильтрация WAF-сетей (таблица ips) ├─ Сравнение с текущим whitelist-файлом ├─ Запись файла + git commit + git push └─ Отправка алерта об изменениях ``` --- ## Модули ### main.go — точка входа и worker pool Инициализирует подключение к БД, собирает все SID для обработки и запускает пул горутин. Количество воркеров задаётся через `MAX_CONCURRENT_WORKERS` (по умолчанию 5). SID передаются воркерам через буферизированный канал. После завершения всех воркеров последовательно запускаются очистка устаревших записей и обновление whitelist. ### config.go — конфигурация Загружает переменные окружения из `/etc/API_sync/API_sync.env` через `godotenv`. Если файл недоступен — использует системные переменные окружения. Все переменные инициализируются в `init()` до старта `main()`. ### api.go — HTTP-клиент и структуры API Содержит единственный HTTP-клиент с таймаутом 20 секунд и функцию `apiGet()`, которая выполняет GET-запрос к API API с Bearer-авторизацией и десериализует JSON-ответ в переданную структуру. Определены структуры ответов API: `originItem`, `aliasItem`, `whoisReAPIonse`, `apiList`. ### database.go — работа с PostgreSQL **`loadClients()`** — загружает список клиентов из `client_info`. **`loadL7IDs()`** — загружает SID из `apps_settings` для конкретного клиента с `mode = 'auto'`. **`processSID()`** — оркестрирует обработку одного SID: делает три запроса к API, резолвит домен для проверки AntiDDOS, вызывает `upsertAPIInfo()`. **`upsertAPIInfo()`** — сравнивает новые данные со старыми из БД и при наличии изменений формирует алерты: - изменение домена → алерт + флаг необходимости обновления PT AF - изменение origins (IP, mode, weight) — через `compareOrigins()` - изменение aliases — через `compareAliases()` - изменение WAF-настроек (vendor, instance, enabled) — отдельный алерт Сохранение выполняется через `INSERT ... ON CONFLICT DO UPDATE` (upsert по `sid`). **`cleanupRemovedSIDs()`** — сравнивает все SID в `API_info` с актуальным списком активных SID. Записи, которых нет в активном списке (ресурс удалён из `apps_settings` или сменил `mode`), удаляются из `API_info`. По каждому удалённому ресурсу отправляется алерт с указанием WAF-вендора (берётся из `apps_settings` через LEFT JOIN). **`wafVendorWarning()`** — формирует строку предупреждения в зависимости от вендора: `ptaf` → PT AF, `sw` → SW, `wmx` → WMX. ### compare.go — функции сравнения **`compareOrigins()`** — сравнивает два списка origins по IP-адресу. Определяет добавленные, удалённые и изменённые (mode/weight) записи. Возвращает отформатированную строку для алерта с текущим состоянием origins. **`compareAliases()`** — сравнивает два отсортированных списка доменов. Возвращает строку с изменениями и булев флаг наличия изменений. ### dns.go — DNS-резолвер Функция `resolveDomain()` возвращает первый IPv4-адрес для заданного домена. Используется в `processSID()` для проверки AntiDDOS: если resolvedIP совпадает с protectedIP из API — AntiDDOS активен. ### notify.go — система уведомлений **`sendAlert()`** — единая точка отправки алертов. Последовательно отправляет сообщение во все настроенные каналы. Ошибка одного канала не блокирует остальные. **Telegram** — `buildTelegramClient()` при каждой отправке выбирает транспорт в порядке приоритета: 1. HTTP-прокси (`TELEGRAM_HTTP_PROXY`) — если задан и доступен 2. SOCKS5-прокси (`TELEGRAM_SOCKS5_PROXY`) — если задан и доступен 3. Прямое подключение — fallback Доступность проверяется реальным GET-запросом на `api.telegram.org`. Сообщения отправляются в формате HTML (`parse_mode: HTML`). **Mattermost** — POST на `/api/v4/posts` с Bearer-токеном. HTML-теги Telegram конвертируются в Markdown через `htmlToMarkdown()`. Отправляется только если заполнены все три переменные: `MATTERMOST_URL`, `MATTERMOST_BOT_TOKEN`, `MATTERMOST_CHANNEL_ID`. **Email** — через стандартный `net/smtp`. Поддерживает несколько адресов получателей через запятую в `EMAIL_TO`. Авторизация опциональна — если `EMAIL_SMTP_USER` пуст, отправка идёт без аутентификации (relay). HTML-теги Telegram удаляются через `stripHTMLTags()`. Отправляется только если заполнены `EMAIL_SMTP_HOST`, `EMAIL_FROM`, `EMAIL_TO`. ### git.go — Git-операции **`syncGitRepo()`** — если репозиторий не существует локально — клонирует (`git clone`), иначе обновляет (`git pull`). Автоматически настраивает `user.email` и `user.name` для коммитов. **`gitCommitAndPush()`** — выполняет `git add `, `git commit -m `, `git push`. Если нечего коммитить (`nothing to commit`) — завершается без ошибки. ### whitelist.go — управление whitelist **`updateWAFWhitelist()`** — основная функция обновления whitelist: 1. Синхронизирует Git-репозиторий 2. Загружает WAF-сети из таблицы `ips` 3. Загружает origin IP из `API_info` (`loadAllOrigins`) и `manual_info` (`loadManualOrigins`), объединяет и дедуплицирует 4. Фильтрует IP попадающие в WAF-сети (`filterNonWAFOrigins`) 5. Сравнивает с текущим содержимым файла (`compareWhitelists`) 6. При наличии изменений — перезаписывает файл, коммитит и пушит, отправляет алерт **`loadManualOrigins()`** — загружает все записи из `manual_info` как есть, без дополнительных условий. Таблица заполняется администратором вручную и программой не изменяется. **`filterNonWAFOrigins()`** — исключает из списка IP-адреса, которые принадлежат WAF-сетям из таблицы `ips`. Такие адреса являются узлами самого WAF и не должны попадать в whitelist. --- ## Алерты Все алерты отправляются через единую функцию `sendAlert()`. Типы алертов: | Событие | Содержание | |---|---| | Изменение origins | Добавленные/удалённые/изменённые backend IP + текущее состояние | | Изменение aliases | Добавленные/удалённые домены | | Изменение домена | Старое и новое значение + предупреждение об обновлении WAF | | Изменение WAF-настроек | Изменения waf_enabled, waf_vendor, waf_instance | | Удаление ресурса | SID, домен, предупреждение с указанием конкретного WAF-вендора | | Обновление whitelist | Добавленные/удалённые IP с привязкой к SID и домену, итоговое количество | --- ## Зависимости | Пакет | Назначение | |---|---| | `github.com/lib/pq` | PostgreSQL драйвер | | `github.com/joho/godotenv` | Загрузка `.env` файла | | `golang.org/x/net` | SOCKS5 прокси для Telegram | | `net/smtp` | Отправка email (стандартная библиотека) |