Безопасность панели была усилена

Проверка пароля переведена на PAM (python-pam) с fallback на crypt/spwd
для совместимости, все POST-формы защищены CSRF-токеном в сессии,
после пяти неудачных попыток входа включается пауза 60 секунд,
установщик генерирует самоподписанный TLS-сертификат и панель
по умолчанию работает по HTTPS (отключается VIRTUALITY_TLS=0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKUoZwHMCHnytfswFVRUHw
Этот коммит содержится в:
Claude
2026-08-15 19:19:33 +00:00
родитель 1da491c9e1
Коммит bb87f52834
17 изменённых файлов: 276 добавлений и 89 удалений
+8 -8
Просмотреть файл
@@ -18,7 +18,7 @@
</div>
<div class="top-meta">
<span>user: {{ user }}</span>
<form method="post" action="/logout" class="logout-form"><button class="ghost">Выйти</button></form>
<form method="post" action="/logout" class="logout-form"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="ghost">Выйти</button></form>
</div>
</header>
@@ -76,11 +76,11 @@
<td><span class="status {{ 'ok' if is_running else 'err' if 'shut' in vm.state else 'warn' }}">{{ vm.state }}</span></td>
<td class="autostart-cell">
{% if vm.autostart_enabled %}
<form method="post" action="/vm/{{ vm.name }}/autostart-disable" class="inline-form">
<form method="post" action="/vm/{{ vm.name }}/autostart-disable" class="inline-form"><input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button class="status status-button ok" title="Отключить автозапуск">{{ vm.autostart_label|default('enabled') }}</button>
</form>
{% else %}
<form method="post" action="/vm/{{ vm.name }}/autostart" class="inline-form">
<form method="post" action="/vm/{{ vm.name }}/autostart" class="inline-form"><input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button class="status status-button err" title="Включить автозапуск">{{ vm.autostart_label|default('disabled') }}</button>
</form>
{% endif %}
@@ -90,12 +90,12 @@
<a class="icon-action" href="/vm/{{ vm.name }}" title="Подробнее"><span></span><em>Детали</em></a>
<a class="icon-action accent" href="/vm/{{ vm.name }}/console" target="_blank" rel="noopener" title="Консоль"><span></span><em>Консоль</em></a>
{% if is_running %}
<form method="post" action="/vm/{{ vm.name }}/reboot"><button class="icon-action" title="Перезагрузить"><span></span><em>Reboot</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/shutdown"><button class="icon-action" title="Мягко выключить"><span></span><em>Shutdown</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/destroy"><button class="icon-action danger" title="Принудительно выключить"><span></span><em>Power</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/reboot"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="icon-action" title="Перезагрузить"><span></span><em>Reboot</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/shutdown"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="icon-action" title="Мягко выключить"><span></span><em>Shutdown</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/destroy"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="icon-action danger" title="Принудительно выключить"><span></span><em>Power</em></button></form>
{% else %}
<form method="post" action="/vm/{{ vm.name }}/start"><button class="icon-action success" title="Запустить"><span></span><em>Start</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/delete" onsubmit="return confirm('Удалить VM {{ vm.name }} вместе с дисками?');"><button class="icon-action danger" title="Удалить VM"><span>🗑</span><em>Delete</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/start"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="icon-action success" title="Запустить"><span></span><em>Start</em></button></form>
<form method="post" action="/vm/{{ vm.name }}/delete" onsubmit="return confirm('Удалить VM {{ vm.name }} вместе с дисками?');"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="icon-action danger" title="Удалить VM"><span>🗑</span><em>Delete</em></button></form>
{% endif %}
</div>
</td>