- XSS: escape serviceName in waking page HTML - Session TTL: 24h expiration with periodic cleanup - Rate limit: 5 login attempts / 15 min per IP - CORS: restrict to same-origin + localhost - SSRF: block localhost/metadata in service targets - UpSnap: log response bodies on auth/wake failures Co-Authored-By: Claude <noreply@anthropic.com>
80 lines
3.9 KiB
Markdown
80 lines
3.9 KiB
Markdown
# SleepGuard Architecture
|
||
|
||
## Обзор
|
||
|
||
Wake-on-demand система из двух компонентов:
|
||
- **Proxy** (n150, 192.168.50.199) — reverse proxy + state machine + dashboard
|
||
- **Agent** (PC, 192.168.1.50) — мониторинг нагрузки + lock manager
|
||
|
||
## State Machine
|
||
|
||
```
|
||
REQUEST_RECEIVED
|
||
OFFLINE ─────────────────────► WAKING
|
||
▲ │
|
||
│ SHUTDOWN_COMPLETE │ HEALTH_CHECK_PASSED
|
||
│ ▼
|
||
SHUTTING_DOWN ◄──── IDLE_CHECK ◄── ONLINE
|
||
AGENT_IDLE IDLE_TIMEOUT ▲
|
||
│ │
|
||
│ AGENT_BUSY / REQUEST
|
||
└────────┘
|
||
```
|
||
|
||
- `OFFLINE` → запрос → wake через UpSnap → `WAKING`
|
||
- `WAKING` → health check passed → `ONLINE`
|
||
- `ONLINE` → idle timeout → `IDLE_CHECK`
|
||
- `IDLE_CHECK` → agent busy → `ONLINE`, agent idle → `SHUTTING_DOWN`
|
||
- `SHUTTING_DOWN` → agent offline → `OFFLINE`
|
||
|
||
## Shutdown Policy (Agent)
|
||
|
||
Три уровня проверки (все должны быть пройдены):
|
||
1. **Locks** — если есть активные локи, выключение блокируется
|
||
2. **Processes** — hashcat, ffmpeg, whisper, python3, ollama
|
||
3. **Metrics** — CPU >15%, GPU >10%, RAM >50%, Disk I/O active
|
||
|
||
## Проксирование
|
||
|
||
Proxy матчит сервисы по `Host` заголовку. Если PC online — http-proxy проксирует запрос. Если offline — показывает "Waking up" страницу с автополлом.
|
||
|
||
## Service Management
|
||
|
||
Сервисы хранятся в `${DATA_DIR}/services.json` (по умолчанию `./data/services.json`). При первом запуске берутся из env var `SERVICES`, затем управляются через CRUD API:
|
||
- `GET /api/services` — список
|
||
- `POST /api/services` — создание
|
||
- `PUT /api/services/:host` — обновление (host неизменяем)
|
||
- `DELETE /api/services/:host` — удаление
|
||
|
||
`ServiceManager` (`packages/proxy/src/services/serviceManager.ts`) — in-memory + атомарная запись (tmp + rename). Изменения уведомляют dashboard через WebSocket (`service_list_changed`).
|
||
|
||
В Docker volume монтируется: `./data/proxy:/app/data`.
|
||
|
||
## Аутентификация
|
||
|
||
Опциональная auth по логину/паролю через env-переменные `AUTH_USERNAME` и `AUTH_PASSWORD`. Если не заданы — auth отключена.
|
||
|
||
- `POST /api/auth/login` — возвращает `{ token }` (UUID v4)
|
||
- `POST /api/auth/logout` — удаляет сессию
|
||
- `GET /api/auth/check` — проверяет, нужна ли auth и валиден ли токен
|
||
- Сессии in-memory (`Map`), TTL 24 часа, теряются при рестарте
|
||
- Rate limiting: 5 попыток / 15 мин на IP для `/api/auth/login`
|
||
- Auth middleware защищает `/api/*` кроме `/api/auth/*`
|
||
- WebSocket: токен через query `?token=...`
|
||
- Сервис-прокси (по Host) — без auth
|
||
- CORS: только same-origin + localhost (для dev)
|
||
- SSRF защита: service target не может указывать на localhost, metadata endpoints
|
||
- XSS защита: HTML-экранирование в waking page
|
||
|
||
## Деплой
|
||
|
||
Два приложения в Dokploy из одного git repo:
|
||
- `sleepguard-proxy`: Dockerfile `packages/proxy/Dockerfile`, build context `.`
|
||
- `sleepguard-agent`: Dockerfile `packages/agent/Dockerfile`, build context `.`
|
||
|
||
Agent деплоится на PC как remote server в Dokploy с NVIDIA GPU passthrough.
|
||
|
||
## Env переменные
|
||
|
||
См. `.env.example` в корне репозитория.
|