diff --git a/docs/history/session-2026-06-22-export-impersonation.md b/docs/history/session-2026-06-22-export-impersonation.md new file mode 100644 index 0000000..3b6727c --- /dev/null +++ b/docs/history/session-2026-06-22-export-impersonation.md @@ -0,0 +1,135 @@ +# Сессия 2026-06-22 — export view=2, фикс имперсонации, TZ аудит + +## Версии +- **0.1.1** — сброс версии с 0.5.180 +- **0.1.2** — `white-space: pre` на `` (пробелы схлопывались) +- **0.1.3** — таблица без точек, октеты в своих `` +- **0.1.4** — `text-align: right` в ячейках +- **0.1.5** — `padStart(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 +```html + + + + +
62 76 39 5 / 32
+``` + +- Каждый октет в своей ``, без точек +- `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`: + +```js +// checkImpersonation — строка 78 (было) +const oldIsImp = !!(u.originalUserEmail && u.impersonatedCompanyId); + +// applyContext — строка 133 (было) +const isImpersonated = !!(u.originalUserEmail && u.impersonatedCompanyId); +``` + +**Поле `impersonatedCompanyId` отсутствует в ответе IAM.** IAM `/auth/user` возвращает: +```json +{ + "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`): + +```js +// checkImpersonation (исправлено) +const oldIsImp = !!u.isImpersonated; + +// applyContext (исправлено) +const isImpersonated = !!(u.isImpersonated || u.originalUserEmail); +``` + +--- + +## 3. Время в аудите — UTC → MSK + +Файл: `views/v2/admin-audit.ejs`, строка 100. + +```js +// Было (возвращает серверное время = 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_EMAIL` → `true` +3. `ADMIN_EMAIL=tazet@narod.ru` в ENV + +Это ожидаемое поведение — `ADMIN_EMAIL` даёт админские права независимо от IAM.