docs: удалить оставшиеся DEPRECATED файлы

This commit is contained in:
“Naeel”
2026-05-30 19:12:25 +03:00
parent 32671bfa43
commit 2e3ac21701
3 changed files with 0 additions and 335 deletions
-169
View File
@@ -1,169 +0,0 @@
# IP WhiteList — Архитектура (актуально, 2026-05-30 14:43)
> Ветка `sonnet`, репо: `gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git`
> Код: `/home/naeel/ipwhitelist-app`
---
## Стек
| Слой | Технология |
|---|---|
| Сервер | Node.js + Express 4 |
| Шаблоны | EJS (server-side, без SPA) |
| БД | PostgreSQL, клиент `pg` (pool) |
| Безопасность | helmet, express-rate-limit, csrf-csrf, express-session |
| JWT | jsonwebtoken (mock RS256 / OIDC validation) |
| Авторизация | Keycloak (OIDC) или mock при локальной разработке |
---
## Структура модулей
```
server.js — точка входа: init + подключение роутеров (131 строк)
src/
auth.js — аутентификация: OIDC или mock, session middleware
config.js — MOCK_USERS, backUrl()
db.js — pg pool (checkConnection)
queries.js — все SQL-запросы к БД
validators.js — validateCIDR, aggregateCIDRs
middleware/
csrf.js — initCsrf() → { doubleCsrfProtection, generateCsrfToken }
rateLimit.js — mutationLimiter (30/мин), exportLimiter (20/мин)
routes/
auth.js — /login /callback /logout /dev-login
entries.js — / /add /edit/:id /delete/:id
admin.js — /audit /admin /admin/limit/:companyId
export.js — /export
views/
login.ejs — форма входа (mock) или заглушка (OIDC)
dev-login.ejs — тестовый вход (пресеты + произвольные поля)
index.ejs — список записей пользователя / admin-обзор
admin.ejs — admin-панель (все компании, лимиты)
audit.ejs — лог операций
sql/
schema.sql — companies, whitelist_entries (soft delete), audit_log
```
---
## Схема авторизации
```
GET /login
┌─ OIDC-режим (KC_CLIENT_ID задан) ──────────────────────────────────────┐
│ state → сессия │
│ redirect → keycloak.nubes.ru/realms/cloud/.../auth │
│ ↓ KK перенаправляет на /callback │
│ GET /callback → проверить state → exchangeCode → токен KK │
│ → userFromPayload → req.session.user → redirect / │
└─────────────────────────────────────────────────────────────────────────┘
┌─ Mock-режим (KC_CLIENT_ID не задан) ───────────────────────────────────┐
│ render login.ejs (выбрать из MOCK_USERS) │
│ POST /login → CSRF → req.session.user → redirect / │
└─────────────────────────────────────────────────────────────────────────┘
GET /dev-login (DEV_MODE=true или DEV_SECRET задан)
render dev-login.ejs (пресеты MOCK_USERS + произвольные поля)
POST /dev-login → CSRF → req.session.user → redirect /
⚠ Работает в ОБОИХ режимах — для тестирования с разными ролями
GET /logout
session.destroy() + clearCookie('connect.sid')
OIDC: redirect → keycloak logout endpoint
Mock: redirect → /login
Все защищённые роуты: auth.middleware
req.session.user → req.user (основной путь)
Authorization: Bearer → verify JWT → req.user (API-клиенты)
cookie 'jwt' (legacy) → verify → session → req.user (плавная миграция)
нет ничего → GET: redirect /login, остальное: 401
```
---
## JWT claims (auth-api, из реального токена портала)
> auth-api выпускает свой JWT — **не Keycloak напрямую**.
> Issuer: `"auth-api"`, алгоритм: RS256.
> Наш сервис принимает и валидирует этот токен.
| Поле | Тип | Пример | Что используем |
|---|---|---|---|
| `ClientID` | string | `"WZ01325"` | `req.user.clientId` |
| `company_id` | UUID | `"3e64aac6-..."` | `req.user.companyId`, FK в БД |
| `company_name` | string | `"Тест"` | `req.user.companyName` |
| `email` | string | `"user@example.com"` | `req.user.email` (аудит) |
| `login` | string | `"user@example.com"` | fallback для email |
| `sub` | UUID | `"0199e325-..."` | fallback для companyId |
| `iss` | string | `"auth-api"` | проверяется при валидации |
| `exp` | number | ~12 часов | автоматически |
**Признак admin:** `clientId === ADMIN_CLIENT_ID` (env `ADMIN_CLIENT_ID`, default `WZ01112`).
`isAdmin` не приходит в JWT — см. [questions.md](questions.md).
---
## Маршруты
| Метод | Путь | Доступ | Лимит |
|---|---|---|---|
| GET | `/healthz` | public | — |
| GET | `/.well-known/jwks.json` | public | — |
| GET | `/export` | public | 20/мин |
| GET/POST | `/login` | public | — |
| GET | `/callback` | public | — |
| GET | `/logout` | public | — |
| GET/POST | `/dev-login` | public (с guard) | — |
| GET | `/` | auth | — |
| POST | `/add` `/edit/:id` `/delete/:id` | auth | 30/мин |
| GET | `/audit` `/admin` | auth + admin | — |
| POST | `/admin/limit/:companyId` | auth + admin | 30/мин |
---
## Env-переменные
### Обязательные в продакшене
| Переменная | Описание |
|---|---|
| `DB_HOST` / `DB_PORT` / `DB_NAME` / `DB_USER` / `DB_PASS` | PostgreSQL |
| `SESSION_SECRET` | Секрет сессии (≥ 32 символа) |
| `CSRF_SECRET` | Секрет CSRF (≥ 32 символа) |
| `KC_CLIENT_ID` | client_id в Keycloak realm cloud |
| `KC_CLIENT_SECRET` | client_secret |
| `APP_URL` | Внешний URL приложения (для redirect_uri) |
### Опциональные
| Переменная | Default | Описание |
|---|---|---|
| `KC_BASE_URL` | `https://keycloak.nubes.ru/realms/cloud` | Keycloak realm base URL |
| `ADMIN_CLIENT_ID` | `WZ01112` | WZ-номер администратора |
| `PORT` | `3000` | HTTP-порт |
| `NODE_ENV` | — | `production` включает secure cookie, trust proxy |
| `DEV_MODE` | `false` | `true` → /dev-login без пароля |
| `DEV_SECRET` | — | Ключ для /dev-login в staging |
---
## БД (dev)
```
Host: write.bde8229b-1381-4330-b24b-727ad73fcb44.dev.nubes.ru
DB: ipwhitelist
User: super
```
Схема: `sql/schema.sql``companies`, `whitelist_entries` (soft delete), `audit_log` + индексы.
---
## Деплой (текущий)
- URL: `https://white.nodejsk8s.dev.nubes.ru`
- k8s namespace: `whitelist`
- Сессии: in-memory (MemoryStore) — **не масштабируется**, нужен Redis при multi-pod
- Режим: ожидает KC_CLIENT_ID/KC_CLIENT_SECRET для перехода с mock на OIDC
-96
View File
@@ -1,96 +0,0 @@
# IP WhiteList — План (pending задачи, 2026-05-30 14:43)
> **Ветка:** `sonnet` · **Обновлено:** 2026-05-30 14:43
> Всё что было в старых планах — реализовано. Здесь только то, чего ещё нет.
---
## Блокер 1 — Keycloak OIDC (нужны данные от DevOps)
Код OIDC Authorization Code Flow написан и готов (`src/auth.js`).
Не активируется пока не получены:
| Что нужно | Env-переменная | Статус |
|---|---|---|
| client_id в realm cloud | `KC_CLIENT_ID` | ❌ ждём DevOps |
| client_secret | `KC_CLIENT_SECRET` | ❌ ждём DevOps |
| redirect_uri зарегистрирован в KK | (в самом KK) | ❌ ждём DevOps |
| SESSION_SECRET для продакшена | `SESSION_SECRET` | ❌ нужно сгенерировать |
Без этого сервис работает в mock-режиме (`/dev-login` как тестовый backdoor).
---
## Блокер 2 — Admin-роль из Keycloak
Сейчас admin = `clientId === WZ01112`.
Как реально приходит `isAdmin` из KK — не ясно (см. [questions.md](questions.md)).
После получения ответа — 1–2 строки в `userFromPayload()` в `src/auth.js`.
---
## Задача 1 — Деплой ветки sonnet
- [ ] Передеплоить на `white.nodejsk8s.dev.nubes.ru` (сейчас там master)
- [ ] Добавить env-секреты в k8s: `SESSION_SECRET`, `CSRF_SECRET`
- [ ] Проверить smoke-тест: `/healthz`, `/login`, `/export`
---
## Задача 2 — Сессии при multi-pod
Сейчас: MemoryStore (in-process, не масштабируется).
При нескольких репликах k8s сессии будут теряться.
- [ ] `npm install connect-redis ioredis`
- [ ] Подключить Redis в `server.js` (3 строки конфига)
- [ ] Добавить `REDIS_URL` в env
**Блокер:** нужен Redis в k8s (или принять ограничение на 1 реплику пока).
---
## Задача 3 — IP-ограничение /export
ТЗ: endpoint доступен без авторизации, ограничен по IP на старте.
Текущее решение: открытый endpoint с rate-limit (20 req/мин).
- [ ] Уточнить: ограничение в приложении или ingress? (см. [questions.md](questions.md))
- [ ] Если в приложении: whitelist IP через `EXPORT_ALLOWED_IPS` env var
---
## Задача 4 — Пагинация
При `custom_limit` > 50 таблица станет неудобной.
Сейчас все записи выводятся без пагинации.
- [ ] `GET /?page=N` + `LIMIT/OFFSET` в `queries.listEntries()`
- [ ] Кнопки Назад/Вперёд в `views/index.ejs`
Низкий приоритет — текущий дефолтный лимит 15 записей на компанию.
---
## Задача 5 — Auto-dismiss alert
Flash-алерты (ошибка/успех) сейчас исчезают только при перезагрузке.
- [ ] 10 строк JS в `views/index.ejs`: `setTimeout(() => alert.remove(), 5000)`
---
## Не делать (закрыто)
| Что | Почему |
|---|---|
| ~~CSRF-защита~~ | ✅ csrf-csrf (double-submit cookie) |
| ~~Рефакторинг server.js~~ | ✅ 131 строка, роутеры вынесены |
| ~~Автотесты~~ | ✅ 50 unit-тестов (`node tests/run-tests.js`) |
| ~~aggregateCIDRs в /export~~ | ✅ в `src/validators.js` |
| ~~Admin-панель~~ | ✅ `src/routes/admin.js`, `views/admin.ejs` |
| ~~Редактирование записи~~ | ✅ `POST /edit/:id` |
| ~~Аудит~~ | ✅ `GET /audit` |
| ~~OIDC Authorization Code Flow~~ | ✅ `src/auth.js` + `src/routes/auth.js` |
| ~~Session middleware~~ | ✅ `express-session` в `server.js` |
| ~~Dev-login backdoor~~ | ✅ `/dev-login` с пресетами + кастомные поля |
-70
View File
@@ -1,70 +0,0 @@
# Вопросы к DevOps / команде Keycloak — IP WhiteList
> Обновлено: 2026-05-30 14:43
> Часть вопросов из первоначального списка закрыта реализацией.
---
## ❌ ОТКРЫТЫЕ (блокируют деплой)
### 1. Данные клиента Keycloak
Для активации OIDC-режима (код готов, ждёт переменных):
```
KC_CLIENT_ID= ? # наш client_id в realm cloud
KC_CLIENT_SECRET= ? # наш client_secret
```
Redirect URI для регистрации в Keycloak:
```
https://white.nodejsk8s.dev.nubes.ru/callback
```
---
### 2. Admin-роль: как приходит из Keycloak
**ТЗ:** Администратор = `clientId = WZ01112` + «отдельный чек-бокс».
Сейчас: `isAdmin = (ClientID === process.env.ADMIN_CLIENT_ID)` — только WZ01112.
Вопросы:
- Есть ли отдельный claim в JWT для признака admin?
- Если да — как называется? Примеры: `realm_access.roles`, `resource_access.whitelist.roles`, `is_admin`, `groups`
- Нужна поддержка нескольких adminов или только WZ01112?
**Если нет отдельного claim** — оставляем текущее решение, закрываем вопрос.
---
### 3. /export — IP-ограничение
ТЗ: «на старте может работать без авторизации (по сетевому ограничению)».
Сейчас: открытый endpoint, rate-limit 20 req/мин.
- Ограничение делаем в **приложении** или в **ingress/nginx**?
- Если в приложении — список разрешённых IP (env var `EXPORT_ALLOWED_IPS`?).
---
## ✅ ЗАКРЫТЫЕ
| # | Вопрос | Решение |
|---|---|---|
| DEV_MODE | Нужен ли dev-режим на платформе? | `/dev-login` — backdoor с `DEV_MODE=true` (без пароля) или `DEV_SECRET=xyz` (с ключом). Работает в обоих режимах. |
| Email claim | Как называется claim с email? | Берём `payload.email \|\| payload.login \|\| 'unknown'` |
| JWT структура | Формат токена auth-api | Изучен из реального токена (см. [DEPRECATED]-auth-architecture.md). Поля: `ClientID`, `company_id`, `company_name`, `email`, `login`. |
| CSRF | Защита POST-форм | csrf-csrf (double-submit cookie pattern) |
| Session | Хранение пользователя | express-session (httpOnly, sameSite lax, 8ч) |
---
## Условные обозначения в коде
```js
// TODO(KK): уточнить формат claim — см. docs/questions.md#2
// FIXME(KK): временно, заменить после ответа команды
```