From 9f44281f9f1391583d7b19f91495a90a992da949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Wed, 17 Jun 2026 08:54:39 +0400 Subject: [PATCH] v0.5.147: add /v2/impersonation-check page with IAM GET endpoints --- docs/iam-impersonation-api.md | 83 ++++++++++++++++++++++++++++++++++ package.json | 2 +- v2/server.js | 84 +++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 docs/iam-impersonation-api.md diff --git a/docs/iam-impersonation-api.md b/docs/iam-impersonation-api.md new file mode 100644 index 0000000..e374bc6 --- /dev/null +++ b/docs/iam-impersonation-api.md @@ -0,0 +1,83 @@ +# IAM Impersonation API + +> Источник: Swagger `https://auth-api-dev.ngcloud.ru/api/v1/documentation/` +> Дата: 2026-06-16 + +## Все эндпоинты имперсонации + +| Метод | Путь | Описание | +|-------|------|----------| +| `POST` | `/api/v1/impersonation/start` | Начать имперсонацию | +| `POST` | `/api/v1/impersonation/end` | Завершить имперсонацию | +| `POST` | `/api/v1/impersonation/extend` | Продлить сессию имперсонации | +| `GET` | `/api/v1/impersonation/status` | Статус текущей имперсонации | +| `GET` | `/api/v1/impersonation/history` | История своих имперсонаций | +| `GET` | `/api/v1/impersonation/history/all` | История имперсонаций всех админов | + +## Формат ImpersonationStartRequest + +```json +{ + "type": "user", + "entity_id": "UUID контакта (contactId из userInfo)", + "reason": "описание причины" +} +``` + +- `entity_id` — **UUID таргета** (кого имперсонируем), не свой +- `type` — всегда `"user"` + +## curl-команды + +### Начать имперсонацию + +```bash +curl --http2 -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + "https://auth-api.ngcloud.ru/api/v1/impersonation/start" \ + -d '{"type":"user","entity_id":"UUID_таргета","reason":"тест"}' +``` + +### Статус + +```bash +curl --http2 \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/json" \ + "https://auth-api.ngcloud.ru/api/v1/impersonation/status" +``` + +### История + +```bash +curl --http2 \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/json" \ + "https://auth-api.ngcloud.ru/api/v1/impersonation/history" +``` + +### Продлить + +```bash +curl --http2 -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/json" \ + "https://auth-api.ngcloud.ru/api/v1/impersonation/extend" +``` + +### Завершить + +```bash +curl --http2 -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/json" \ + "https://auth-api.ngcloud.ru/api/v1/impersonation/end" +``` + +## Примечания + +- Требуется роль IAM-админа или право на объект `impersonation` +- `--http2` обязателен для обхода ddos-guard +- Стенды: `auth-api.ngcloud.ru` (prod), `auth-api-test.ngcloud.ru` (test), `auth-api-dev.ngcloud.ru` (dev) diff --git a/package.json b/package.json index 471b91f..d2c7ed4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipwhitelist", - "version": "0.5.146", + "version": "0.5.147", "description": "IP WhiteList microservice for cloud provider", "main": "server.js", "scripts": { diff --git a/v2/server.js b/v2/server.js index 48e38af..6d25198 100644 --- a/v2/server.js +++ b/v2/server.js @@ -90,6 +90,31 @@ function createV2Router() { } }); + // ── GET /v2/impersonation-check — IAM impersonation: все GET эндпоинты ─ + router.get('/impersonation-check', async (req, res) => { + const token = req.session && req.session.token; + if (!token) return res.send('

Нет токена

Войти

'); + + const endpoints = [ + { name: 'status', url: 'https://auth-api.ngcloud.ru/api/v1/impersonation/status' }, + { name: 'history', url: 'https://auth-api.ngcloud.ru/api/v1/impersonation/history' }, + { name: 'history/all', url: 'https://auth-api.ngcloud.ru/api/v1/impersonation/history/all' }, + ]; + + const results = {}; + for (const ep of endpoints) { + try { + const data = await iamFetch(token, ep.url); + results[ep.name] = { ok: true, data }; + } catch (e) { + results[ep.name] = { ok: false, error: e.message }; + } + } + + res.set('Content-Type', 'text/html; charset=utf-8'); + res.send(iamStatPage(results)); + }); + // ── /v2/app — пользовательский CRUD (только с сессией) ────────────── router.use('/app', enhanceImpersonation, resolveContext, createUserRouter()); @@ -162,4 +187,63 @@ function debugPage(u, version) { `; } +function iamStatPage(results) { + function fmt(data, depth) { + if (data === null || data === undefined) return 'null'; + if (typeof data === 'string') return '"' + data.replace(/'; + if (typeof data === 'number' || typeof data === 'boolean') return '' + data + ''; + if (Array.isArray(data)) { + if (data.length === 0) return '[]'; + let html = '[
'; + for (const item of data) html += '
' + fmt(item, depth + 1) + ',
'; + html += '
]'; + return html; + } + if (typeof data === 'object') { + let html = '{
'; + for (const [k, v] of Object.entries(data)) { + html += '
"' + k + '": ' + fmt(v, depth + 1) + '
'; + } + html += '
}'; + return html; + } + return String(data).replace(/'; + if (r.ok) { + html += '
'; + html += fmt(r.data, 0); + html += '
'; + } else { + html += '
❌ ' + r.error.replace(/'; + } + html += '
'; + } + + html += ''; + return html; +} + module.exports = { createV2Router };