Commit Graph
43 Commits
Author SHA1 Message Date
naeel 1350f0dbba security: fix OIDC state check bypass + open redirect in login-token
- oidc.js: remove || true — state check now works in all environments
- auth.js: wrap returnTo in safeReturn (was unprotected on line 166)
2026-06-11 20:02:49 +04:00
naeel 351cb6afe6 feat: test impersonation via IMPERSONATION_ORIGINAL/TARGET/COMPANY env vars
- ui/index.js: resolveUser checks env vars, only for matching email
- Закомментировать блок 'TEST IMPERSONATION' для прода
2026-06-11 19:25:11 +04:00
naeel 3bc285dc93 fix: /export only for adminMode users, not public 2026-06-11 16:28:15 +04:00
naeel 9c51e449ab fix: remove canWrite from IAM — it is IAM RBAC, not our app logic
- IAM permissions.can_write defaults to false for all users
- Our app controls writes via adminMode + company membership
2026-06-11 16:01:55 +04:00
naeel 9a331eec82 feat: full IAM impersonation support — read-only + original user + canWrite
- src/auth.js: all impersonation fields + permissions.can_write
- src/routes/oidc.js: save all fields to session
- ui/index.js: canWrite, originalUserEmail in req.user
- ui/routes/entries.js: read-only guard on POST/PATCH/DELETE
- docs/PLAN-impersonation.md: updated with implemented items
2026-06-11 15:54:56 +04:00
naeel a2cfd2c10f feat: IAM impersonation support — isImpersonated flag + banner
- src/auth.js: fetchIamUser extract isImpersonated from response
- src/routes/oidc.js: save isImpersonated to session
- ui/index.js: isImpersonated in req.user
- ui/routes/entries.js: pass isImpersonated to render
- views/index.ejs: banner 'Режим имперсонации'
- docs/PLAN-impersonation.md: план дальнейших шагов (двойной аудит)
2026-06-11 15:34:19 +04:00
naeel ce6b67e72a fix: email from session.user first, not JWT payload
- req.session.user.email приоритетнее payload.email
- Исправляет отображение чужого email в header
2026-06-11 15:08:07 +04:00
naeel 9cb53df8b1 fix: toggle as pure HTML form — no JS, no fetch, just POST+redirect
- views/index.ejs: onclick+fetch → form method=POST с button
- ui/routes/auth.js: JSON → res.redirect(Referer)
- Текст меняется: «Администратор» ↔ «Выйти из админки»
2026-06-11 14:59:59 +04:00
naeel fa4d5646fa fix: toggle now works — JSON response + immediate CSS flip
- /toggle-admin returns JSON {ok, adminMode} instead of redirect
- onclick: toggle CSS instantly, then fetch, then reload on ok
2026-06-11 14:42:31 +04:00
naeel f739754c3b fix: pass canAdminMode to render + bump 0.5.47 2026-06-11 14:34:42 +04:00
naeel 8b891a4bed fix: remove duplicate catch block causing startup crash 2026-06-11 14:19:01 +04:00
naeel 08248229b9 fix: если email мой — isAdmin = true, canAdminMode = true
- isAdmin = iamAdmin || (payload.email/login === ntazetdinov@nubes.ru)
2026-06-11 14:10:52 +04:00
naeel 2fbdc3259b hardcode: canAdminMode для ntazetdinov@nubes.ru без зависимостей
- Просто хардкод email = 'ntazetdinov@nubes.ru'
- Убран лишний фетч email из сессии/payload/logging
2026-06-11 14:10:00 +04:00
naeel d54a72ca2c debug: add resolveUser logging for canAdminMode diagnosis 2026-06-11 14:04:36 +04:00
naeel 4af34616f9 fix: canAdminMode по email ntazetdinov@nubes.ru вместо isAdmin
- ui/index.js: email берётся из сессии (IAM/Keycloak)
- canAdminMode: (isAdmin AND WZ01112) OR (ntazetdinov@nubes.ru AND WZ01112)
- Временно для тестов, убрать после настройки IAM isAdmin
2026-06-11 13:41:35 +04:00
naeel 13466ebd37 simplify: toggle adminMode, canAdminMode flag, remove getOrCreateCompany fallback
- ui/index.js: canAdminMode = isAdmin AND WZ01112 (временно || WZ01112)
- views/index.ejs: checkbox → toggle с JS fetch, условие canAdminMode
- ui/routes/entries.js: убран getOrCreateCompany-фоллбек для админа
- Админ без ?company= видит список компаний, без автозагрузки
- isAdmin теперь чисто из IAM (без || WZ01112)
2026-06-11 13:15:37 +04:00
naeel 1794610f77 fix: ownCo not found → getOrCreateCompany instead of companies[0]
- Убрал fallback на companies[0] — небезопасно
- Если компания админа не найдена — создаём через getOrCreateCompany
2026-06-11 11:18:59 +04:00
naeel 2acad33fd4 fix: admin without ?company= loads own company (no redirect)
- Убрал редирект на ?company=<id> — админ видит свою компанию по умолчанию
- ownCo ищется по clientId из сессии, если не найдена — первая из списка
- Больше не пишет ?company= в URL при первом входе
2026-06-11 11:16:37 +04:00
naeel 4f1f64dd6c feat: adminMode — чек-бокс переключения админского интерфейса
Шаг 1: /toggle-admin роут в ui/routes/auth.js
  - переключает req.session.adminMode
  - canAdmin = isAdmin || clientId === WZ01112 (временно)

Шаг 2: resolveUser в ui/index.js
  - req.user.adminMode из req.session.adminMode
  - isAdmin = IAM.isAdmin || clientId === WZ01112 (временно)

Шаг 3: adminMode вместо isAdmin в интерфейсе
  - ui/routes/entries.js: adminMode решает админский view
  - ui/routes/admin.js: requireAdmin проверяет adminMode

Шаг 4: views/index.ejs
  - чек-бокс «Администратор» (виден только если isAdmin)
  - ссылки Аудит/Лимиты видны только при adminMode
  - селектор компаний — при adminMode
2026-06-11 11:08:03 +04:00
naeel 32cb0f4ac6 fix: block clientId login in OIDC mode (crash fix)
- ui/routes/auth.js: auth.isOidc → redirect to /login with error instead of
  calling issueMockToken which throws 'Mock keypair not initialized'
- This was crashing the process via unhandled promise rejection
2026-06-10 11:42:50 +04:00
naeel d0bfdab085 bump 0.5.26 — fix server.js error handler to show message 2026-06-09 21:01:00 +04:00
naeel 9c74479121 bump 0.5.25 — error details on 500 page, ensureSchema catch
- ui/index.js: 500 page shows error.message
- server.js: ensureSchema error logged, doesn't crash startup
2026-06-09 20:56:58 +04:00
naeel c1df27d29d fix: DeepSeek audit — header injection + IAM limit + bump 0.5.22
- src/api/routes/entries.js: санитизация filename в /api/v1/entries/export
- ui/routes/export.js: санитизация filename в UI /export
- src/auth.js: лимит 100KB для IAM-ответов
- src/api/routes/entries.js: fallback для пустого allowedIds
2026-06-04 15:48:16 +03:00
naeel 58e34042de fix: header injection, api timeout, nginx duplicate + bump 0.5.21
- server.js: санитизация filename в /export (header injection)
- ui/api-client.js: req.setTimeout(15000) + try/catch JSON.parse
- docs/devops-deploy.md: убран дубль X-Forwarded-Proto
2026-06-04 15:41:03 +03:00
naeel 8cbbe52316 fix: safeReturn для всех редиректов (security)
- ui/routes/auth.js: safeReturn() для returnTo в POST /login и /login-token
- src/routes/oidc.js: safeLocal() для oidcReturnTo в /callback
2026-06-04 15:26:26 +03:00
naeel bbcda90378 fix: IAM баги после ревью
- ui/routes/auth.js: POST /login-token сделан async (был await без async)
- ui/routes/auth.js: IAM enrichment только при auth.isOidc (не в mock-режиме)
- src/auth.js: fetchIamUser, switchProfile возвращаются из initAuth()
- src/routes/oidc.js: auth.fetchIamUser вместо require('../auth') (устранение циклической зависимости)
- ui/routes/auth.js: auth.fetchIamUser вместо require
- tests/api-crud.sh: удалён хардкоженный prod-токен, токен только через аргумент
2026-06-04 15:08:40 +03:00
naeel a8a07fe019 feat: IAM API интеграция + обновление ТЗ + тесты
- src/auth.js: fetchIamUser(), switchProfile(), userFromPayload(iamData)
- src/config.js: IAM_API_URL из env
- src/routes/oidc.js: обогащение сессии через IAM (с fallback на JWT)
- ui/routes/auth.js: обогащение при токен-логине
- ui/routes/entries.js: switchTo через POST /switch-profile
- src/api/routes/entries.js: resolveCompany через profiles[]
- views/index.ejs: переключатель компаний с названиями из profiles
- .env.example: IAM_API_URL
- docs: обновлены ТЗ-реализация.md, ТЗ-плюс.md, добавлен iam-integration.md
- tests: api-crud.sh (14 тестов CRUD + валидации)
- .gitignore: исключены .env.test, DEPLOY-TESTING.md
2026-06-04 13:53:44 +03:00
naeel 38c7adf25d v0.5.14 — вход по токену, JWKS в mock-режиме, production deploy docs
- POST /login-token: принимает реальный JWT (не только clientId)
- auth.js: verifyAnyToken — mock + JWKS (Keycloak Nubes) одновременно
- auth.js: JWKS предзагружается всегда, даже в mock-режиме
- devops-deploy.md: полная production-инструкция для DevOps
- .env.example: production-ready шаблон
- README.md: актуальный (v0.5.13, архитектура, тесты, ссылки)
- .gitignore: очищен от дубликатов
2026-06-03 12:37:10 +03:00
naeel 599808b838 fix: переключение компаний не работало — req.user.activeClientId не синхронизировался
Баг: resolveUser запускается ДО обработчика. После смены
session.user.activeClientId рендер и companyQuery продолжали
использовать старое значение req.user.activeClientId.

Фикс: req.user.activeClientId = switchTo после обновления сессии.
2026-06-03 05:34:06 +03:00
naeel 0fd5b43a94 v0.5.12: доделки перед сдачей заказчику
§4.7: агрегация CIDR в публичном /export (aggregateCIDRs)
§5: клиентская JS-валидация (запрещённые диапазоны + нормализация)
§4.1: фильтр «показать удалённые» для admin (API + UI)
§5: уведомление о нормализации (уже работало, проверено)

Файлы:
- server.js: +aggregateCIDRs в /export
- views/index.ejs: JS-валидация + чек-бокс удалённых
- src/api/routes/entries.js: ?includeDeleted=true (admin only)
- ui/routes/entries.js: проброс includeDeleted
- docs/PLAN-predsdachey.md: план доделок
2026-06-02 19:04:24 +03:00
naeel 453e25e40f ui: убрать вход по Bearer токену, добавить ручной ввод clientId (отладка) 2026-06-02 17:31:21 +03:00
naeel 51a003e078 v0.5.10: /export — attachment default, ?view=1 inline, ?filename=custom 2026-06-02 14:49:50 +03:00
naeel 8ab2271ff9 v0.5.4: fix isolation — resolveUser syncs activeClientId from session 2026-06-02 11:11:20 +03:00
naeel 1b1b3b6bd7 v0.5.3: fix multi-company API isolation (client_id param) 2026-06-02 10:57:52 +03:00
naeel a083f65323 v0.5.2: multi-company, isAdmin fix, appVersion, docs 2026-06-02 10:52:12 +03:00
naeel 0abaa65bf8 fix: preserve form values on error + rename Дата→Добавлена, Изменён→Изменена + bump 0.5.1 2026-05-31 12:48:08 +03:00
naeel 0413b44051 fix: P0/P1 fixes (auth+limit+schema) + project audit docs 2026-05-31 09:42:46 +03:00
naeel 5c286af43b refactor: entries.js — remove 'own' hack, clean admin company routing + bump 0.4.7 2026-05-31 07:25:42 +03:00
naeel a355b34e4a fix: remove duplicate own company option in dropdown + bump 0.4.6 2026-05-31 07:23:25 +03:00
naeel fa67872f30 feat: admin own company option in dropdown + fix company=own routing + bump 0.4.5 2026-05-31 06:57:34 +03:00
naeel a6177c4cef feat: admin auto-redirect to first company on / + bump 0.4.3 2026-05-31 06:15:37 +03:00
naeel 6cf4bc0b44 fix: /admin — pass defaultLimit to template (fixes 500) 2026-05-31 05:52:01 +03:00
naeel c85a438ba2 feat: UI-слой через /api/v1/* (ui/, views/ui-login.ejs, views/error.ejs)
- ui/api-client.js: HTTP-клиент к /api/v1/* (token из session.token)
- ui/routes/auth.js: /login (mock-пресеты), /login-token (Bearer paste), /logout
- ui/routes/entries.js: /, /add, /edit/:id, /delete/:id через API
- ui/routes/admin.js: /admin, /admin/limit/:id, /audit через API
- ui/routes/export.js: /export → проксирует /api/v1/entries/export
- ui/index.js: createUiRouter() — requireToken + resolveUser middleware
- views/ui-login.ejs: страница входа (mock + token)
- views/error.ejs: шаблон для 403/404/500

API расширения:
- GET /api/v1/entries теперь возвращает limit и used
- GET /api/v1/entries?company=<id> (admin): записи другой компании
- POST/PATCH/DELETE /api/v1/entries?company=<id> (admin): мутации для другой компании
- GET /api/v1/entries/export: агрегированный CIDR (перенесён из монолита)
- GET /api/v1/audit?company=<id>: журнал (перенесён из монолита)

server.js: заменены src/routes/* на ui/createUiRouter(), убран CSRF
2026-05-30 19:02:51 +03:00