Files
ipwhitelist-app/docs/history/session-2026-06-22-export-impersonation.md
T

5.1 KiB
Raw Blame History

Сессия 2026-06-22 — export view=2, фикс имперсонации, TZ аудит

Версии

  • 0.1.1 — сброс версии с 0.5.180
  • 0.1.2white-space: pre на <code> (пробелы схлопывались)
  • 0.1.3 — таблица без точек, октеты в своих <td>
  • 0.1.4text-align: right в ячейках
  • 0.1.5padStart(2) плотнее (один пробел, не два)
  • 0.1.6 — фикс детекции имперсонации
  • 0.1.7 — аудит: время Москвы вместо UTC

1. Export view=2 — HTML-таблица с выровненными IP

Устройство

Файл: v2/src/export/index.js

Три режима:

Параметр Content-Type Поведение
(нет) text/plain Скачивание .txt
?view=1 text/plain Inline в браузере
?view=2 text/html Таблица: 4 ячейки октетов + маска

Структура view=2

<table>
  <tr>
    <td> 62</td><td> 76</td><td> 39</td><td>  5</td><td> / 32</td>
  </tr>
</table>
  • Каждый октет в своей <td>, без точек
  • padStart(2, ' ') — минимум 2 символа на октет
  • text-align: right — выравнивание по правой границе
  • white-space: pre — пробелы не схлопываются
  • Границы не видны (border-collapse: collapse, без border на td)

2. Фикс имперсонации — БАГ

Симптом

На странице /v2/app не показывался баннер «Режим имперсонации», хотя IAM API возвращал is_impersonated: true.

Причина

В двух местах v2/src/router/index.js проверка имперсонации использовала u.impersonatedCompanyId:

// checkImpersonation — строка 78 (было)
const oldIsImp = !!(u.originalUserEmail && u.impersonatedCompanyId);

// applyContext — строка 133 (было)
const isImpersonated = !!(u.originalUserEmail && u.impersonatedCompanyId);

Поле impersonatedCompanyId отсутствует в ответе IAM. IAM /auth/user возвращает:

{
  "impersonation": {
    "is_impersonated": true,
    "impersonatedUserId": "...",
    "originalUserEmail": "ntazetdinov@nubes.ru",
    "originalUserFullName": "...",
    "originalUserCompany": "...",
    "sessionId": 613,
    ...
    // ⚠️ impersonatedCompanyId — НЕТ
  }
}

Из-за этого:

  • u.impersonatedCompanyId всегда '' (пустая строка = falsy)
  • !!(truthy && falsy) → всегда false
  • Баннер не показывался
  • checkImpersonation на каждый запрос заново дёргал IAM (думал что статус изменился)

Исправление

Заменить проверку на u.isImpersonated (которое корректно выставляется в checkImpersonation):

// checkImpersonation (исправлено)
const oldIsImp = !!u.isImpersonated;

// applyContext (исправлено)
const isImpersonated = !!(u.isImpersonated || u.originalUserEmail);

3. Время в аудите — UTC → MSK

Файл: views/v2/admin-audit.ejs, строка 100.

// Было (возвращает серверное время = UTC):
new Date(a.created_at).toLocaleString('ru')

// Стало (Москва, UTC+3):
new Date(a.created_at).toLocaleString('ru-RU', { timeZone: 'Europe/Moscow' })

4. Проверка IAM API

Три эндпоинта, проверены через Node.js с IAM-токеном (iss: auth-api):

Эндпоинт Статус Результат
auth-api /auth/user 200 Полные данные + имперсонация
lk-api-gateway /iam/auth/user 200 Идентично auth-api
auth-api /impersonation/status 200 is_impersonating, session_id, etc.

Данные между auth-api и lk-api-gateway совпадают поле-в-поле.

Важно: токены

  • Keycloak-токен (iss: auth.k8s.ngcloud.ru) → IAM возвращает 401 (не может проверить подпись)
  • IAM-токен (iss: auth-api) → работает
  • Tech-токен (8541 символ) → nginx 400 (превышен лимит заголовка 8KB)
  • Для проверки API нужен IAM-токен из активной сессии

5. Админ при имперсонации

tazet@narod.ru показывается как админ, потому что:

  1. IAM честно говорит isAdmin: false для tazet@narod.ru
  2. Но applyContext проверяет email === ADMIN_EMAILtrue
  3. ADMIN_EMAIL=tazet@narod.ru в ENV

Это ожидаемое поведение — ADMIN_EMAIL даёт админские права независимо от IAM.