Commit Graph

34 Commits

Author SHA1 Message Date
ruslan beb2781123 Fix request-access: add Telegram env to compose, fix log_event calls 2026-05-14 06:28:58 +00:00
ruslan f740420a77 Add request access modal on login page with Telegram notification
- Modal form: name, company, email, phone (required), manager (optional), product checkboxes
- Products loaded from DB via GET /api/public/services-by-category (public route)
- POST /api/request-access sends styled Telegram message with divider and emojis
- Dark-themed modal matching login page design
- CSS: overlay, card, fields, checkbox list, error, footer buttons
2026-05-14 06:22:39 +00:00
ruslan 6aa40eb5c2 feat: add first_name/last_name to users, avatar in header, neutral dashboard bg 2026-05-12 12:51:47 +00:00
ruslan 3d8ccd30b6 fix: add hash_password to auth imports in main.py 2026-05-01 16:47:48 +00:00
ruslan dc90569631 fix: call connect_rdp_slot on session reuse
Previously connect_rdp_slot was only called when creating a new session.
If the API container restarted, existing sessions had should_be_connected=false
and xfreerdp never started. Now connect is triggered on every /go/<slug> visit
when an RDP session already exists.
2026-05-01 16:11:30 +00:00
ruslan 38dc206f5a fix: add missing user_is_valid import from auth in main.py 2026-05-01 12:56:19 +00:00
ruslan fb4af8cfe6 fix: add missing import secrets in main.py 2026-05-01 12:55:02 +00:00
ruslan 58cb8b1035 feat: on-demand RDP - connect xfreerdp only when session opens
Replaces always-on xfreerdp with on-demand model (load 12 to under 1 at idle).
- rdp-proxy/manager.py: HTTP server port 7001 managing xfreerdp lifecycle
- rdp-proxy/entrypoint.sh: starts Xvfb+x11vnc+websockify+manager, no auto-connect
- rdp-proxy/Dockerfile: adds python3, copies manager.py, exposes 7001
- runtime.py: connect_rdp_slot and disconnect_rdp_slot via manager HTTP API
- terminate_session_record: disconnect instead of container restart
- main.py: calls connect_rdp_slot in background thread on session create
- maintenance.py: cleanup_loop disconnects on expire, run_maintenance_service
  includes RDP slot init, maintenance_runner fixed to import maintenance
2026-05-01 10:12:52 +00:00
ruslan 82024a36c4 fix: add missing sqlalchemy imports (select, text, delete, update) to main.py 2026-05-01 09:51:24 +00:00
ruslan b8dd023233 fix: add missing runtime imports (route_ready, docker_client, ensure_universal_pool, get_universal_pool_status) 2026-05-01 09:48:42 +00:00
ruslan 1c7caec021 fix: add missing config imports to main.py (GO_*_LOCK_TIMEOUT, WEB_POOL_BUFFER) 2026-05-01 09:45:55 +00:00
ruslan c8c77048c7 refactor: split main.py into modules (config, database, models, utils, auth, runtime, maintenance)
main.py was ~3000 lines with models, routes, Docker ops, maintenance all mixed.
Split into 7 focused modules:
- config.py: env vars and constants
- database.py: SQLAlchemy engine, SessionLocal, Base, get_db
- models.py: ORM models and enums
- utils.py: logging, formatting, icon handling, misc helpers
- auth.py: password hashing, cookies, CSRF, user dependency
- runtime.py: all Docker operations, pool management, session lifecycle
- maintenance.py: cleanup loop, schema bootstrap, startup logic
- main.py: FastAPI app, middleware, all route handlers only
2026-05-01 09:40:06 +00:00
ruslan cf68bc848f Fix CSRF SameSite=Strict breaking login on iPad/Safari
Safari (iPadOS/iOS) blocks SameSite=Strict cookies on the initial
top-level navigation when it considers the request cross-site (links
from messengers, email, QR codes). The CSRF cookie was therefore never
set on first visit, and the subsequent login POST failed with 403
"CSRF failed".

Switch the CSRF cookie to SameSite=Lax — this is the OWASP recommended
default and matches industry practice. The auth (session) cookie keeps
SameSite=Strict, since it is only issued after a successful first-party
login POST and needs the stricter binding.
2026-04-30 17:38:20 +00:00
ruslan 23c1f6e342 Chromium: Russian language, autofill passwords from svc_login/svc_password via Login Data 2026-04-30 07:22:31 +00:00
ruslan 154ec35384 Block mobile devices: show desktop-only page 2026-04-28 20:52:24 +00:00
ruslan 8f3617afdd Remove copy buttons from credentials panels 2026-04-28 13:49:47 +00:00
ruslan beb6828520 Add credentials panel on view page; remove copy buttons from dashboard cards 2026-04-28 13:47:46 +00:00
ruslan a64d49a8c1 feat: reorder card layout + svc_cred_hint field for credentials note 2026-04-28 12:20:37 +00:00
ruslan b9d13733c9 feat: service credentials (login/password) on dashboard cards with copy button 2026-04-28 12:10:40 +00:00
ruslan fa88f7f4e4 feat: full Markdown support in service card comments (mistune) 2026-04-28 11:57:44 +00:00
ruslan a4a96c45b0 fix: RDP slot occupancy and cleanup_loop always running
- admin_page: slot shown as occupied based on ACTIVE status only (no time cutoff)
- go_service: busy slots checked by ACTIVE status (no cutoff) — cleanup_loop handles expiry
- startup_event: cleanup_loop starts regardless of ENABLE_STARTUP_MAINTENANCE flag;
  pool/container init guarded by the flag separately
- cleanup_loop: RDPSLOT sessions expire correctly and trigger container restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 06:48:00 +00:00
ruslan 552898e3e9 fix: cleanup_loop correctly frees and restarts RDP slots on session expiry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 06:34:04 +00:00
ruslan 6847cbc078 feat: RDP slot pool — multi-user RDP with per-account containers
- New RdpSlot model (rdp_slots table): service_id, rdp_username,
  rdp_password, container_name
- Each slot gets a dedicated portal-rdpslot-<slug>-<id> container with
  Traefik route /rdp/<slot_id>/ and restart_policy=unless-stopped
- go_service: RDP services with slots use pool allocation — finds first
  free slot (not occupied by active session), returns 503 if all busy
- session_status + session_view: handle RDPSLOT: container_id prefix
- terminate_session_record: restarts slot container in background on close
- session_redirect_url: RDPSLOT sessions redirect to /s/<id>/view
- startup_event: starts containers for all configured slots on boot
- Admin: POST /api/admin/services/{id}/rdp-slots, DELETE /api/admin/rdp-slots/{id}
- admin.html: slot management UI (list, add, delete); removed ACL exclusivity
- set_acl: removed RDP 1-user exclusivity — RDP services now assignable to many

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 06:32:02 +00:00
ruslan 6f17193312 feat: loading overlay on dashboard, RDP pooled session routing fix
- dashboard.html: overlay div moved before <script> so getElementById works;
  double rAF ensures browser paints spinner before navigation
- main.py: pooled_rdp route fix — session_status now returns /svc/<slug>/
  route and redirect_url for POOL: RDP sessions (was always ready instantly)
- docker-compose.yml: parametrise env vars via .env for easier tuning

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 19:07:55 +00:00
ruslan 419b495020 feat: RDP ACL exclusivity, mobile wall, nav buttons, resolution xrandr
- RDP сервис может быть назначен только одному пользователю в ACL
- Мобильная заглушка на dashboard при ширине < 1024px
- rdp-proxy: кнопки навигации, спиннер Ожидайте, реконнект
- session_wait_page: тёмная тема, CSS спиннер
- kiosk/universal-runtime manager.py: xrandr + cvt --newmode для resolution
- Dockerfiles: x11-xserver-utils, x11-utils
2026-04-27 18:49:06 +00:00
ruslan 6871ea6b67 fix: improve web runtime resolution and restore x11vnc ncache 2026-04-25 17:28:04 +00:00
ruslan 8863943d79 feat: propagate client screen size to web runtime 2026-04-24 18:26:11 +00:00
ruslan 7000c17d2b chore: commit all pending changes and ignore project context 2026-04-24 12:41:37 +00:00
ruslan 1438dee21a feat: improve session limit handling and add k6 load testing 2026-04-23 05:17:53 +00:00
ruslan 6f9bc32440 UI/runtime polish, session rotation limit, login errors, docs update 2026-04-21 16:05:15 +00:00
ruslan c97cf5308d Tune idle timeout, heartbeat redirect, and update project context 2026-04-21 13:31:47 +00:00
ruslan 52d1991092 feat: categories, runtime nav, and UX updates 2026-04-21 11:43:43 +00:00
ruslan 605b269f74 feat: switch WEB to shared hot pool with autoscale 2026-04-14 13:37:45 +00:00
ruslan fc46d90194 feat: redesign portal UX and stabilize web session runtime 2026-04-13 08:35:07 +00:00