From e6c477a88cf40628de30eeb56508d31d60e9af03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 30 May 2026 00:05:08 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=B0=D0=BD=D0=B0=D0=BB=D0=B8=D0=B7=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20=E2=80=94=20=D1=81?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D0=B5,=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8=D1=8F,=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D0=BE=D1=80=D0=B8=D1=82=D0=B5=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/analysis-2026-05-30.md | 112 ++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docs/analysis-2026-05-30.md diff --git a/docs/analysis-2026-05-30.md b/docs/analysis-2026-05-30.md new file mode 100644 index 0000000..e6acc14 --- /dev/null +++ b/docs/analysis-2026-05-30.md @@ -0,0 +1,112 @@ +# Анализ проекта IP WhiteList — 30.05.2026 + +## Что сделано + +| Компонент | Файл | Строк | Статус | +|---|---|---|---| +| Express-сервер, роуты | `server.js` | 101 | ✅ | +| Валидатор IPv4/CIDR | `src/validators.js` | 99 | ✅ | +| CRUD + audit_log | `src/queries.js` | 149 | ✅ | +| Пул PG | `src/db.js` | 24 | ✅ | +| UI (EJS, стиль Nubes) | `views/index.ejs` | 248 | ✅ | +| Схема БД | `sql/schema.sql` | 39 | ✅ | +| Favicon | `public/favicon.png` | — | ✅ | +| Дизайн-система (документ) | `docs/nubes-design-system.md` | — | ✅ | +| Тестирование | `tests/test-results.md` | 16/16 ✅ | ✅ | + +### Валидатор — что проверяет: +- RFC1918 (10/8, 172.16/12, 192.168/16) — запрет +- TEST-NET (192.0.2/24, 198.51.100/24, 203.0.113/24) — запрет +- Loopback, link-local — запрет +- IPv6 — запрет +- Маска: допускается только /22–/32 +- Нормализация host-битов (10.0.0.1/24 → 10.0.0.0/24) +- Пересечения с уже существующими записями — запрет +- Лимит записей на компанию (по умолчанию 15) + +### Экспорт: +- `GET /export` → plain text, один CIDR на строку, без заголовков + +--- + +## Что не готово (критично для продакшена) + +### 1. JWT-авторизация +**Сейчас:** `DEV_MODE=true` — авторизация заглушена, `clientId` захардкожен. +**Нужно:** Распаковка JWT из `Authorization: Bearer ` → извлечение `clientId` и `email`. +Схема описана в `docs/auth-architecture.md`. +**Риск:** без этого нельзя открывать сервис для реальных пользователей — любой запрос видит и меняет все данные. + +### 2. Изоляция данных по компании +**Сейчас:** Все роуты используют один захардкоженный `clientId`. БД правильная (таблица `companies` есть), но `WHERE company_id = $1` не работает по-настоящему без JWT. +**Нужно:** После JWT — всё заработает автоматически, код менять не придётся. + +### 3. CSRF-защита на POST-формах +**Сейчас:** Формы без CSRF-токена. +**Нужно:** `csurf` middleware или `SameSite=Strict` на session cookie. +Или, если фронт перейдёт на fetch/JSON API — Authorization header автоматически решает проблему. + +--- + +## Замечания и предложения + +### Архитектура + +- `server.js` содержит все роуты в одном файле (101 строка). Пока норм, но при добавлении админки/API станет неудобно. Рекомендую разбить на `routes/user.js`, `routes/admin.js`, `routes/api.js` перед тем как добавлять функциональность. + +- `queries.js` возвращает сырые строки, не объекты с явным типом. Если сервис будет расти — стоит обернуть в Result-паттерн `{ ok, data, error }`. + +### UI + +- Нет пагинации. При лимите 15 записей на компанию — не критично. Если лимит поднимут до 100+ — нужна. +- Нет поиска/фильтрации в таблице. +- Алерты исчезают только при перезагрузке страницы (flash-сообщения). Если добавить JS — можно auto-dismiss через 5 секунд. + +### Экспорт + +- Сейчас `GET /export` отдаёт все CIDR без суммаризации. Если у компании 10 записей типа `1.2.3.0/28` и `1.2.3.16/28` — они будут двумя строками. Суммаризация в `/28` + `/28` → `/27` сократила бы файл и упростила настройку оборудования. Это отдельная задача, потребует библиотеку CIDR-merge. + +### Тесты + +- Тесты ручные (curl в md-файле). Для CI/CD нужен автоматический прогон: `jest` или `supertest`. Команда для инициализации: `npm install --save-dev jest supertest`. + +### БД + +- `audit_log` пишется, но нигде не отображается пользователю. Для полноты — стоит добавить вкладку "История" или endpoint `GET /audit`. +- Нет индекса на `whitelist_entries(company_id)` — при росте данных будет полный скан. Добавить в `schema.sql`: + ```sql + CREATE INDEX idx_whitelist_company ON whitelist_entries(company_id); + CREATE INDEX idx_audit_company ON audit_log(company_id); + ``` + +### Безопасность + +- `.env` в `.gitignore` ✅ — правильно. +- `secrets.txt` в корне репо — нужно убедиться что он тоже в `.gitignore`. +- Параметризованные запросы в `queries.js` ✅ — SQL-инъекции закрыты. +- `express-validator` не подключён — валидация только на уровне `validators.js`. Нормально, т.к. все входные данные проходят через него. + +--- + +## Приоритеты следующих задач + +1. **JWT** — без этого продакшен не открыть +2. **CSRF** — параллельно с JWT +3. **Индексы БД** — 2 строки в schema.sql, риск нулевой +4. **Разбивка роутов** — перед добавлением админки +5. **Автотесты** — перед CI/CD +6. **Суммаризация CIDR** — nice to have +7. **Пагинация + фильтр** — после поднятия лимита +8. **Audit UI** — опционально + +--- + +## Текущий стек + +- Node.js + Express.js +- PostgreSQL (pg pool) +- EJS templates +- Платформа: Nubes NodeJS instance "white" +- URL: `https://white.nodejsk8s.dev.nubes.ru` +- Repo (код): `gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git` +- Repo (docs): `gitea.services.ngcloud.ru/Nail/IPWhiteList.git`