Перейти к содержанию

Управление командой

Раздел описывает работу с пользователями трекера TrafMate: учётные записи, роли, разграничение доступа (ACL), API-ключи и восстановление пароля.

Пользователи

Управление пользователями доступно в разделе «Пользователи». Раздел виден только администраторам - и в интерфейсе, и в API: обращение не-админа к /api/v1/users отклоняется с кодом 403.

Каждая учётная запись содержит поля:

Поле Описание
Логин Уникальное имя для входа
Роль admin или user
Статус active (активна) или любое другое значение (вход закрыт)
Пароль Задаётся при создании; хранится в виде bcrypt-хеша

Войти может только учётная запись со статусом active. Пароль никогда не хранится и не отображается в открытом виде - в базе данных сохраняется только его bcrypt-хеш. Принимаются оба формата хеша ($2a$ и $2y$), поэтому пользователи, перенесённые из Keitaro, входят со своими прежними паролями.

Защищённые учётные записи

Отдельные учётные записи помечаются флагом protected. Такую запись нельзя:

  • удалить;
  • деактивировать (увести статус из active);
  • лишить роли admin.

Ограничение действует не только в интерфейсе, но и на уровне базы данных - через триггеры на DELETE, UPDATE и TRUNCATE. Это означает, что защищённую запись невозможно испортить даже прямым SQL-запросом в обход панели. Механизм защищает основной аккаунт владельца от случайной или ошибочной блокировки.

Аварийный выход предусмотрен и он один: сначала снять сам флаг (UPDATE users SET protected=false), и только потом удалять или менять запись.

Роли

В трекере две роли:

  • admin - полный доступ ко всем разделам, сущностям и настройкам без ограничений. Проверки прав администратор проходит всегда.
  • user (баер) - ограниченный доступ, определяемый настройками ACL.

Разграничение доступа (ACL)

Доступ баера ограничивают два независимых слоя. Чтобы баер увидел сущность, должны сработать оба: ему нужен и раздел, и группа, к которой сущность относится.

Слой 1. Доступ к разделам

Набор разделов пользователя определяет, какие пункты меню и какие адреса API ему доступны. Полный список разделов:

dashboard, campaigns, streams, offers, landings, domains, traffic_sources, affiliate_networks, geo_profiles, groups, reports, trends, clicks, conversions.

Если раздел не выдан, обращение к его адресам возвращает 403 с текстом «нет доступа к разделу».

Пустой набор разделов означает «не настроено» и даёт доступ ко всем разделам. Это сделано намеренно: у пользователя, созданного без настройки прав, иначе было бы пустое меню. Чтобы ограничить баера, нужно выдать ему непустое подмножество разделов - снятые галочки при пустом наборе ничего не ограничивают.

Слой 2. Изоляция по группам

Группы пользователя (раздел «Пользователи» -> карточка -> «Группы») определяют, какие конкретные сущности он видит. Правило зависит от типа сущности, и это не оплошность, а два разных сценария:

Сущность Что видит баер
Кампании, потоки Строго свои группы. Кампания без группы баеру не видна вовсе
Офферы, лендинги, домены, источники трафика Свои группы и общие (записи без группы)
Партнёрские сети, гео-профили Группы у сущности нет - доступ решает только раздел

Общие записи (без группы) видны всем не случайно: источники трафика на реальных установках часто заведены без группы, и без них у баера был бы пустой выпадающий список «Источник трафика». Менять общую запись по-прежнему может только администратор.

У потока собственной группы нет: поток принадлежит кампании и наследует её группу.

Что именно режется по группам

Изоляция применяется не только к спискам сущностей:

  • Кампании и потоки. Проверка стоит на маршруте, а не внутри обработчика: чтение, изменение, удаление, клонирование, смена состояния, порядок потоков, метки, домены кампании. Чужой id даёт 403 - тот же ответ, что и несуществующий id, чтобы перебором нельзя было выяснить, какие кампании существуют.
  • Отчёты. Каждый запрос статистики несёт ограничение по кампаниям групп пользователя: дашборд, отчёт по кликам, лог конверсий, лог кликов, тренды, лог постбеков, ручное обновление расхода. Чужие campaign_id в выдачу не попадают.
  • Файлы лендингов и офферов. Список файлов, чтение, сохранение, удаление, переименование, загрузка, выгрузка архивом, замена и предпросмотр проходят через одну общую проверку прав. Прочитать или переписать чужую связку по её id нельзя.
  • Правила постбеков. Баер работает только с правилами области campaign и только для своих кампаний. Глобальное правило (scope=global) - админское: такое правило шлёт копию каждой конверсии установки на указанный адрес.
  • Глобальный поиск. Ищет сразу по семи таблицам и применяет оба слоя: раздел и группу, по правилам того раздела, к которому относится сущность.

Пользователь без групп не видит ничего

Это ожидаемое поведение, а не поломка. Отказ по умолчанию означает:

  • списки кампаний и потоков пусты;
  • отчёты пусты (не «вся установка», а именно ноль строк);
  • глобальный поиск не находит ни кампаний, ни потоков.

Если баер жалуется, что «трекер пустой», первое, что нужно проверить, - выданы ли ему группы. Порядок настройки: сначала завести группу, разложить по ней кампании, затем выдать группу пользователю.

Что может и чего не может баер

Может (при выданных разделах и группах): вести свои кампании и потоки, заводить офферы и лендинги, править файлы своих лендингов, смотреть отчёты по своим кампаниям, настраивать S2S-постбеки своих кампаний, обновлять расход своих кампаний, создавать себе избранное, пользоваться поиском.

Не может ни при каких настройках ACL:

  • управлять пользователями, командами, метками, пользовательскими метриками, белым списком IP, триггерами и интеграциями - это админские сущности;
  • открывать глобальные настройки трекера и курсы валют;
  • смотреть журнал действий, диагностику системы и обновления;
  • работать с обслуживанием (объём статистики, срок хранения, очистка);
  • создавать и удалять API-ключи;
  • заводить глобальные правила постбеков;
  • менять общие (без группы) офферы, лендинги, домены и источники.

Отдельно стоит знать про два ограничения, которых у нас нет: уровня доступа «только чтение» и скрытия отдельных столбцов отчёта. Баер, которому выдан раздел «Отчёты», видит по своим кампаниям все метрики, включая расход, доход и ROI.

Поведение при нарушении

Обращение к недоступному разделу, к чужой группе или к административному адресу отклоняется с кодом 403 (Forbidden). Неавторизованный запрос - 401.

Управление доступом пользователя

Настройка выполняется в карточке пользователя. Администратор задаёт:

  • Разделы - к каким пунктам меню и адресам API есть доступ (GET/PUT /api/v1/users/{id}/resources);
  • Группы - какие группы сущностей видит пользователь (GET/PUT /api/v1/users/{id}/groups).

Обе настройки заменяют набор целиком, а не дополняют его. Изменения вступают в силу немедленно и распространяются на все обращения пользователя, включая доступ по его API-ключам.

API-ключи (Admin API)

API-ключи создаются в разделе «Настройки» -> карточка «API-ключи». Раздел доступен только администраторам - завести себе ключ баер не может.

Назначение

Ключ даёт доступ к REST API трекера. Формат ключа: префикс tm_ и hex-строка (например, tm_a1b2c3...).

Ключ передаётся в запросе одним из способов:

  • заголовок Api-Key: <ключ>;
  • заголовок Authorization: Bearer <ключ>.

Наследование прав (ACL)

API-ключ наследует права своего пользователя. Ключ не даёт больше доступа, чем есть у владельца:

  • ключ администратора имеет полный доступ;
  • ключ баера ограничен теми же разделами и группами, что и его учётная запись в панели.

Показ и хранение

Ключ показывается полностью только один раз - в момент создания. Скопируйте и сохраните его сразу. При последующих просмотрах ключ отображается в маскированном виде и восстановить его целиком нельзя. У ключа есть имя и отметка последнего использования - по ней видно, какой ключ давно не работает.

В базе ключ лежит открытым текстом. Практическое следствие: дамп конфигурации (trafmate backup-config) содержит рабочие ключи, поэтому бэкапы нужно хранить там же, где хранят пароли.

Отзыв

Чтобы отозвать доступ, удалите ключ. После удаления запросы с этим ключом перестают работать немедленно.

Защита от подбора пароля

Неудачные попытки входа считаются в двух счётчиках - по адресу обратившегося и по логину. При превышении лимита вход отвечает 429 и текстом «слишком много попыток входа, попробуйте через 15 минут». Успешный вход счётчики сбрасывает.

Требований к сложности пароля трекер не предъявляет: принимается любая непустая строка. Единственное исключение - сброс пароля из CLI, там пароль короче 8 символов не примут. Ответ на неверный вход одинаков для несуществующего логина и неверного пароля («неверный логин или пароль»), поэтому перебрать список логинов по ответу нельзя.

Восстановление пароля

Самостоятельного сброса пароля пользователем нет: письма с восстановлением трекер не шлёт. Есть два пути.

Обычный: администратор задаёт новый пароль

  1. Откройте раздел «Пользователи».
  2. Откройте карточку нужного пользователя.
  3. Задайте новый пароль и сохраните.

Новый пароль сохраняется в виде bcrypt-хеша и вступает в силу сразу.

Важно знать: ранее выданная сессия пользователя после смены пароля из панели продолжает жить (до 7 суток). Чтобы гарантированно выбить человека из панели, уведите его учётную запись из статуса active.

Аварийный: сброс пароля владельца через CLI

Если пароль потерял сам владелец и в панель войти некому, пароль сбрасывается на сервере командой:

trafmate reset-password [логин] [--password НОВЫЙ]

Как это работает:

  • логин можно не указывать - тогда берётся ADMIN_LOGIN из .env, а если его нет - admin;
  • --password можно не указывать - CLI сгенерирует случайный пароль из 20 символов и покажет его один раз;
  • пароль короче 8 символов команда не примет;
  • если такой пользователь есть, ему меняется только пароль и возвращается статус active. Роль не меняется: повысить баера до администратора сбросом пароля нельзя;
  • если такого логина нет, создаётся новая учётная запись с ролью admin;
  • все прежние сессии этого пользователя гасятся - в отличие от смены пароля из панели.

Команда требует запущенного Postgres. Хеш считается bcrypt-ом: сначала через контейнер lander, если он не поднят - через расширение pgcrypto в Postgres.