Files
ipwhitelist-app/docs/STATE-old.md
T

205 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Состояние проекта на 2026-05-30 14:43 (ветка `sonnet`)
## Репозитории
| Репо | URL | Ветка | Локальный путь |
|---|---|---|---|
| Код приложения | `https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git` | **sonnet** | `/home/naeel/ipwhitelist-app` |
| Документация | `https://gitea.services.ngcloud.ru/Nail/IPWhiteList.git` | main | `/home/naeel/IPWhiteList` |
## Стек
Node.js + Express + EJS + PostgreSQL + pg pool + jsonwebtoken
## Деплой
- URL: `https://white.nodejsk8s.dev.nubes.ru`
- DEV_MODE=true (мок-аутентификация)
- ⚠️ Нужен передеплой Nubes для ветки sonnet
## БД
- `write.bde8229b-1381-4330-b24b-727ad73fcb44.dev.nubes.ru`
- user: `super`, db: `ipwhitelist`
- Миграция от 2026-05-30 применена (CHECK, UNIQUE, индексы)
---
## Что сделано в ветке `sonnet` (4 коммита поверх master)
### 1. `src/validators.js` — CIDR агрегация
- `aggregateCIDRs(cidrs)` — суммаризация: merge пересекающихся + смежных диапазонов → минимальный набор CIDR
- Вспомогательные: `numToIP(n)`, `rangeToCIDRs(start, end)`
- Экспортируется и используется в `/export`
### 2. `src/auth.js` — admin-роль
- `ADMIN_CLIENT_ID` = `process.env.ADMIN_CLIENT_ID || 'WZ01112'`
- `req.user.isAdmin` — определяется по `clientId === ADMIN_CLIENT_ID`
- `DEV_ADMIN=true` в `.env` → admin-права в dev-режиме
- `requireAdmin` middleware — 403 для не-admin
### 3. `src/queries.js` — новые функции
- `getCompanyById(id)` — компания по числовому PK
- `getAllCompanies()` — все компании + `active_count` (LEFT JOIN)
- `setLimit(companyId, newLimit)` — установить/сбросить (null) индивидуальный лимит
- `getAudit()` — обновлён: JOIN с companies (поля `company_name`, `client_id`)
### 4. `server.js` — новые роуты
- `/export` — публичный (до auth.middleware), возвращает агрегированный список всех компаний
- `GET /` — admin: видит все компании с переключателем `?company=X`
- `POST /edit/:id` — редактирование записи (admin + user)
- `GET /audit` — журнал аудита (только admin)
- `GET /admin` — управление лимитами (только admin)
- `POST /admin/limit/:companyId` — изменить/сбросить лимит компании
- `backUrl()` — хелпер для редиректа обратно с учётом контекста admin/user
### 5. `views/index.ejs`
- Admin-панель выбора компании (dropdown + быстрые ссылки на Аудит/Лимиты)
- Кнопки Аудит/Лимиты/Выйти в header для admin
- Кнопка "Изменить" в таблице (открывает edit modal)
- Edit modal — overlay с формой, закрывается по Escape/backdrop
- Скрытый `company_id` в формах add/delete для корректной admin-ветки
### 6. `views/audit.ejs` — **новый**
- Таблица журнала аудита с фильтром по компании
- Цветные badges (CREATE/UPDATE/DELETE)
- old_value → new_value стрелочкой
### 7. `views/admin.ejs` — **новый**
- Таблица всех компаний: client_id, active_count, лимит
- Прогресс-бар использования (зелёный/янтарный/красный)
- Форма изменения лимита с подтверждением; кнопка ↺ сброс на дефолт
---
## Не сделано (production-hardening, не баги)
- helmet (X-Frame-Options, CSP, HSTS)
- rate-limit на POST /add, /delete, /export
- CSRF-токены в формах
- JWT-верификация через внешний JWKS (нужен URL от девопсов)
- Multi-company (нужен формат claims от платформы — массив clientId?)
## Мёртвый код (не критично)
- `isSubnetOf()` в validators.js — определена, не используется, не экспортируется
## Для прода
Выставить в `.env`:
```
NODE_ENV=production
JWKS_URL=<auth-api JWKS URL>
ADMIN_CLIENT_ID=<clientId администратора>
DEFAULT_LIMIT=15
```
## Репозитории
| Репо | URL | Ветка | Локальный путь |
|---|---|---|---|
| Код приложения | `https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git` | master | `/home/naeel/ipwhitelist-app` |
| Документация | `https://gitea.services.ngcloud.ru/Nail/IPWhiteList.git` | main | `/home/naeel/IPWhiteList` |
## Стек
Node.js + Express + EJS + PostgreSQL + pg pool + jsonwebtoken
## Деплой
- URL: `https://white.nodejsk8s.dev.nubes.ru`
- DEV_MODE=true (мок-аутентификация)
- ⚠️ Код запушен, но Nubes не передеплоил — крутится старая версия
## БД
- `write.bde8229b-1381-4330-b24b-727ad73fcb44.dev.nubes.ru`
- user: `super`, db: `ipwhitelist`
- Миграция от 2026-05-30 применена (CHECK, UNIQUE, индексы)
---
## Что сделано (запушено)
### 1. `src/validators.js` — исправлены 3 бага
- Запрещённые диапазоны: `isSubnetOf``overlaps` (обход через суперсеть `/22`)
- Маска: `parseInt('24abc')` глотал мусор → строгая проверка `/^\d{1,2}$/`
- Множественные слэши: `10.0.0.0/24/8` теперь отклоняется
### 2. `src/queries.js` — транзакции + гонки
- `createEntry`, `updateEntry`, `deleteEntry` — внутри транзакции с `SELECT ... FOR UPDATE`
- `getOrCreateCompany` — атомарный `INSERT ... ON CONFLICT`
- `getLimit``!= null` вместо `||` (custom_limit=0 не игнорируется)
- `logAudit` — принимает клиента транзакции (пишется атомарно)
- `getExportCIDRs` — фильтр по `companyId`
- `deleteEntry``company_id` в WHERE
### 3. `src/auth.js` — **новый.** Мок JWT-аутентификация
- Генерирует RSA-ключи при старте
- JWKS endpoint: `/.well-known/jwks.json`
- `verifyJWT(token)` — RS256, issuer: `mock-auth-api`
- `issueJWT(claims)` — выпускает токен с claims как в HAR (`ClientID`, `company_id`, `company_name`, `email`)
- Middleware: извлекает JWT из cookie (`jwt`) или `Authorization: Bearer`
- DEV_MODE: при `DEV_MODE=true && NODE_ENV!=production` — обход auth
- **Для прода:** выставить `JWKS_URL=https://auth-api.../jwks` → switches to external verification
### 4. `views/login.ejs` — **новый.** Мок-страница входа
- Выбор из 3 пользователей (admin WZ01112, тест WZ01325, компания 2 WZ02001)
- В проде заменяется на редирект в Keycloak
### 5. `server.js`
- `cookie-parser` для чтения JWT из cookie
- `/healthz` — выше auth (k8s probe)
- `/login` GET/POST — мок-логин
- `/logout` — чистит cookie
- `/export` — только для своей компании (с авторизацией)
- `req.query.error` читается
- `urlencoded({ limit: '32kb' })`
### 6. `sql/schema.sql`
- UNIQUE INDEX на активный `(company_id, value_cidr)` WHERE deleted_at IS NULL
- CHECK на `value_cidr` формат
- CHECK на `audit_log.action IN ('CREATE','UPDATE','DELETE')`
- CHECK на `custom_limit IS NULL OR >= 0`
- FK: `ON DELETE RESTRICT`
- Составной индекс `(company_id, created_at DESC)` на audit_log
- Индекс `(company_id, created_at DESC)` на whitelist_entries
### 7. `views/index.ejs`
- `pattern` + `maxlength="18"` + `title` на инпуте value
---
## Ревью (`/home/naeel/IPWhiteList/research/`)
| Файл | Что |
|---|---|
| `REVIEW-SUMMARY.md` | Сводка всех находок (11 критических, 21 средний) |
| `opus-review-validators.md` | 1 критичный + 2 средних |
| `opus-review-queries.md` | 3 гонки + audit + getLimit |
| `opus-review-server.md` | JWT без подписи, 401, CSRF, /export |
| `opus-review-schema.md` | UNIQUE, CIDR, FK, индексы |
| `opus-review-ejs.md` | CSRF, clickjacking, client-валидация |
| `auth-flow.md` | Анализ HAR: claims, цепочка auth-api |
---
## Не сделано (production-hardening, не баги)
- helmet (X-Frame-Options, CSP, HSTS)
- rate-limit на POST /add, /delete, /export
- CSRF-токены в формах
- JWT-верификация через внешний JWKS (нужен URL от девопсов)
- Admin-признак в токене (нужен пример токена админа)
- Multi-company (нужен формат claims от платформы)
## Для прода
Выставить в `.env`:
```
NODE_ENV=production
JWKS_URL=<auth-api JWKS URL>
```
Всё остальное работает без изменений.