security(auth): anti-enumeration, returnTo-валидация, лимит попыток логина

Шаг 2.1 плана production-готовности:
- единый 401 при любом отказе логина + constant-time bcrypt
- forgot-password: идентичный ответ независимо от существования email
- sanitizeReturnTo (open redirect fix в /api/documents/generate-link)
- 10 неудачных попыток → блок 15 мин (in-memory, аудит)
- DATABASE_SSL_REJECT_UNAUTHORIZED env (дефолт true)
- доделка 0.7: статичные тексты в llm-providers/rag/finance-di2
- 8 новых тестов (104/104)
This commit is contained in:
2026-09-08 00:46:57 +03:00
parent 0828003141
commit 5750a3106f
15 changed files with 525 additions and 45 deletions

View File

@@ -279,7 +279,8 @@ router.get(
const tagsData = await tagsRes.json() as { models?: Array<{ name: string; size: number; digest: string; modified_at: string }> };
return res.json({ success: true, models: tagsData.models ?? [] });
} catch (err: any) {
return res.json({ success: false, error: `Ошибка получения моделей: ${err?.message ?? err}` });
console.error("[LLM-Providers] ollama models error:", err);
return res.json({ success: false, error: "Не удалось получить список моделей Ollama" });
}
}
);
@@ -377,7 +378,7 @@ router.delete(
return res.json({ success: true });
} catch (err: any) {
console.error("[LLM-Providers] ollama delete model error:", err);
return res.json({ success: false, error: `Ошибка удаления модели: ${err?.message ?? err}` });
return res.json({ success: false, error: "Не удалось удалить модель" });
}
}
);
@@ -454,7 +455,8 @@ router.post(
const models = (tagsData.models ?? []).map((m) => m.name);
return res.json({ success: true, models });
} catch (err: any) {
return res.json({ success: false, error: `Ошибка подключения к Ollama: ${err?.message ?? err}` });
console.error("[LLM-Providers] ollama test connection error:", err);
return res.json({ success: false, error: "Не удалось подключиться к Ollama" });
}
}
@@ -475,11 +477,12 @@ router.post(
const models = (modelsData.data ?? []).map((m) => m.id).sort();
return res.json({ success: true, models });
} catch (err: any) {
return res.json({ success: false, error: `Ошибка подключения: ${err?.message ?? err}` });
console.error("[LLM-Providers] provider test connection error:", err);
return res.json({ success: false, error: "Не удалось подключиться к провайдеру" });
}
} catch (err: any) {
console.error("[LLM-Providers] test error:", err);
return res.json({ success: false, error: `Внутренняя ошибка: ${err?.message ?? err}` });
return res.json({ success: false, error: "Внутренняя ошибка сервера" });
}
}
);