diff --git a/DOCS.md b/DOCS.md
index 73831c4..6b9365b 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -35,13 +35,17 @@
| Среда выполнения | Node.js 20 |
| Веб-фреймворк | Express 5 |
| База данных | MariaDB 10.11 |
+| Хранение сессий | express-mysql-session (MariaDB) |
+| Очередь задач | better-sqlite3 (SQLite WAL, `/mnt/webdata/storage/jobs.db`) |
| Обработка изображений | Sharp 0.34 |
-| Обработка видео | FFmpeg (системный), ffprobe |
+| Обработка видео | FFmpeg 5.1.8 (libx264, libvpx, libmp3lame), ffprobe |
| Обработка PDF | pdf-lib, pdf-parse, Ghostscript (системный) |
| Парсинг HTML | @mozilla/readability, jsdom |
| Авторизация | express-session, bcrypt |
| Панель администратора | AdminJS 7 + @adminjs/sequelize |
-| Стили | Tailwind CSS (CDN), кастомный shared.css |
+| Стили | Tailwind CSS 3 (CLI build, `vendor/tailwind.min.css`) |
+| WebSocket | ws (реалтайм прогресс конвертации) |
+| Логирование | pino (структурированный JSON) |
| Процесс-менеджер | PM2 |
### Сервер
@@ -69,7 +73,11 @@
│ ├── auth.js # Middleware авторизации: список публичных путей, редиректы
│ ├── admin.js # Настройка AdminJS: Sequelize модели, ресурсы, монтирование
│ ├── db.js # Пул соединений MariaDB (mysql2/promise), хелперы для users
-│ ├── logger.js # Логгер: stdout + запись в compress.log через logToFile
+│ ├── logger.js # Логгер pino: структурированный JSON + logToFile
+│ ├── queue.js # Очередь задач на SQLite (better-sqlite3, WAL mode)
+│ ├── session.js # Persistent sessions (express-mysql-session → MariaDB)
+│ ├── storage.js # Единые пути хранения: /mnt/webdata/storage/{uploads,results}
+│ ├── ws.js # WebSocket сервер (ws) — реалтайм прогресс конвертации
│ └── ssrf.js # Защита от SSRF: проверка IP-диапазонов, DNS-резолвинг
│
├── routes/
@@ -650,6 +658,10 @@ session({
### Rate limiting для auth
+Rate limit работает per-user: `keyGenerator` использует `req.session.user.id` для авторизованных пользователей, `req.ip` для анонимных. Это предотвращает ситуацию, когда один бот исчерпывает лимит для всех.
+
+
+
15 минут, 10 попыток (применяется к `POST /auth/login` и `POST /auth/register`).
---
@@ -961,12 +973,25 @@ session({
```js
helmet({
- contentSecurityPolicy: false, // отключено — Tailwind CDN требует inline-скриптов
+ contentSecurityPolicy: {
+ directives: {
+ defaultSrc: ["'self'"],
+ scriptSrc: ["'self'", "'unsafe-inline'", "https://mc.yandex.ru"],
+ styleSrc: ["'self'", "'unsafe-inline'"],
+ imgSrc: ["'self'", "data:", "https://mc.yandex.ru"],
+ connectSrc: ["'self'", "wss:", "ws:"],
+ fontSrc: ["'self'"],
+ objectSrc: ["'none'"],
+ frameAncestors: ["'none'"],
+ baseUri: ["'self'"],
+ formAction: ["'self'"],
+ },
+ },
crossOriginEmbedderPolicy: false,
})
```
-Остальные политики helmet включены: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy.
+CSP включён. `unsafe-inline` необходим для inline `
+
@@ -36,63 +113,51 @@
-
+
-
- Перетащите файлы сюда или выберите
+
+ Перетащите файлы сюда или выберите
-
+
Файлы загружаются мгновенно, по одному
+
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+ Размер
+
@@ -103,269 +168,382 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/dashboard.html b/public/dashboard.html
index 932c766..68d762d 100644
--- a/public/dashboard.html
+++ b/public/dashboard.html
@@ -4,69 +4,47 @@
WA Dev Tools — Панель
-
+
-
+
+
+
+
+
+
@@ -595,6 +619,20 @@
});
};
+ // Store response data for AI audit
+ window._lastResponse = {
+ status: data.status,
+ statusText: data.statusText,
+ headers: data.headers,
+ body: (data.body || '').slice(0, 2000),
+ url: data.url || req.url,
+ method: req.method,
+ time: data.time,
+ };
+ // Show AI audit button
+ document.getElementById('aiAuditWrap').classList.remove('hidden');
+ document.getElementById('aiAuditResult').classList.add('hidden');
+
addToHistory(req.method, req.url, data.status, data.time);
} catch (err) {
statusBar.innerHTML = `Ошибка соединения: ${escHtml(err.message)}`;
@@ -700,6 +738,83 @@
renderHistory();
})();
+
+
+// ── AI Security Audit ─────────────────────────────────────────────────────────
+async function aiSecurityAudit() {
+ const resp = window._lastResponse;
+ if (!resp) return;
+
+ const btn = document.getElementById('aiAuditBtn');
+ const resultDiv = document.getElementById('aiAuditResult');
+
+ btn.disabled = true;
+ btn.innerHTML = ' Анализирую...';
+ resultDiv.classList.remove('hidden');
+ resultDiv.innerHTML = '';
+
+ // Build headers summary
+ const hdrs = resp.headers || {};
+ const hdrLines = Object.entries(hdrs).map(([k,v]) => k + ': ' + v).join('\n');
+
+ const payload = {
+ pattern: `${resp.method} ${resp.url} → ${resp.status} ${resp.statusText}
+
+Response Headers:
+${hdrLines}
+
+Response Body (first 500 chars):
+${(resp.body || '').slice(0, 500)}`,
+ flags: 'security-audit'
+ };
+
+ let fullText = '';
+
+ try {
+ const res = await fetch('/api/ai/explain', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(payload),
+ });
+
+ if (!res.ok) throw new Error('Ошибка ' + res.status);
+
+ const reader = res.body.getReader();
+ const decoder = new TextDecoder();
+ let buffer = '';
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+ buffer += decoder.decode(value, { stream: true });
+ const lines = buffer.split('\n');
+ buffer = lines.pop();
+ for (const line of lines) {
+ if (!line.startsWith('data: ')) continue;
+ const d = line.slice(6).trim();
+ if (d === '[DONE]') continue;
+ try {
+ const parsed = JSON.parse(d);
+ if (parsed.error) throw new Error(parsed.error);
+ const delta = parsed.choices?.[0]?.delta?.content || '';
+ if (delta) {
+ fullText += delta;
+ let md = fullText.replace(/^```[a-z]*\n?/gm, '').replace(/```\s*$/gm, '').trim();
+ resultDiv.innerHTML = marked.parse(md);
+ }
+ } catch (e) {
+ if (e.message && !e.message.includes('JSON')) throw e;
+ }
+ }
+ }
+ if (!fullText.trim()) resultDiv.innerHTML = 'Пустой ответ';
+ } catch (err) {
+ resultDiv.innerHTML = '' + (err.message || 'AI недоступен') + '';
+ } finally {
+ btn.disabled = false;
+ btn.innerHTML = ' AI Security Audit';
+ }
+}
+
-
+
diff --git a/public/login.html b/public/login.html
index ed98ce1..88ff158 100644
--- a/public/login.html
+++ b/public/login.html
@@ -4,16 +4,8 @@
Вход — WA Dev Tools
-
-
+
+
\n\n\n' + body + '\n
-
-
-
-\n